Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the kernel's mm module #145

Merged
merged 7 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hal_aarch64/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ edition = "2021"
hal_core = { path = "../hal_core" }
tock-registers = "0.8"
cortex-a = "8.1"
log = "0.4"
8 changes: 4 additions & 4 deletions hal_aarch64/src/irq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hal_core::{Error, TimerCallbackFn};
use crate::devices::gicv2::GicV2;

use crate::mm;
use hal_core::mm::{PageAllocFn, PageMap, Permissions, VAddr};
use hal_core::mm::{PageAlloc, PageMap, Permissions, VAddr};

use tock_registers::interfaces::Writeable;

Expand Down Expand Up @@ -64,19 +64,19 @@ impl IrqChip {

static mut IRQ_CHIP: IrqChip = IrqChip::NoChip;

pub fn init_irq_chip(_dt_node: (), alloc: PageAllocFn) -> Result<(), Error> {
pub fn init_irq_chip(_dt_node: (), allocator: &impl PageAlloc) -> Result<(), Error> {
let (gicd_base, gicc_base) = (0x800_0000, 0x801_0000);
mm::current().identity_map_range(
VAddr::new(gicd_base),
0x0001_0000 / mm::PAGE_SIZE,
Permissions::READ | Permissions::WRITE,
alloc,
allocator,
)?;
mm::current().identity_map_range(
VAddr::new(gicc_base),
0x0001_0000 / mm::PAGE_SIZE,
Permissions::READ | Permissions::WRITE,
alloc,
allocator,
)?;

unsafe {
Expand Down
2 changes: 2 additions & 0 deletions hal_aarch64/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ mod devices;
pub struct PanicInfo {
esr_el1: u64,
elr_el1: u64,
far_el1: u64,
}

pub fn panic_info() -> PanicInfo {
PanicInfo {
esr_el1: ESR_EL1.get(),
elr_el1: ELR_EL1.get(),
far_el1: FAR_EL1.get(),
}
}

Expand Down
41 changes: 26 additions & 15 deletions hal_aarch64/src/mm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use hal_core::{
mm::{self, PageAllocFn, PageMap},
mm::{self, PageAlloc, PageMap},
AddressRange, Error,
};

Expand All @@ -19,32 +19,39 @@ use core::cell::OnceCell;

static mut GPT: OnceCell<&'static mut PageTable> = OnceCell::new();

pub fn is_pagetable_installed() -> bool {
unsafe { GPT.get_mut().is_some() }
}

pub fn current() -> &'static mut PageTable {
unsafe { GPT.get_mut().unwrap() }
}

pub fn init_paging(
pub fn prefill_pagetable(
r: impl Iterator<Item = AddressRange>,
rw: impl Iterator<Item = AddressRange>,
rwx: impl Iterator<Item = AddressRange>,
pre_allocated: impl Iterator<Item = AddressRange>,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
hal_core::mm::init_paging::<PageTable>(r, rw, rwx, pre_allocated, alloc, |pt| {
// TODO: put into into the hal_core::Error
unsafe {
if GPT.set(pt).is_err() {
panic!("GPT is already set ?");
}
};
unsafe {
load_pagetable(current());
};
})?;
let pt = hal_core::mm::prefill_pagetable::<PageTable>(r, rw, rwx, pre_allocated, allocator)?;

// TODO: put into into the hal_core::Error
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the todo now or later?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oneday 🙏

unsafe {
if GPT.set(pt).is_err() {
panic!("GPT is already set ?");
}
};

Ok(())
}

pub fn enable_paging() {
unsafe {
load_pagetable(current());
};
}

unsafe fn load_pagetable(pt: &'static mut PageTable) {
MAIR_EL1.write(
// Attribute 0 - NonCacheable normal DRAM. FIXME: enable cache?
Expand Down Expand Up @@ -75,5 +82,9 @@ unsafe fn load_pagetable(pt: &'static mut PageTable) {
}

pub fn align_up(addr: usize) -> usize {
mm::align_up(addr, PageTable::PAGE_SIZE)
mm::align_up(addr, PAGE_SIZE)
}

pub fn align_down(addr: usize) -> usize {
mm::align_down(addr, PAGE_SIZE)
}
20 changes: 12 additions & 8 deletions hal_aarch64/src/mm/pgt48.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use hal_core::{
mm::{self, PageAllocFn, PageEntry, PageMap, Permissions},
mm::{self, PageAlloc, PageEntry, PageMap, Permissions},
Error,
};

Expand Down Expand Up @@ -224,9 +224,9 @@ impl PageMap for PageTable {
const PAGE_SIZE: usize = 4096;
type Entry = TableEntry;

fn new(alloc: PageAllocFn) -> Result<&'static mut Self, Error> {
let page = alloc(1);
let page_table = page.ptr_cast::<PageTable>();
fn new(allocator: &impl PageAlloc) -> Result<&'static mut Self, Error> {
let page = allocator.alloc(1)?;
let page_table = unsafe { page as *mut PageTable };
// Safety: the PMM gave us the memory, it should be a valid pointer.
let page_table: &mut PageTable = unsafe { page_table.as_mut().unwrap() };

Expand All @@ -243,7 +243,7 @@ impl PageMap for PageTable {
va: mm::VAddr,
pa: mm::PAddr,
perms: Permissions,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<&mut TableEntry, Error> {
let va = VAddr::from(va);
let pa = PAddr::from(pa);
Expand All @@ -266,7 +266,7 @@ impl PageMap for PageTable {

let descriptor = unsafe { &mut content.descriptor };
if descriptor.is_invalid() {
let new_page_table = PageTable::new(alloc)?;
let new_page_table = PageTable::new(allocator)?;
descriptor.set_next_level(new_page_table);
}

Expand All @@ -276,14 +276,18 @@ impl PageMap for PageTable {
unreachable!("We should have reached lvl 3 and returned by now...");
}

fn add_invalid_entry(&mut self, va: mm::VAddr, alloc: PageAllocFn) -> Result<(), Error> {
fn add_invalid_entry(
&mut self,
va: mm::VAddr,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
let entry = self.map(
va,
mm::PAddr {
val: 0x0A0A_0A0A_0A0A_0A0A,
},
mm::Permissions::READ,
alloc,
allocator,
)?;

entry.set_invalid();
Expand Down
13 changes: 11 additions & 2 deletions hal_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
#![no_std]
#![feature(return_position_impl_trait_in_trait)]

use core::convert::Into;
use core::ops::Range;

pub mod mm;

#[derive(Debug)]
pub enum Error {}
pub enum Error {
Alloc(mm::AllocatorError),
}

impl From<mm::AllocatorError> for Error {
fn from(e: mm::AllocatorError) -> Self {
Self::Alloc(e)
}
}

pub type TimerCallbackFn = fn();

Expand Down Expand Up @@ -43,7 +52,7 @@ impl AddressRange {
pub fn iter_pages(self, page_size: usize) -> impl Iterator<Item = usize> {
assert_eq!(self.end, mm::align_up(self.end, page_size));

(self.start..=self.end).step_by(page_size)
(self.start..self.end).step_by(page_size)
}

pub fn count_pages(&self, page_size: usize) -> usize {
Expand Down
80 changes: 56 additions & 24 deletions hal_core/src/mm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,34 @@ bitflags::bitflags! {

pub type PageAllocFn = fn(usize) -> PAddr;

#[derive(Debug)]
pub enum AllocatorError {
NotEnoughMemoryForMetadata,
OutOfMemory,
}

pub trait PageAlloc: Sync {
fn alloc(&self, page_count: usize) -> Result<usize, AllocatorError>;
fn dealloc(&self, base: usize, page_count: usize) -> Result<(), AllocatorError>;
fn used_pages<F: FnMut(usize)>(&self, f: F);
}

pub struct NullPageAllocator;

impl PageAlloc for NullPageAllocator {
fn alloc(&self, _page_count: usize) -> Result<usize, AllocatorError> {
panic!("the null page allocator mustn't allocate");
}

fn dealloc(&self, _base: usize, _page_count: usize) -> Result<(), AllocatorError> {
panic!("the null page allocator cannot deallocate");
}

fn used_pages<F: FnMut(usize)>(&self, _f: F) {
panic!("obviously the null allocator has no pages that are in use");
}
}

pub trait PageEntry {
fn set_invalid(&mut self);
}
Expand All @@ -59,22 +87,22 @@ pub trait PageMap {
const PAGE_SIZE: usize;
type Entry: PageEntry;

fn new(alloc: PageAllocFn) -> Result<&'static mut Self, Error>;
fn new(allocator: &impl PageAlloc) -> Result<&'static mut Self, Error>;

fn map(
&mut self,
va: VAddr,
pa: PAddr,
perms: Permissions,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<&mut Self::Entry, Error>;

fn add_invalid_entry(&mut self, va: VAddr, alloc: PageAllocFn) -> Result<(), Error> {
fn add_invalid_entry(&mut self, va: VAddr, allocator: &impl PageAlloc) -> Result<(), Error> {
self.map(
va,
PAddr::new(0x0A0A_0A0A_0A0A_0A0A),
Permissions::READ,
alloc,
allocator,
)?
.set_invalid();

Expand All @@ -85,9 +113,9 @@ pub trait PageMap {
&mut self,
addr: VAddr,
perms: Permissions,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
self.map(addr, PAddr::new(addr.val), perms, alloc)
self.map(addr, PAddr::new(addr.val), perms, allocator)
.map(|_| ())
}

Expand All @@ -96,11 +124,11 @@ pub trait PageMap {
addr: VAddr,
page_count: usize,
perms: Permissions,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
let start = addr.val;
for i in 0..page_count {
self.identity_map(VAddr::new(start + i * Self::PAGE_SIZE), perms, alloc)?;
self.identity_map(VAddr::new(start + i * Self::PAGE_SIZE), perms, allocator)?;
}

Ok(())
Expand All @@ -109,10 +137,10 @@ pub trait PageMap {
fn add_invalid_entries(
&mut self,
range: AddressRange,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
for page in range.iter_pages(Self::PAGE_SIZE) {
self.add_invalid_entry(VAddr::new(page), alloc)?;
self.add_invalid_entry(VAddr::new(page), allocator)?;
}

Ok(())
Expand All @@ -122,10 +150,10 @@ pub trait PageMap {
&mut self,
range: AddressRange,
perms: Permissions,
alloc: PageAllocFn,
allocator: &impl PageAlloc,
) -> Result<(), Error> {
for page in range.iter_pages(Self::PAGE_SIZE) {
self.identity_map(VAddr::new(page), perms, alloc)?;
self.identity_map(VAddr::new(page), perms, allocator)?;
}

Ok(())
Expand All @@ -136,41 +164,45 @@ pub fn align_up(val: usize, page_sz: usize) -> usize {
((val + page_sz - 1) / page_sz) * page_sz
}

pub fn init_paging<P: PageMap + 'static>(
pub fn align_down(addr: usize, page_sz: usize) -> usize {
// TODO: can this be more optimized ?
// XXX: uh isn't this math wrong ?
align_up(addr, page_sz) + page_sz
n1tram1 marked this conversation as resolved.
Show resolved Hide resolved
}

pub fn prefill_pagetable<P: PageMap + 'static>(
r: impl Iterator<Item = AddressRange>,
rw: impl Iterator<Item = AddressRange>,
rwx: impl Iterator<Item = AddressRange>,
pre_allocated: impl Iterator<Item = AddressRange>,
alloc: PageAllocFn,
store_pagetable: impl FnOnce(&'static mut P),
) -> Result<(), Error> {
let pt: &'static mut P = P::new(alloc)?;
allocator: &impl PageAlloc,
) -> Result<&'static mut P, Error> {
trace!("hal_core::mm::prefill_pagetable");
let pt: &'static mut P = P::new(allocator)?;
let page_size = P::PAGE_SIZE;

for range in pre_allocated {
pt.add_invalid_entries(range, alloc)?;
pt.add_invalid_entries(range, allocator)?;
}

for range in r {
trace!("mapping as RO: {:X?}", range);
pt.identity_map_addressrange(range, Permissions::READ, alloc)?;
pt.identity_map_addressrange(range, Permissions::READ, allocator)?;
}

for range in rw {
trace!("mapping as RW: {:X?}", range);
pt.identity_map_addressrange(range, Permissions::READ | Permissions::WRITE, alloc)?;
pt.identity_map_addressrange(range, Permissions::READ | Permissions::WRITE, allocator)?;
}

for range in rwx {
trace!("mapping as RWX: {:X?}", range);
pt.identity_map_addressrange(
range,
Permissions::READ | Permissions::WRITE | Permissions::EXECUTE,
alloc,
allocator,
)?
}

store_pagetable(pt);

Ok(())
Ok(pt)
}
Loading
Loading