diff --git a/src/main.rs b/src/main.rs index 31ed6150af..a531da1eb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use rmm::{ PageMapper, PageTable, PhysicalAddress, + VirtualAddress, }; use core::{ @@ -178,17 +179,19 @@ unsafe fn new_tables(areas: &'static [MemoryArea]) { { // Map all physical areas at PHYS_OFFSET - let mut mapper = PageMapper::::new( + let mut mapper = PageMapper::::create( &mut bump_allocator ).expect("failed to create Mapper"); for area in areas.iter() { for i in 0..area.size / A::PAGE_SIZE { let phys = area.base.add(i * A::PAGE_SIZE); let virt = A::phys_to_virt(phys); - mapper.map( + let flush = mapper.map_phys( virt, - PageEntry::new(phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT) - ).expect("failed to map frame"); + phys, + A::ENTRY_FLAG_WRITABLE + ).expect("failed to map page to frame"); + flush.ignore(); // Not the active table } } @@ -211,17 +214,17 @@ unsafe fn new_tables(areas: &'static [MemoryArea]) { } } } - // for i in 0..16 { - // let phys_opt = allocator.allocate(2 * MEGABYTE); - // println!("2 MB page {}: {:X?}", i, phys_opt); - // if i % 2 == 0 { - // if let Some(phys) = phys_opt { - // allocator.free(phys, 2 * MEGABYTE); - // } - // } - // } - // - // println!("Remaining: {}", format_size(allocator.remaining())); + + let mut mapper = PageMapper::::current( + &mut allocator + ); + for i in 0..16 { + let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE); + let flush = mapper.map( + virt, + A::ENTRY_FLAG_USER | A::ENTRY_FLAG_WRITABLE + ).expect("failed to map page"); + } } unsafe fn inner() { diff --git a/src/page/flush.rs b/src/page/flush.rs new file mode 100644 index 0000000000..9aae51f599 --- /dev/null +++ b/src/page/flush.rs @@ -0,0 +1,57 @@ +use core::{ + marker::PhantomData, + mem, +}; + +use crate::{ + Arch, + VirtualAddress, +}; + +#[must_use = "The page table must be flushed, or the changes unsafely ignored"] +pub struct PageFlush { + virt: VirtualAddress, + phantom: PhantomData, +} + +impl PageFlush { + pub fn new(virt: VirtualAddress) -> Self { + Self { + virt, + phantom: PhantomData, + } + } + + pub fn flush(self) { + unsafe { A::invalidate(self.virt); } + } + + pub unsafe fn ignore(self) { + mem::forget(self); + } +} + +#[must_use = "The page table must be flushed, or the changes unsafely ignored"] +pub struct PageFlushAll { + phantom: PhantomData, +} + +impl PageFlushAll { + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } + + pub fn consume(&self, flush: PageFlush) { + unsafe { flush.ignore(); } + } + + pub fn flush(self) { + unsafe { A::invalidate_all(); } + } + + pub unsafe fn ignore(self) { + mem::forget(self); + } +} diff --git a/src/page/mapper.rs b/src/page/mapper.rs index fa60be1cc3..9fc80884b4 100644 --- a/src/page/mapper.rs +++ b/src/page/mapper.rs @@ -4,6 +4,7 @@ use crate::{ Arch, FrameAllocator, PageEntry, + PageFlush, PageTable, PhysicalAddress, VirtualAddress, @@ -16,13 +17,22 @@ pub struct PageMapper<'f, A, F> { } impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> { - pub unsafe fn new(allocator: &'f mut F) -> Option { - let table_addr = allocator.allocate_one()?; - Some(Self { + pub unsafe fn new(table_addr: PhysicalAddress, allocator: &'f mut F) -> Self { + Self { table_addr, allocator, phantom: PhantomData, - }) + } + } + + pub unsafe fn create(allocator: &'f mut F) -> Option { + let table_addr = allocator.allocate_one()?; + Some(Self::new(table_addr, allocator)) + } + + pub unsafe fn current(allocator: &'f mut F) -> Self { + let table_addr = A::table(); + Self::new(table_addr, allocator) } pub unsafe fn activate(&mut self) { @@ -37,22 +47,30 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> { ) } - pub unsafe fn map(&mut self, virt: VirtualAddress, entry: PageEntry) -> Option<()> { + pub unsafe fn map(&mut self, virt: VirtualAddress, flags: usize) -> Option> { + let phys = self.allocator.allocate_one()?; + self.map_phys(virt, phys, flags) + } + + pub unsafe fn map_phys(&mut self, virt: VirtualAddress, phys: PhysicalAddress, flags: usize) -> Option> { + //TODO: verify virt and phys are aligned + //TODO: verify flags have correct bits + let entry = PageEntry::new(phys.data() | flags | A::ENTRY_FLAG_PRESENT); let mut table = self.table(); loop { let i = table.index_of(virt)?; if table.level() == 0 { //TODO: check for overwriting entry table.set_entry(i, entry); - return Some(()); + return Some(PageFlush::new(virt)); } else { let next_opt = table.next(i); let next = match next_opt { Some(some) => some, None => { - let phys = self.allocator.allocate_one()?; + let next_phys = self.allocator.allocate_one()?; //TODO: correct flags? - table.set_entry(i, PageEntry::new(phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT)); + table.set_entry(i, PageEntry::new(next_phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT)); table.next(i)? } }; diff --git a/src/page/mod.rs b/src/page/mod.rs index 268d3be9d3..48a07e717d 100644 --- a/src/page/mod.rs +++ b/src/page/mod.rs @@ -1,9 +1,11 @@ pub use self::{ - entry::PageEntry, - mapper::PageMapper, - table::PageTable, + entry::*, + flush::*, + mapper::*, + table::*, }; mod entry; +mod flush; mod mapper; mod table;