From f7c48049f5ef7141736f871310b33b77cfdf151d Mon Sep 17 00:00:00 2001 From: aarch <126242-aarch@users.noreply.gitlab.redox-os.org> Date: Sat, 18 Apr 2026 15:46:34 +0000 Subject: [PATCH] RISCV64: Change VA scheme to Sv39 for real hardware support + Sv57 definitions --- linkers/riscv64.ld | 4 +- rmm/src/arch/riscv64/mod.rs | 2 + rmm/src/arch/riscv64/sv57.rs | 116 +++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 rmm/src/arch/riscv64/sv57.rs diff --git a/linkers/riscv64.ld b/linkers/riscv64.ld index 8494d8fa81..7935190f2b 100644 --- a/linkers/riscv64.ld +++ b/linkers/riscv64.ld @@ -1,7 +1,7 @@ ENTRY(kstart) OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv" ) -KERNEL_OFFSET = 0xFFFFFF0000000000; +KERNEL_OFFSET = 0xFFFFFFFF80000000; SECTIONS { . = KERNEL_OFFSET; @@ -11,7 +11,7 @@ SECTIONS { /* Force the zero page to be part of a segment by creating a * dummy section in the zero page. * Linker will map the segment with the lowest vaddr value at - * 0xFFFFFF0000000000 even if the segment has a higher vaddr. + * 0xFFFFFFFF80000000 even if the segment has a higher vaddr. * As such without the zero page being part of a segment, the * kernel would be loaded at an offset from the expected * location. As the redox kernel is not currently relocatable, diff --git a/rmm/src/arch/riscv64/mod.rs b/rmm/src/arch/riscv64/mod.rs index 894ef349e4..b12daec511 100644 --- a/rmm/src/arch/riscv64/mod.rs +++ b/rmm/src/arch/riscv64/mod.rs @@ -1,5 +1,7 @@ pub use sv39::RiscV64Sv39Arch; pub use sv48::RiscV64Sv48Arch; +pub use sv57::RiscV64Sv57Arch; mod sv39; mod sv48; +mod sv57; diff --git a/rmm/src/arch/riscv64/sv57.rs b/rmm/src/arch/riscv64/sv57.rs new file mode 100644 index 0000000000..c54ffa4a05 --- /dev/null +++ b/rmm/src/arch/riscv64/sv57.rs @@ -0,0 +1,116 @@ +use core::arch::asm; + +use crate::{Arch, PhysicalAddress, TableKind, VirtualAddress}; + +#[derive(Clone, Copy)] +pub struct RiscV64Sv57Arch; + +impl Arch for RiscV64Sv57Arch { + const KERNEL_SEPARATE_TABLE: bool = false; + + const PAGE_SHIFT: usize = 12; // 4096 bytes + const PAGE_ENTRY_SHIFT: usize = 9; // 512 entries, 8 bytes each + const PAGE_LEVELS: usize = 5; // L0, L1, L2, L3, L4 + + 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 = 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_DEVICE_MEMORY: usize = 0; // FIXME use Svpbmt + const ENTRY_FLAG_UNCACHEABLE: usize = 0; // FIXME use Svpbmt + const ENTRY_FLAG_WRITE_COMBINING: usize = 0; // FIXME use Svpbmt + + const PHYS_OFFSET: usize = 0xFF00_0000_0000_0000; + + #[inline(always)] + fn invalidate(address: VirtualAddress) { + unsafe { asm!("sfence.vma {}", in(reg) address.data()) }; + } + + #[inline(always)] + fn invalidate_all() { + unsafe { asm!("sfence.vma") }; + } + + #[inline(always)] + fn table(_table_kind: TableKind) -> PhysicalAddress { + let satp: usize; + unsafe { asm!("csrr {0}, satp", out(reg) satp) }; + PhysicalAddress::new( + (satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN + ) + } + + #[inline(always)] + unsafe fn set_table(_table_kind: TableKind, address: PhysicalAddress) { + let satp = (10 << 60) | // Sv57 MODE + (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) + unsafe { + asm!("csrw satp, {0}", in(reg) satp); + Self::invalidate_all(); + } + } + + fn virt_is_valid(address: VirtualAddress) -> bool { + let mask = !((Self::PAGE_ADDRESS_SIZE as usize - 1) >> 1); + let masked = address.data() & mask; + + masked == mask || masked == 0 + } +} + +const _: () = { + assert!(RiscV64Sv57Arch::PAGE_SIZE == 4096); + assert!(RiscV64Sv57Arch::PAGE_OFFSET_MASK == 0xFFF); + assert!(RiscV64Sv57Arch::PAGE_ADDRESS_SHIFT == 57); + assert!(RiscV64Sv57Arch::PAGE_ADDRESS_SIZE == 0x0200_0000_0000_0000); + assert!(RiscV64Sv57Arch::PAGE_ADDRESS_MASK == 0x01FF_FFFF_FFFF_F000); + assert!(RiscV64Sv57Arch::PAGE_ENTRY_SIZE == 8); + assert!(RiscV64Sv57Arch::PAGE_ENTRIES == 512); + assert!(RiscV64Sv57Arch::PAGE_ENTRY_MASK == 0x1FF); + assert!(RiscV64Sv57Arch::PAGE_NEGATIVE_MASK == 0xFE00_0000_0000_0000); + + assert!(RiscV64Sv57Arch::ENTRY_ADDRESS_SIZE == 0x0000_1000_0000_0000); + assert!(RiscV64Sv57Arch::ENTRY_ADDRESS_MASK == 0x0000_0FFF_FFFF_FFFF); + assert!(RiscV64Sv57Arch::ENTRY_FLAGS_MASK == 0xFFC0_0000_0000_03FF); + + assert!(RiscV64Sv57Arch::PHYS_OFFSET == 0xFF00_0000_0000_0000); +}; + +#[cfg(test)] +mod tests { + use super::RiscV64Sv57Arch; + use crate::Arch; + + #[test] + fn is_canonical() { + use super::VirtualAddress; + + fn yes(address: usize) { + assert!(RiscV64Sv57Arch::virt_is_valid(VirtualAddress::new(address))); + } + fn no(address: usize) { + assert!(!RiscV64Sv57Arch::virt_is_valid(VirtualAddress::new( + address + ))); + } + + yes(0xFF00_0000_1337_1337); + yes(0xFFFF_FFFF_FFFF_FFFF); + yes(0x0000_0000_0000_0042); + yes(0x00FF_FFFF_FFFF_FFFF); + no(0x1337_0000_0000_0000); + no(0x1337_8000_0000_0000); + no(0x0F00_0000_0000_0000); + } +}