Add riscv64 sv39 and sv48

This commit is contained in:
Jeremy Soller
2021-05-03 11:20:49 -06:00
parent c46d148e26
commit 2f74326384
8 changed files with 188 additions and 0 deletions
+1
View File
@@ -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;
+1
View File
@@ -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;
+6
View File
@@ -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;
+5
View File
@@ -0,0 +1,5 @@
pub use sv39::RiscV64Sv39Arch;
pub use sv48::RiscV64Sv48Arch;
mod sv39;
mod sv48;
+86
View File
@@ -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);
}
}
+86
View File
@@ -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);
}
}
+1
View File
@@ -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
+2
View File
@@ -56,6 +56,8 @@ impl<A: Arch> PageFlags<A> {
#[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)
}
}