diff --git a/src/arch/aarch64.rs b/src/arch/aarch64.rs index 3a811a0184..687294d3b5 100644 --- a/src/arch/aarch64.rs +++ b/src/arch/aarch64.rs @@ -11,26 +11,28 @@ impl Arch for AArch64Arch { const PAGE_LEVELS: usize = 4; // L0, L1, L2, L3 //TODO - const ENTRY_ADDRESS_SHIFT: usize = 52; + const ENTRY_ADDRESS_WIDTH: usize = 40; const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT | 1 << 1 // Page flag | 1 << 10 // Access flag | Self::ENTRY_FLAG_NO_GLOBAL; const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT + | Self::ENTRY_FLAG_READWRITE | 1 << 1 // Table flag | 1 << 10 // Access flag ; const ENTRY_FLAG_PRESENT: usize = 1 << 0; const ENTRY_FLAG_READONLY: usize = 1 << 7; const ENTRY_FLAG_READWRITE: usize = 0; - const ENTRY_FLAG_USER: usize = 1 << 6; + const ENTRY_FLAG_PAGE_USER: usize = 1 << 6; // This sets both userspace and privileged execute never //TODO: Separate the two? const ENTRY_FLAG_NO_EXEC: usize = 0b11 << 53; const ENTRY_FLAG_EXEC: usize = 0; const ENTRY_FLAG_GLOBAL: usize = 0; const ENTRY_FLAG_NO_GLOBAL: usize = 1 << 11; + const ENTRY_FLAG_WRITE_COMBINING: usize = 0; const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000; @@ -110,8 +112,8 @@ mod tests { assert_eq!(AArch64Arch::PAGE_ENTRY_MASK, 0x1FF); assert_eq!(AArch64Arch::PAGE_NEGATIVE_MASK, 0xFFFF_0000_0000_0000); - assert_eq!(AArch64Arch::ENTRY_ADDRESS_SIZE, 0x0010_0000_0000_0000); - assert_eq!(AArch64Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF_FFFF_F000); + assert_eq!(AArch64Arch::ENTRY_ADDRESS_SIZE, 0x0000_0100_0000_0000); + assert_eq!(AArch64Arch::ENTRY_ADDRESS_MASK, 0x0000_00FF_FFFF_FFFF); assert_eq!(AArch64Arch::ENTRY_FLAGS_MASK, 0xFFF0_0000_0000_0FFF); assert_eq!(AArch64Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000); diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index 88a200769a..3e381db676 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -20,7 +20,7 @@ impl Arch for EmulateArch { const ENTRY_FLAG_PRESENT: usize = X8664Arch::ENTRY_FLAG_PRESENT; const ENTRY_FLAG_READONLY: usize = X8664Arch::ENTRY_FLAG_READONLY; const ENTRY_FLAG_READWRITE: usize = X8664Arch::ENTRY_FLAG_READWRITE; - const ENTRY_FLAG_USER: usize = X8664Arch::ENTRY_FLAG_USER; + const ENTRY_FLAG_PAGE_USER: usize = X8664Arch::ENTRY_FLAG_PAGE_USER; const ENTRY_FLAG_NO_EXEC: usize = X8664Arch::ENTRY_FLAG_NO_EXEC; const ENTRY_FLAG_EXEC: usize = X8664Arch::ENTRY_FLAG_EXEC; @@ -29,6 +29,10 @@ impl Arch for EmulateArch { const ENTRY_FLAG_GLOBAL: usize = X8664Arch::ENTRY_FLAG_GLOBAL; const ENTRY_FLAG_NO_GLOBAL: usize = X8664Arch::ENTRY_FLAG_NO_GLOBAL; + const ENTRY_ADDRESS_WIDTH: usize = X8664Arch::ENTRY_ADDRESS_WIDTH; + + const ENTRY_FLAG_WRITE_COMBINING: usize = X8664Arch::ENTRY_FLAG_WRITE_COMBINING; + unsafe fn init() -> &'static [MemoryArea] { // Create machine with PAGE_ENTRIES pages offset mapped (2 MiB on x86_64) let mut machine = Machine::new(MEMORY_SIZE); @@ -275,7 +279,7 @@ impl Machine { } // Page directory pointer - let a3 = e3 & A::ENTRY_ADDRESS_MASK; + let a3 = ((e3 >> A::ENTRY_ADDRESS_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::PAGE_SHIFT; for i3 in 0..A::PAGE_ENTRIES { let e2 = self.read_phys::(PhysicalAddress::new(a3 + i3 * A::PAGE_ENTRY_SIZE)); @@ -285,7 +289,7 @@ impl Machine { } // Page directory - let a2 = e2 & A::ENTRY_ADDRESS_MASK; + let a2 = ((e2 >> A::ENTRY_ADDRESS_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::PAGE_SHIFT; for i2 in 0..A::PAGE_ENTRIES { let e1 = self.read_phys::(PhysicalAddress::new(a2 + i2 * A::PAGE_ENTRY_SIZE)); @@ -295,7 +299,8 @@ impl Machine { } // Page table - let a1 = e1 & A::ENTRY_ADDRESS_MASK; + let a1 = + ((e1 >> A::ENTRY_ADDRESS_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::PAGE_SHIFT; for i1 in 0..A::PAGE_ENTRIES { let e = self .read_phys::(PhysicalAddress::new(a1 + i1 * A::PAGE_ENTRY_SIZE)); @@ -308,7 +313,7 @@ impl Machine { let page = (i4 << 39) | (i3 << 30) | (i2 << 21) | (i1 << 12); //println!("map 0x{:X} to 0x{:X}, 0x{:X}", page, a, f); self.map - .insert(VirtualAddress::new(page), PageEntry::new(e)); + .insert(VirtualAddress::new(page), PageEntry::from_data(e)); } } } diff --git a/src/arch/mod.rs b/src/arch/mod.rs index f6f5ec9c53..cd68f09f2c 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -30,17 +30,20 @@ pub trait Arch: Clone + Copy { const PAGE_ENTRY_SHIFT: usize; const PAGE_LEVELS: usize; - const ENTRY_ADDRESS_SHIFT: usize; + const ENTRY_ADDRESS_WIDTH: usize; // Number of bits of physical address in PTE + const ENTRY_ADDRESS_SHIFT: usize = Self::PAGE_SHIFT; // Offset of physical address in PTE const ENTRY_FLAG_DEFAULT_PAGE: usize; const ENTRY_FLAG_DEFAULT_TABLE: usize; const ENTRY_FLAG_PRESENT: usize; const ENTRY_FLAG_READONLY: usize; const ENTRY_FLAG_READWRITE: usize; - const ENTRY_FLAG_USER: usize; + const ENTRY_FLAG_PAGE_USER: usize; // Leaf table user page flag + const ENTRY_FLAG_TABLE_USER: usize = Self::ENTRY_FLAG_PAGE_USER; // Directory user page table flag const ENTRY_FLAG_NO_EXEC: usize; const ENTRY_FLAG_EXEC: usize; const ENTRY_FLAG_GLOBAL: usize; const ENTRY_FLAG_NO_GLOBAL: usize; + const ENTRY_FLAG_WRITE_COMBINING: usize; const PHYS_OFFSET: usize; @@ -54,10 +57,9 @@ pub trait Arch: Clone + Copy { const PAGE_ENTRY_MASK: usize = Self::PAGE_ENTRIES - 1; const PAGE_NEGATIVE_MASK: usize = !(Self::PAGE_ADDRESS_SIZE - 1) as usize; - const ENTRY_ADDRESS_SIZE: u64 = 1 << Self::ENTRY_ADDRESS_SHIFT; - const ENTRY_ADDRESS_MASK: usize = - (Self::ENTRY_ADDRESS_SIZE - (Self::PAGE_SIZE as u64)) as usize; - const ENTRY_FLAGS_MASK: usize = !Self::ENTRY_ADDRESS_MASK; + const ENTRY_ADDRESS_SIZE: usize = 1 << Self::ENTRY_ADDRESS_WIDTH; // size of addressable physical memory, in pages + const ENTRY_ADDRESS_MASK: usize = Self::ENTRY_ADDRESS_SIZE - 1; // Mask of physical address, starting at 0th bit + const ENTRY_FLAGS_MASK: usize = !(Self::ENTRY_ADDRESS_MASK << Self::ENTRY_ADDRESS_SHIFT); unsafe fn init() -> &'static [MemoryArea]; diff --git a/src/arch/riscv64/sv39.rs b/src/arch/riscv64/sv39.rs index 0980428754..31ade20c1e 100644 --- a/src/arch/riscv64/sv39.rs +++ b/src/arch/riscv64/sv39.rs @@ -10,32 +10,36 @@ impl Arch for RiscV64Sv39Arch { const PAGE_ENTRY_SHIFT: usize = 9; // 512 entries, 8 bytes each const PAGE_LEVELS: usize = 3; // L0, L1, L2 - //TODO - const ENTRY_ADDRESS_SHIFT: usize = 52; - const ENTRY_FLAG_DEFAULT_PAGE: usize - = Self::ENTRY_FLAG_PRESENT - | 1 << 1 // Read flag - ; + const ENTRY_ADDRESS_WIDTH: usize = 44; + const ENTRY_ADDRESS_SHIFT: usize = 10; + + const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_READONLY; const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT; const ENTRY_FLAG_PRESENT: usize = 1 << 0; - const ENTRY_FLAG_READONLY: usize = 0; - const ENTRY_FLAG_READWRITE: usize = 1 << 2; - const ENTRY_FLAG_USER: usize = 1 << 4; + const ENTRY_FLAG_READONLY: usize = 1 << 1; + const ENTRY_FLAG_READWRITE: usize = 3 << 1; + const ENTRY_FLAG_PAGE_USER: usize = 1 << 4; + const ENTRY_FLAG_TABLE_USER: usize = 0; const ENTRY_FLAG_NO_EXEC: usize = 0; const ENTRY_FLAG_EXEC: usize = 1 << 3; const ENTRY_FLAG_GLOBAL: usize = 1 << 5; const ENTRY_FLAG_NO_GLOBAL: usize = 0; + const ENTRY_FLAG_WRITE_COMBINING: usize = 0; - const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000; + const PHYS_OFFSET: usize = 0xFFFF_FFC0_0000_0000; unsafe fn init() -> &'static [MemoryArea] { unimplemented!("RiscV64Sv39Arch::init unimplemented"); } #[inline(always)] - unsafe fn invalidate(_address: VirtualAddress) { - //TODO: can one address be invalidated? - Self::invalidate_all(); + unsafe fn invalidate(address: VirtualAddress) { + asm!("sfence.vma {}", in(reg) address.data()); + } + + #[inline(always)] + unsafe fn invalidate_all() { + asm!("sfence.vma"); } #[inline(always)] @@ -43,7 +47,7 @@ impl Arch for RiscV64Sv39Arch { let satp: usize; asm!("csrr {0}, satp", out(reg) satp); PhysicalAddress::new( - (satp & 0x0000_0FFF_FFFF_FFFF) << Self::PAGE_SHIFT, // Convert from PPN + (satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN ) } @@ -52,13 +56,14 @@ impl Arch for RiscV64Sv39Arch { let satp = (8 << 60) | // Sv39 MODE (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) asm!("csrw satp, {0}", in(reg) satp); + Self::invalidate_all(); } fn virt_is_valid(address: VirtualAddress) -> bool { - const MASK: usize = 0xFFFF_FFC0_0000_0000; - let masked = address.data() & MASK; + let mask = !((Self::PAGE_ADDRESS_SIZE as usize - 1) >> 1); + let masked = address.data() & mask; - masked == MASK || masked == 0 + masked == mask || masked == 0 } } @@ -79,11 +84,11 @@ mod tests { assert_eq!(RiscV64Sv39Arch::PAGE_ENTRY_MASK, 0x1FF); assert_eq!(RiscV64Sv39Arch::PAGE_NEGATIVE_MASK, 0xFFFF_FF80_0000_0000); - assert_eq!(RiscV64Sv39Arch::ENTRY_ADDRESS_SIZE, 0x0010_0000_0000_0000); - assert_eq!(RiscV64Sv39Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF_FFFF_F000); - assert_eq!(RiscV64Sv39Arch::ENTRY_FLAGS_MASK, 0xFFF0_0000_0000_0FFF); + assert_eq!(RiscV64Sv39Arch::ENTRY_ADDRESS_SIZE, 0x0000_1000_0000_0000); + assert_eq!(RiscV64Sv39Arch::ENTRY_ADDRESS_MASK, 0x0000_0FFF_FFFF_FFFF); + assert_eq!(RiscV64Sv39Arch::ENTRY_FLAGS_MASK, 0xFFC0_0000_0000_03FF); - assert_eq!(RiscV64Sv39Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000); + assert_eq!(RiscV64Sv39Arch::PHYS_OFFSET, 0xFFFF_FFC0_0000_0000); } #[test] fn is_canonical() { diff --git a/src/arch/riscv64/sv48.rs b/src/arch/riscv64/sv48.rs index b1142317f0..7e80ad0c3a 100644 --- a/src/arch/riscv64/sv48.rs +++ b/src/arch/riscv64/sv48.rs @@ -10,21 +10,21 @@ impl Arch for RiscV64Sv48Arch { const PAGE_ENTRY_SHIFT: usize = 9; // 512 entries, 8 bytes each const PAGE_LEVELS: usize = 4; // L0, L1, L2, L3 - //TODO - const ENTRY_ADDRESS_SHIFT: usize = 52; - const ENTRY_FLAG_DEFAULT_PAGE: usize - = Self::ENTRY_FLAG_PRESENT - | 1 << 1 // Read flag - ; + const ENTRY_ADDRESS_WIDTH: usize = 44; + const ENTRY_ADDRESS_SHIFT: usize = 10; + + const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_READONLY; const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT; const ENTRY_FLAG_PRESENT: usize = 1 << 0; - const ENTRY_FLAG_READONLY: usize = 0; - const ENTRY_FLAG_READWRITE: usize = 1 << 2; - const ENTRY_FLAG_USER: usize = 1 << 4; + const ENTRY_FLAG_READONLY: usize = 1 << 1; + const ENTRY_FLAG_READWRITE: usize = 3 << 1; + const ENTRY_FLAG_PAGE_USER: usize = 1 << 4; + const ENTRY_FLAG_TABLE_USER: usize = 0; const ENTRY_FLAG_NO_EXEC: usize = 0; const ENTRY_FLAG_EXEC: usize = 1 << 3; const ENTRY_FLAG_GLOBAL: usize = 1 << 5; const ENTRY_FLAG_NO_GLOBAL: usize = 0; + const ENTRY_FLAG_WRITE_COMBINING: usize = 0; const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000; @@ -33,9 +33,13 @@ impl Arch for RiscV64Sv48Arch { } #[inline(always)] - unsafe fn invalidate(_address: VirtualAddress) { - //TODO: can one address be invalidated? - Self::invalidate_all(); + unsafe fn invalidate(address: VirtualAddress) { + asm!("sfence.vma {}", in(reg) address.data()); + } + + #[inline(always)] + unsafe fn invalidate_all() { + asm!("sfence.vma"); } #[inline(always)] @@ -43,7 +47,7 @@ impl Arch for RiscV64Sv48Arch { let satp: usize; asm!("csrr {0}, satp", out(reg) satp); PhysicalAddress::new( - (satp & 0x0000_0FFF_FFFF_FFFF) << Self::PAGE_SHIFT, // Convert from PPN + (satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN ) } @@ -52,10 +56,12 @@ impl Arch for RiscV64Sv48Arch { let satp = (9 << 60) | // Sv48 MODE (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) asm!("csrw satp, {0}", in(reg) satp); + Self::invalidate_all(); } + fn virt_is_valid(address: VirtualAddress) -> bool { // RISC-V SV48 uses 48-bit sign-extended addresses, identical to 4-level paging on x86_64. - let mask = 0xFFFF_8000_0000_0000; + let mask = !((Self::PAGE_ADDRESS_SIZE as usize - 1) >> 1); let masked = address.data() & mask; masked == mask || masked == 0 @@ -79,9 +85,9 @@ mod tests { assert_eq!(RiscV64Sv48Arch::PAGE_ENTRY_MASK, 0x1FF); assert_eq!(RiscV64Sv48Arch::PAGE_NEGATIVE_MASK, 0xFFFF_0000_0000_0000); - assert_eq!(RiscV64Sv48Arch::ENTRY_ADDRESS_SIZE, 0x0010_0000_0000_0000); - assert_eq!(RiscV64Sv48Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF_FFFF_F000); - assert_eq!(RiscV64Sv48Arch::ENTRY_FLAGS_MASK, 0xFFF0_0000_0000_0FFF); + assert_eq!(RiscV64Sv48Arch::ENTRY_ADDRESS_SIZE, 0x0000_1000_0000_0000); + assert_eq!(RiscV64Sv48Arch::ENTRY_ADDRESS_MASK, 0x0000_0FFF_FFFF_FFFF); + assert_eq!(RiscV64Sv48Arch::ENTRY_FLAGS_MASK, 0xFFC0_0000_0000_03FF); assert_eq!(RiscV64Sv48Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000); } diff --git a/src/arch/x86.rs b/src/arch/x86.rs index 8dcd238f3e..7e078a2fc0 100644 --- a/src/arch/x86.rs +++ b/src/arch/x86.rs @@ -11,18 +11,19 @@ impl Arch for X86Arch { const PAGE_ENTRY_SHIFT: usize = 10; // 1024 entries, 4 bytes each const PAGE_LEVELS: usize = 2; // PD, PT - const ENTRY_ADDRESS_SHIFT: usize = 32; + const ENTRY_ADDRESS_WIDTH: usize = 20; const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT; - const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT; + const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_READWRITE; const ENTRY_FLAG_PRESENT: usize = 1 << 0; const ENTRY_FLAG_READONLY: usize = 0; const ENTRY_FLAG_READWRITE: usize = 1 << 1; - const ENTRY_FLAG_USER: usize = 1 << 2; + const ENTRY_FLAG_PAGE_USER: usize = 1 << 2; // Not used: const ENTRY_FLAG_HUGE: usize = 1 << 7; const ENTRY_FLAG_GLOBAL: usize = 1 << 8; const ENTRY_FLAG_NO_GLOBAL: usize = 0; const ENTRY_FLAG_NO_EXEC: usize = 0; // NOT AVAILABLE UNLESS PAE IS USED! const ENTRY_FLAG_EXEC: usize = 0; + const ENTRY_FLAG_WRITE_COMBINING: usize = 1 << 7; const PHYS_OFFSET: usize = 0x8000_0000; @@ -70,8 +71,8 @@ mod tests { assert_eq!(X86Arch::PAGE_ENTRY_MASK, 0x3FF); assert_eq!(X86Arch::PAGE_NEGATIVE_MASK, 0x0000_0000_0000); - assert_eq!(X86Arch::ENTRY_ADDRESS_SIZE, 0x0000_0001_0000_0000); - assert_eq!(X86Arch::ENTRY_ADDRESS_MASK, 0xFFFF_F000); + assert_eq!(X86Arch::ENTRY_ADDRESS_SIZE, 0x0000_0000_0010_0000); + assert_eq!(X86Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF); assert_eq!(X86Arch::ENTRY_FLAGS_MASK, 0x0000_0FFF); assert_eq!(X86Arch::PHYS_OFFSET, 0x8000_0000); diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 113f66f036..3b0bacff0d 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -10,18 +10,19 @@ impl Arch for X8664Arch { const PAGE_ENTRY_SHIFT: usize = 9; // 512 entries, 8 bytes each const PAGE_LEVELS: usize = 4; // PML4, PDP, PD, PT - const ENTRY_ADDRESS_SHIFT: usize = 52; + const ENTRY_ADDRESS_WIDTH: usize = 40; const ENTRY_FLAG_DEFAULT_PAGE: usize = Self::ENTRY_FLAG_PRESENT; - const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT; + const ENTRY_FLAG_DEFAULT_TABLE: usize = Self::ENTRY_FLAG_PRESENT | Self::ENTRY_FLAG_READWRITE; const ENTRY_FLAG_PRESENT: usize = 1 << 0; const ENTRY_FLAG_READONLY: usize = 0; const ENTRY_FLAG_READWRITE: usize = 1 << 1; - const ENTRY_FLAG_USER: usize = 1 << 2; + const ENTRY_FLAG_PAGE_USER: usize = 1 << 2; // Not used: const ENTRY_FLAG_HUGE: usize = 1 << 7; const ENTRY_FLAG_GLOBAL: usize = 1 << 8; const ENTRY_FLAG_NO_GLOBAL: usize = 0; const ENTRY_FLAG_NO_EXEC: usize = 1 << 63; const ENTRY_FLAG_EXEC: usize = 0; + const ENTRY_FLAG_WRITE_COMBINING: usize = 1 << 7; const PHYS_OFFSET: usize = Self::PAGE_NEGATIVE_MASK + (Self::PAGE_ADDRESS_SIZE >> 1) as usize; // PML4 slot 256 and onwards @@ -80,8 +81,8 @@ mod tests { assert_eq!(X8664Arch::PAGE_ENTRY_MASK, 0x1FF); assert_eq!(X8664Arch::PAGE_NEGATIVE_MASK, 0xFFFF_0000_0000_0000); - assert_eq!(X8664Arch::ENTRY_ADDRESS_SIZE, 0x0010_0000_0000_0000); - assert_eq!(X8664Arch::ENTRY_ADDRESS_MASK, 0x000F_FFFF_FFFF_F000); + assert_eq!(X8664Arch::ENTRY_ADDRESS_SIZE, 0x0000_0100_0000_0000); + assert_eq!(X8664Arch::ENTRY_ADDRESS_MASK, 0x0000_00FF_FFFF_FFFF); assert_eq!(X8664Arch::ENTRY_FLAGS_MASK, 0xFFF0_0000_0000_0FFF); assert_eq!(X8664Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000); diff --git a/src/page/entry.rs b/src/page/entry.rs index 34a83d448f..ac75f162b0 100644 --- a/src/page/entry.rs +++ b/src/page/entry.rs @@ -10,7 +10,14 @@ pub struct PageEntry { impl PageEntry { #[inline(always)] - pub fn new(data: usize) -> Self { + pub fn new(address: usize, flags: usize) -> Self { + let data = (((address >> A::PAGE_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::ENTRY_ADDRESS_SHIFT) + | flags; + Self::from_data(data) + } + + #[inline(always)] + pub fn from_data(data: usize) -> Self { Self { data, phantom: PhantomData, @@ -24,7 +31,9 @@ impl PageEntry { #[inline(always)] pub fn address(&self) -> Result { - let addr = PhysicalAddress(self.data & A::ENTRY_ADDRESS_MASK); + let addr = PhysicalAddress( + ((self.data >> A::ENTRY_ADDRESS_SHIFT) & A::ENTRY_ADDRESS_MASK) << A::PAGE_SHIFT, + ); if self.present() { Ok(addr) diff --git a/src/page/flags.rs b/src/page/flags.rs index bffe12643e..3d90691d60 100644 --- a/src/page/flags.rs +++ b/src/page/flags.rs @@ -27,10 +27,7 @@ impl PageFlags { unsafe { Self::from_data( // Flags set to present, kernel space, read-only, no-execute by default - A::ENTRY_FLAG_DEFAULT_TABLE - | A::ENTRY_FLAG_READONLY - | A::ENTRY_FLAG_NO_EXEC - | A::ENTRY_FLAG_NO_GLOBAL, + A::ENTRY_FLAG_DEFAULT_TABLE | A::ENTRY_FLAG_NO_EXEC | A::ENTRY_FLAG_NO_GLOBAL, ) } } @@ -59,6 +56,12 @@ impl PageFlags { self } + #[must_use] + #[inline(always)] + pub fn write_combining(self, value: bool) -> Self { + self.custom_flag(A::ENTRY_FLAG_WRITE_COMBINING, value) + } + #[inline(always)] pub fn has_flag(&self, flag: usize) -> bool { self.data & flag == flag @@ -72,25 +75,30 @@ impl PageFlags { #[must_use] #[inline(always)] pub fn user(self, value: bool) -> Self { - self.custom_flag(A::ENTRY_FLAG_USER, value) + self.custom_flag(A::ENTRY_FLAG_PAGE_USER, value) } #[inline(always)] pub fn has_user(&self) -> bool { - self.has_flag(A::ENTRY_FLAG_USER) + self.has_flag(A::ENTRY_FLAG_PAGE_USER) } #[must_use] #[inline(always)] pub fn write(self, value: bool) -> Self { - // Architecture may use readonly or readwrite, support either - self.custom_flag(A::ENTRY_FLAG_READONLY, !value) - .custom_flag(A::ENTRY_FLAG_READWRITE, value) + // Architecture may use readonly or readwrite, or both, support either + if value { + self.custom_flag(A::ENTRY_FLAG_READONLY | A::ENTRY_FLAG_READWRITE, false) + .custom_flag(A::ENTRY_FLAG_READWRITE, true) + } else { + self.custom_flag(A::ENTRY_FLAG_READONLY | A::ENTRY_FLAG_READWRITE, false) + .custom_flag(A::ENTRY_FLAG_READONLY, true) + } } #[inline(always)] pub fn has_write(&self) -> bool { - // Architecture may use readonly or readwrite, support either + // Architecture may use readonly or readwrite, or both, support either self.data & (A::ENTRY_FLAG_READONLY | A::ENTRY_FLAG_READWRITE) == A::ENTRY_FLAG_READWRITE } diff --git a/src/page/mapper.rs b/src/page/mapper.rs index 28bea52791..a6aa726be8 100644 --- a/src/page/mapper.rs +++ b/src/page/mapper.rs @@ -65,7 +65,7 @@ impl PageMapper { let old_flags = old_entry.flags(); let (new_phys, new_flags) = f(old_phys, old_flags); // TODO: Higher-level PageEntry::new interface? - let new_entry = PageEntry::new(new_phys.data() | new_flags.data()); + let new_entry = PageEntry::new(new_phys.data(), new_flags.data()); p1.set_entry(i, new_entry); Some((old_flags, old_phys, PageFlush::new(virt))) }) @@ -105,7 +105,7 @@ impl PageMapper { ) -> Option> { //TODO: verify virt and phys are aligned //TODO: verify flags have correct bits - let entry = PageEntry::new(phys.data() | flags.data()); + let entry = PageEntry::new(phys.data(), flags.data()); let mut table = self.table(); loop { let i = table.index_of(virt)?; @@ -120,14 +120,13 @@ impl PageMapper { None => { let next_phys = self.allocator.allocate_one()?; //TODO: correct flags? - let flags = A::ENTRY_FLAG_READWRITE - | A::ENTRY_FLAG_DEFAULT_TABLE + let flags = A::ENTRY_FLAG_DEFAULT_TABLE | if virt.kind() == TableKind::User { - A::ENTRY_FLAG_USER + A::ENTRY_FLAG_TABLE_USER } else { 0 }; - table.set_entry(i, PageEntry::new(next_phys.data() | flags)); + table.set_entry(i, PageEntry::new(next_phys.data(), flags)); table.next(i)? } }; @@ -198,7 +197,7 @@ unsafe fn unmap_phys_inner( if table.level() == 0 { let entry_opt = table.entry(i); - table.set_entry(i, PageEntry::new(0)); + table.set_entry(i, PageEntry::new(0, 0)); let entry = entry_opt?; Some((entry.address().ok()?, entry.flags())) @@ -218,7 +217,7 @@ unsafe fn unmap_phys_inner( if !is_still_populated { allocator.free_one(subtable.phys()); - table.set_entry(i, PageEntry::new(0)); + table.set_entry(i, PageEntry::new(0, 0)); } } diff --git a/src/page/table.rs b/src/page/table.rs index 323a808c00..70d281543d 100644 --- a/src/page/table.rs +++ b/src/page/table.rs @@ -72,7 +72,7 @@ impl PageTable { pub unsafe fn entry(&self, i: usize) -> Option> { let addr = self.entry_virt(i)?; - Some(PageEntry::new(A::read::(addr))) + Some(PageEntry::from_data(A::read::(addr))) } pub unsafe fn set_entry(&mut self, i: usize, entry: PageEntry) -> Option<()> {