Merge branch 'riscv' into 'master'
Fixes and changes to make RISC-V paging work See merge request redox-os/rmm!14
This commit is contained in:
+6
-4
@@ -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);
|
||||
|
||||
+10
-5
@@ -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<A: Arch> Machine<A> {
|
||||
}
|
||||
|
||||
// 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::<usize>(PhysicalAddress::new(a3 + i3 * A::PAGE_ENTRY_SIZE));
|
||||
@@ -285,7 +289,7 @@ impl<A: Arch> Machine<A> {
|
||||
}
|
||||
|
||||
// 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::<usize>(PhysicalAddress::new(a2 + i2 * A::PAGE_ENTRY_SIZE));
|
||||
@@ -295,7 +299,8 @@ impl<A: Arch> Machine<A> {
|
||||
}
|
||||
|
||||
// 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::<usize>(PhysicalAddress::new(a1 + i1 * A::PAGE_ENTRY_SIZE));
|
||||
@@ -308,7 +313,7 @@ impl<A: Arch> Machine<A> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -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];
|
||||
|
||||
|
||||
+26
-21
@@ -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() {
|
||||
|
||||
+23
-17
@@ -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);
|
||||
}
|
||||
|
||||
+6
-5
@@ -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);
|
||||
|
||||
+6
-5
@@ -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);
|
||||
|
||||
+11
-2
@@ -10,7 +10,14 @@ pub struct PageEntry<A> {
|
||||
|
||||
impl<A: Arch> PageEntry<A> {
|
||||
#[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<A: Arch> PageEntry<A> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn address(&self) -> Result<PhysicalAddress, PhysicalAddress> {
|
||||
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)
|
||||
|
||||
+18
-10
@@ -27,10 +27,7 @@ impl<A: Arch> PageFlags<A> {
|
||||
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<A: Arch> PageFlags<A> {
|
||||
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<A: Arch> PageFlags<A> {
|
||||
#[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
|
||||
}
|
||||
|
||||
|
||||
+7
-8
@@ -65,7 +65,7 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
|
||||
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<A: Arch, F: FrameAllocator> PageMapper<A, F> {
|
||||
) -> Option<PageFlush<A>> {
|
||||
//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<A: Arch, F: FrameAllocator> PageMapper<A, F> {
|
||||
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<A: Arch>(
|
||||
|
||||
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<A: Arch>(
|
||||
|
||||
if !is_still_populated {
|
||||
allocator.free_one(subtable.phys());
|
||||
table.set_entry(i, PageEntry::new(0));
|
||||
table.set_entry(i, PageEntry::new(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ impl<A: Arch> PageTable<A> {
|
||||
|
||||
pub unsafe fn entry(&self, i: usize) -> Option<PageEntry<A>> {
|
||||
let addr = self.entry_virt(i)?;
|
||||
Some(PageEntry::new(A::read::<usize>(addr)))
|
||||
Some(PageEntry::from_data(A::read::<usize>(addr)))
|
||||
}
|
||||
|
||||
pub unsafe fn set_entry(&mut self, i: usize, entry: PageEntry<A>) -> Option<()> {
|
||||
|
||||
Reference in New Issue
Block a user