diff --git a/src/main.rs b/src/main.rs index 94a9b482d0..02ae2a3840 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,27 +76,32 @@ const ENTRY_FLAGS_MASK: usize = !ENTRY_ADDRESS_MASK; static mut MACHINE: Option = None; #[inline(always)] -pub unsafe fn machine_read(address: usize) -> T { +pub unsafe fn arch_read(address: usize) -> T { MACHINE.as_ref().unwrap().read(address) } #[inline(always)] -pub unsafe fn machine_write(address: usize, value: T) { +pub unsafe fn arch_write(address: usize, value: T) { MACHINE.as_mut().unwrap().write(address, value) } #[inline(always)] -pub unsafe fn machine_invalidate(address: usize) { +pub unsafe fn arch_invalidate(address: usize) { MACHINE.as_mut().unwrap().invalidate(address); } #[inline(always)] -pub unsafe fn machine_invalidate_all() { +pub unsafe fn arch_invalidate_all() { MACHINE.as_mut().unwrap().invalidate_all(); } #[inline(always)] -pub unsafe fn machine_set_table(address: usize) { +pub unsafe fn arch_get_table() -> usize { + MACHINE.as_mut().unwrap().get_table() +} + +#[inline(always)] +pub unsafe fn arch_set_table(address: usize) { MACHINE.as_mut().unwrap().set_table(address); } @@ -150,7 +155,7 @@ impl Machine { pub fn read(&self, virt: usize) -> T { //TODO: allow reading past page boundaries let size = mem::size_of::(); - if (virt & PAGE_ADDRESS_MASK) != ((virt + size) & PAGE_ADDRESS_MASK) { + if (virt & PAGE_ADDRESS_MASK) != ((virt + size - 1) & PAGE_ADDRESS_MASK) { panic!("read: 0x{:X} size 0x{:X} passes page boundary", virt, size); } @@ -164,7 +169,7 @@ impl Machine { pub fn write(&mut self, virt: usize, value: T) { //TODO: allow writing past page boundaries let size = mem::size_of::(); - if (virt & PAGE_ADDRESS_MASK) != ((virt + size) & PAGE_ADDRESS_MASK) { + if (virt & PAGE_ADDRESS_MASK) != ((virt + size - 1) & PAGE_ADDRESS_MASK) { panic!("write: 0x{:X} size 0x{:X} passes page boundary", virt, size); } @@ -229,12 +234,126 @@ impl Machine { } } + pub fn get_table(&self) -> usize { + self.table_addr + } + pub fn set_table(&mut self, address: usize) { self.table_addr = address; self.invalidate_all(); } } +#[repr(transparent)] +pub struct PageEntry(usize); + +impl PageEntry { + pub fn address(&self) -> PhysicalAddress { + PhysicalAddress(self.0 & ENTRY_ADDRESS_MASK) + } + + pub fn present(&self) -> bool { + self.0 & ENTRY_PRESENT != 0 + } +} + +pub struct PageTable { + base: VirtualAddress, + phys: PhysicalAddress, + level: usize +} + +impl PageTable { + pub unsafe fn new(base: VirtualAddress, phys: PhysicalAddress, level: usize) -> Self { + Self { base, phys, level } + } + + pub unsafe fn top() -> Self { + Self::new( + VirtualAddress::new(0), + PhysicalAddress::new(arch_get_table()), + 3 + ) + } + + pub fn level(&self) -> usize { + self.level + } + + pub unsafe fn virt(&self) -> VirtualAddress { + //TODO: something other than identity mapping + VirtualAddress(self.phys.0) + } + + pub fn entry_base(&self, i: usize) -> Option { + if i < PAGE_ENTRIES { + Some(VirtualAddress( + self.base.0 + i << (9 * self.level + PAGE_SHIFT) + )) + } else { + None + } + } + + pub unsafe fn entry_virt(&self, i: usize) -> Option { + if i < PAGE_ENTRIES { + Some(VirtualAddress( + self.virt().0 + i * PAGE_ENTRY_SIZE + )) + } else { + None + } + } + + pub unsafe fn entry(&self, i: usize) -> Option { + let addr = self.entry_virt(i)?; + Some(PageEntry(arch_read::(addr.0))) + } + + pub unsafe fn set_entry(&mut self, i: usize, entry: PageEntry) -> Option<()> { + let addr = self.entry_virt(i)?; + arch_write::(addr.0, entry.0); + Some(()) + } + + pub unsafe fn next(&self, i: usize) -> Option { + if self.level > 0 { + let entry = self.entry(i)?; + if entry.present() { + return Some(PageTable::new( + self.entry_base(i)?, + entry.address(), + self.level - 1 + )); + } + } + None + } +} + +unsafe fn dump_tables(table: PageTable) { + let level = table.level(); + for i in 0..PAGE_ENTRIES { + if level == 0 { + if let Some(entry) = table.entry(i) { + if entry.present() { + let base = table.entry_base(i).unwrap(); + println!("0x{:X}: 0x{:X}", base.0, entry.address().0); + } + } + } else { + if let Some(next) = table.next(i) { + dump_tables(next); + } + } + } +} + +pub struct MemoryArea { + base: PhysicalAddress, + size: usize, +} + fn main() { let memory_size = 64 * 1024 * 1024; @@ -262,27 +381,32 @@ fn main() { // PT links to frames for i in 0..PAGE_ENTRIES { let page = i * PAGE_SIZE; - let flags = if page >= megabyte { - ENTRY_WRITABLE | ENTRY_PRESENT - } else { - ENTRY_PRESENT - }; + let flags = ENTRY_WRITABLE | ENTRY_PRESENT; machine.write_phys::(pt + i * PAGE_ENTRY_SIZE, page | flags); } MACHINE = Some(machine); // Set table to pml4 - machine_set_table(pml4); + arch_set_table(pml4); } + // Debug table + dump_tables(PageTable::top()); + // Test read - println!("0x{:X} = 0x{:X}", megabyte, machine_read::(megabyte)); + println!("0x{:X} = 0x{:X}", megabyte, arch_read::(megabyte)); // Test write - machine_write::(megabyte, 0x5A); + arch_write::(megabyte, 0x5A); // Test read - println!("0x{:X} = 0x{:X}", megabyte, machine_read::(megabyte)); + println!("0x{:X} = 0x{:X}", megabyte, arch_read::(megabyte)); + + // Initialize memory allocator + let areas = [MemoryArea { + base: PhysicalAddress::new(megabyte), + size: megabyte, + }]; } }