diff --git a/src/arch/aarch64.rs b/src/arch/aarch64.rs index 5a89b4b6d6..f9896e3879 100644 --- a/src/arch/aarch64.rs +++ b/src/arch/aarch64.rs @@ -33,6 +33,7 @@ impl Arch for AArch64Arch { // 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; //TODO: adjust to match x86_64? const PHYS_OFFSET: usize = 0xfffffe0000000000; diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index 6f0342808d..35098e2828 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -31,6 +31,7 @@ impl Arch for EmulateArch { const ENTRY_FLAG_READWRITE: usize = X8664Arch::ENTRY_FLAG_READWRITE; const ENTRY_FLAG_USER: usize = X8664Arch::ENTRY_FLAG_USER; const ENTRY_FLAG_NO_EXEC: usize = X8664Arch::ENTRY_FLAG_NO_EXEC; + const ENTRY_FLAG_EXEC: usize = X8664Arch::ENTRY_FLAG_EXEC; const PHYS_OFFSET: usize = X8664Arch::PHYS_OFFSET; diff --git a/src/arch/mod.rs b/src/arch/mod.rs index ceecab5c41..3c9d0e0c31 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -7,11 +7,16 @@ use crate::{ }; pub use self::aarch64::AArch64Arch; +pub use self::riscv64::{ + RiscV64Sv39Arch, + RiscV64Sv48Arch +}; #[cfg(feature = "std")] pub use self::emulate::EmulateArch; pub use self::x86_64::X8664Arch; mod aarch64; +mod riscv64; #[cfg(feature = "std")] mod emulate; mod x86_64; @@ -29,6 +34,7 @@ pub trait Arch: Clone + Copy { const ENTRY_FLAG_READWRITE: usize; const ENTRY_FLAG_USER: usize; const ENTRY_FLAG_NO_EXEC: usize; + const ENTRY_FLAG_EXEC: usize; const PHYS_OFFSET: usize; diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs new file mode 100644 index 0000000000..894ef349e4 --- /dev/null +++ b/src/arch/riscv64/mod.rs @@ -0,0 +1,5 @@ +pub use sv39::RiscV64Sv39Arch; +pub use sv48::RiscV64Sv48Arch; + +mod sv39; +mod sv48; diff --git a/src/arch/riscv64/sv39.rs b/src/arch/riscv64/sv39.rs new file mode 100644 index 0000000000..e8cb7cd8f4 --- /dev/null +++ b/src/arch/riscv64/sv39.rs @@ -0,0 +1,86 @@ +use crate::{ + Arch, + MemoryArea, + PhysicalAddress, + VirtualAddress, +}; + +#[derive(Clone, Copy)] +pub struct RiscV64Sv39Arch; + +impl Arch for RiscV64Sv39Arch { + const PAGE_SHIFT: usize = 12; // 4096 bytes + 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_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_NO_EXEC: usize = 0; + const ENTRY_FLAG_EXEC: usize = 1 << 3; + + //TODO: adjust to match x86_64? + const PHYS_OFFSET: usize = 0xfffffe0000000000; + + 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(); + } + + #[inline(always)] + unsafe fn table() -> PhysicalAddress { + let satp: usize; + asm!("csrr {0}, satp", out(reg) satp); + PhysicalAddress::new( + (satp & 0x0000_0FFF_FFFF_FFFF) << Self::PAGE_SHIFT // Convert from PPN + ) + } + + #[inline(always)] + unsafe fn set_table(address: PhysicalAddress) { + let satp = + (8 << 60) | // Sv39 MODE + (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) + asm!("csrw satp, {0}", in(reg) satp); + } +} + +#[cfg(test)] +mod tests { + use crate::Arch; + use super::RiscV64Sv39Arch; + + #[test] + fn constants() { + assert_eq!(RiscV64Sv39Arch::PAGE_SIZE, 4096); + assert_eq!(RiscV64Sv39Arch::PAGE_OFFSET_MASK, 0xFFF); + assert_eq!(RiscV64Sv39Arch::PAGE_ADDRESS_SHIFT, 39); + assert_eq!(RiscV64Sv39Arch::PAGE_ADDRESS_SIZE, 0x0000_0080_0000_0000); + assert_eq!(RiscV64Sv39Arch::PAGE_ADDRESS_MASK, 0x0000_007F_FFFF_F000); + assert_eq!(RiscV64Sv39Arch::PAGE_ENTRY_SIZE, 8); + assert_eq!(RiscV64Sv39Arch::PAGE_ENTRIES, 512); + 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::PHYS_OFFSET, 0xFFFF_FE00_0000_0000); + } +} diff --git a/src/arch/riscv64/sv48.rs b/src/arch/riscv64/sv48.rs new file mode 100644 index 0000000000..f49076cc66 --- /dev/null +++ b/src/arch/riscv64/sv48.rs @@ -0,0 +1,86 @@ +use crate::{ + Arch, + MemoryArea, + PhysicalAddress, + VirtualAddress, +}; + +#[derive(Clone, Copy)] +pub struct RiscV64Sv48Arch; + +impl Arch for RiscV64Sv48Arch { + const PAGE_SHIFT: usize = 12; // 4096 bytes + 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_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_NO_EXEC: usize = 0; + const ENTRY_FLAG_EXEC: usize = 1 << 3; + + //TODO: adjust to match x86_64? + const PHYS_OFFSET: usize = 0xfffffe0000000000; + + unsafe fn init() -> &'static [MemoryArea] { + unimplemented!("RiscV64Sv48Arch::init unimplemented"); + } + + #[inline(always)] + unsafe fn invalidate(address: VirtualAddress) { + //TODO: can one address be invalidated? + Self::invalidate_all(); + } + + #[inline(always)] + unsafe fn table() -> PhysicalAddress { + let satp: usize; + asm!("csrr {0}, satp", out(reg) satp); + PhysicalAddress::new( + (satp & 0x0000_0FFF_FFFF_FFFF) << Self::PAGE_SHIFT // Convert from PPN + ) + } + + #[inline(always)] + unsafe fn set_table(address: PhysicalAddress) { + let satp = + (9 << 60) | // Sv48 MODE + (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) + asm!("csrw satp, {0}", in(reg) satp); + } +} + +#[cfg(test)] +mod tests { + use crate::Arch; + use super::RiscV64Sv48Arch; + + #[test] + fn constants() { + assert_eq!(RiscV64Sv48Arch::PAGE_SIZE, 4096); + assert_eq!(RiscV64Sv48Arch::PAGE_OFFSET_MASK, 0xFFF); + assert_eq!(RiscV64Sv48Arch::PAGE_ADDRESS_SHIFT, 48); + assert_eq!(RiscV64Sv48Arch::PAGE_ADDRESS_SIZE, 0x0001_0000_0000_0000); + assert_eq!(RiscV64Sv48Arch::PAGE_ADDRESS_MASK, 0x0000_FFFF_FFFF_F000); + assert_eq!(RiscV64Sv48Arch::PAGE_ENTRY_SIZE, 8); + assert_eq!(RiscV64Sv48Arch::PAGE_ENTRIES, 512); + 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::PHYS_OFFSET, 0xFFFF_FE00_0000_0000); + } +} diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 19ff13883f..3b0a2572da 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -23,6 +23,7 @@ impl Arch for X8664Arch { // Not used: const ENTRY_FLAG_HUGE: usize = 1 << 7; // Not used: const ENTRY_FLAG_GLOBAL: usize = 1 << 8; const ENTRY_FLAG_NO_EXEC: usize = 1 << 63; + const ENTRY_FLAG_EXEC: usize = 0; const PHYS_OFFSET: usize = Self::PAGE_NEGATIVE_MASK + (Self::PAGE_ADDRESS_SIZE >> 1); // PML4 slot 256 and onwards diff --git a/src/page/flags.rs b/src/page/flags.rs index 91a181dd60..6a2f084ed3 100644 --- a/src/page/flags.rs +++ b/src/page/flags.rs @@ -56,6 +56,8 @@ impl PageFlags { #[inline(always)] pub fn execute(self, value: bool) -> Self { //TODO: write xor execute? + // Architecture may use no exec or exec, support either self.custom_flag(A::ENTRY_FLAG_NO_EXEC, !value) + .custom_flag(A::ENTRY_FLAG_EXEC, value) } }