From 32caee3095e54a8d9181841fe48d9ea8d43f4e6c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 8 Jul 2021 13:27:08 +0200 Subject: [PATCH 1/3] Add arch functions for checking canonical addrs. --- src/arch/aarch64.rs | 13 ++++++++++++ src/arch/mod.rs | 4 ++++ src/arch/riscv64/sv39.rs | 8 +++++++ src/arch/riscv64/sv48.rs | 7 +++++++ src/arch/x86_64.rs | 45 +++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 +- 6 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/arch/aarch64.rs b/src/arch/aarch64.rs index f9896e3879..3f5305a5d3 100644 --- a/src/arch/aarch64.rs +++ b/src/arch/aarch64.rs @@ -84,6 +84,19 @@ impl Arch for AArch64Arch { //TODO: Does this need to be called? Self::invalidate_all(); } + + fn virt_is_valid(address: VirtualAddress) -> bool { + // TODO + true + } + fn virt_kind(address: VirtualAddress) -> TableKind { + // TODO: Is this correct? + if address.data() & (1 << 63) == (1 << 63) { + TableKind::Kernel + } else { + TableKind::User + } + } } #[cfg(test)] diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 3c9d0e0c31..a24eae36e0 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -3,6 +3,7 @@ use core::ptr; use crate::{ MemoryArea, PhysicalAddress, + TableKind, VirtualAddress, }; @@ -84,4 +85,7 @@ pub trait Arch: Clone + Copy { unsafe fn phys_to_virt(phys: PhysicalAddress) -> VirtualAddress { VirtualAddress::new(phys.data() + Self::PHYS_OFFSET) } + + fn virt_is_valid(address: VirtualAddress) -> bool; + fn virt_kind(address: VirtualAddress) -> TableKind; } diff --git a/src/arch/riscv64/sv39.rs b/src/arch/riscv64/sv39.rs index e8cb7cd8f4..ced17ecb0d 100644 --- a/src/arch/riscv64/sv39.rs +++ b/src/arch/riscv64/sv39.rs @@ -2,6 +2,7 @@ use crate::{ Arch, MemoryArea, PhysicalAddress, + TableKind, VirtualAddress, }; @@ -58,6 +59,13 @@ impl Arch for RiscV64Sv39Arch { (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) asm!("csrw satp, {0}", in(reg) satp); } + + fn virt_is_valid(address: VirtualAddress) -> bool { + todo!() + } + fn virt_kind(address: VirtualAddress) -> TableKind { + todo!() + } } #[cfg(test)] diff --git a/src/arch/riscv64/sv48.rs b/src/arch/riscv64/sv48.rs index f49076cc66..f26aeb7216 100644 --- a/src/arch/riscv64/sv48.rs +++ b/src/arch/riscv64/sv48.rs @@ -2,6 +2,7 @@ use crate::{ Arch, MemoryArea, PhysicalAddress, + TableKind, VirtualAddress, }; @@ -58,6 +59,12 @@ impl Arch for RiscV64Sv48Arch { (address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment) asm!("csrw satp, {0}", in(reg) satp); } + fn virt_is_valid(address: VirtualAddress) -> bool { + todo!() + } + fn virt_kind(address: VirtualAddress) -> TableKind { + todo!() + } } #[cfg(test)] diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index 3b0a2572da..ead8013100 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -2,6 +2,7 @@ use crate::{ Arch, MemoryArea, PhysicalAddress, + TableKind, VirtualAddress, }; @@ -47,12 +48,37 @@ impl Arch for X8664Arch { unsafe fn set_table(address: PhysicalAddress) { asm!("mov cr3, {0}", in(reg) address.data()); } + + fn virt_is_valid(address: VirtualAddress) -> bool { + // On x86_64, an address is valid if and only if it is canonical. It may still point to + // unmapped memory, but will always be valid once translated via the page table has + // suceeded. + address.is_canonical() + } + fn virt_kind(address: VirtualAddress) -> TableKind { + if address.data() & (1 << 48) == (1 << 48) { + TableKind::Kernel + } else { + TableKind::User + } + } +} + +impl VirtualAddress { + #[cfg(any(doc, target_arch = "x86_64"))] + #[doc(cfg(target_arch = "x86_64"))] + pub fn is_canonical(self) -> bool { + let masked = self.data() & 0xFFFF_8000_0000_0000; + // TODO: 5-level paging + masked == 0xFFFF_8000_0000_0000 + || masked == 0 + } } #[cfg(test)] mod tests { use crate::Arch; - use super::X8664Arch; + use super::{VirtualAddress, X8664Arch}; #[test] fn constants() { @@ -72,4 +98,21 @@ mod tests { assert_eq!(X8664Arch::PHYS_OFFSET, 0xFFFF_8000_0000_0000); } + #[test] + fn is_canonical() { + fn yes(address: usize) { + assert!(VirtualAddress::new(address).is_canonical()); + } + fn no(address: usize) { + assert!(!VirtualAddress::new(address).is_canonical()); + } + + yes(0xFFFF_8000_1337_1337); + yes(0xFFFF_FFFF_FFFF_FFFF); + yes(0x0000_0000_0000_0042); + yes(0x0000_7FFF_FFFF_FFFF); + no(0x1337_0000_0000_0000); + no(0x1337_8000_0000_0000); + no(0x0000_8000_0000_0000); + } } diff --git a/src/lib.rs b/src/lib.rs index 487e089e88..58d27a564b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![feature(asm)] +#![feature(asm, doc_cfg)] pub use crate::{ allocator::*, From b75c329a273d194e313bc36a1ceab5362fd5f8e2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 8 Jul 2021 13:35:51 +0200 Subject: [PATCH 2/3] Add virt_kind and virt_is_valid for emulation. --- src/arch/emulate.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index 35098e2828..fade414bc0 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -101,6 +101,18 @@ impl Arch for EmulateArch { unsafe fn set_table(address: PhysicalAddress) { MACHINE.as_mut().unwrap().set_table(address); } + fn virt_kind(address: VirtualAddress) -> crate::TableKind { + // TODO + if address.data() & (1 << 63) == (1 << 63) { + crate::TableKind::Kernel + } else { + crate::TableKind::User + } + } + fn virt_is_valid(_address: VirtualAddress) -> bool { + // TODO + true + } } const MEMORY_SIZE: usize = 64 * MEGABYTE; From 6bc59e70131135984a41216c45e4dc3a6395a30a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 8 Jul 2021 16:06:51 +0200 Subject: [PATCH 3/3] Remove virt_kind, impl virt_is_valid() for riscv. All there is left now is AArch64. --- src/arch/aarch64.rs | 10 +--------- src/arch/emulate.rs | 10 +--------- src/arch/mod.rs | 1 - src/arch/riscv64/sv39.rs | 33 +++++++++++++++++++++++++++++---- src/arch/riscv64/sv48.rs | 30 ++++++++++++++++++++++++++---- src/arch/x86_64.rs | 8 -------- 6 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/arch/aarch64.rs b/src/arch/aarch64.rs index 3f5305a5d3..be42f31aab 100644 --- a/src/arch/aarch64.rs +++ b/src/arch/aarch64.rs @@ -86,17 +86,9 @@ impl Arch for AArch64Arch { } fn virt_is_valid(address: VirtualAddress) -> bool { - // TODO + // FIXME true } - fn virt_kind(address: VirtualAddress) -> TableKind { - // TODO: Is this correct? - if address.data() & (1 << 63) == (1 << 63) { - TableKind::Kernel - } else { - TableKind::User - } - } } #[cfg(test)] diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index fade414bc0..a73bb084c8 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -101,16 +101,8 @@ impl Arch for EmulateArch { unsafe fn set_table(address: PhysicalAddress) { MACHINE.as_mut().unwrap().set_table(address); } - fn virt_kind(address: VirtualAddress) -> crate::TableKind { - // TODO - if address.data() & (1 << 63) == (1 << 63) { - crate::TableKind::Kernel - } else { - crate::TableKind::User - } - } fn virt_is_valid(_address: VirtualAddress) -> bool { - // TODO + // TODO: Don't see why an emulated arch would have any problems with canonicalness... true } } diff --git a/src/arch/mod.rs b/src/arch/mod.rs index a24eae36e0..7194e16cec 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -87,5 +87,4 @@ pub trait Arch: Clone + Copy { } fn virt_is_valid(address: VirtualAddress) -> bool; - fn virt_kind(address: VirtualAddress) -> TableKind; } diff --git a/src/arch/riscv64/sv39.rs b/src/arch/riscv64/sv39.rs index ced17ecb0d..7b14130b5b 100644 --- a/src/arch/riscv64/sv39.rs +++ b/src/arch/riscv64/sv39.rs @@ -61,10 +61,10 @@ impl Arch for RiscV64Sv39Arch { } fn virt_is_valid(address: VirtualAddress) -> bool { - todo!() - } - fn virt_kind(address: VirtualAddress) -> TableKind { - todo!() + const MASK: usize = 0xFFFF_FFC0_0000_0000; + let masked = address.data() & MASK; + + masked == MASK || masked == 0 } } @@ -91,4 +91,29 @@ mod tests { assert_eq!(RiscV64Sv39Arch::PHYS_OFFSET, 0xFFFF_FE00_0000_0000); } + #[test] + fn is_canonical() { + use super::VirtualAddress; + + #[track_caller] + fn yes(addr: usize) { + assert!(RiscV64Sv39Arch::virt_is_valid(VirtualAddress::new(addr))); + } + #[track_caller] + fn no(addr: usize) { + assert!(!RiscV64Sv39Arch::virt_is_valid(VirtualAddress::new(addr))); + } + + yes(0xFFFF_FFFF_FFFF_FFFF); + yes(0xFFFF_FFF0_1337_1337); + no(0x0000_0F00_0000_0000); + no(0x1337_0000_0000_0000); + no(1 << 38); + yes(1 << 37); + + // Check for off-by-one errors. + yes(0xFFFF_FFC0_0000_0000 | (1 << 37)); + yes(0xFFFF_FFE0_0000_0000 | (1 << 37)); + no(0xFFFF_FF80_0000_0000 | (1 << 37)); + } } diff --git a/src/arch/riscv64/sv48.rs b/src/arch/riscv64/sv48.rs index f26aeb7216..5e1eff9d59 100644 --- a/src/arch/riscv64/sv48.rs +++ b/src/arch/riscv64/sv48.rs @@ -60,10 +60,12 @@ impl Arch for RiscV64Sv48Arch { asm!("csrw satp, {0}", in(reg) satp); } fn virt_is_valid(address: VirtualAddress) -> bool { - todo!() - } - fn virt_kind(address: VirtualAddress) -> TableKind { - todo!() + // RISC-V SV48 uses 48-bit sign-extended addresses, identical to 4-level paging on x86_64. + let mask = 0xFFFF_8000_0000_0000; + let masked = address.data() & mask; + + masked == mask + || masked == 0 } } @@ -90,4 +92,24 @@ mod tests { assert_eq!(RiscV64Sv48Arch::PHYS_OFFSET, 0xFFFF_FE00_0000_0000); } + #[test] + fn is_canonical() { + use super::VirtualAddress; + + // Close to identical when compared to x86_64 test. + fn yes(address: usize) { + assert!(RiscV64Sv48Arch::virt_is_valid(VirtualAddress::new(address))); + } + fn no(address: usize) { + assert!(!RiscV64Sv48Arch::virt_is_valid(VirtualAddress::new(address))); + } + + yes(0xFFFF_8000_1337_1337); + yes(0xFFFF_FFFF_FFFF_FFFF); + yes(0x0000_0000_0000_0042); + yes(0x0000_7FFF_FFFF_FFFF); + no(0x1337_0000_0000_0000); + no(0x1337_8000_0000_0000); + no(0x0000_8000_0000_0000); + } } diff --git a/src/arch/x86_64.rs b/src/arch/x86_64.rs index ead8013100..da100f7bee 100644 --- a/src/arch/x86_64.rs +++ b/src/arch/x86_64.rs @@ -2,7 +2,6 @@ use crate::{ Arch, MemoryArea, PhysicalAddress, - TableKind, VirtualAddress, }; @@ -55,13 +54,6 @@ impl Arch for X8664Arch { // suceeded. address.is_canonical() } - fn virt_kind(address: VirtualAddress) -> TableKind { - if address.data() & (1 << 48) == (1 << 48) { - TableKind::Kernel - } else { - TableKind::User - } - } } impl VirtualAddress {