diff --git a/Cargo.lock b/Cargo.lock index 2a223db8..74bce957 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,13 +48,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -65,7 +65,7 @@ checksum = "99e1aca718ea7b89985790c94aad72d77533063fe00bc497bb79a7c2dae6a661" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -220,7 +220,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -266,7 +266,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -374,7 +374,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -574,7 +574,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -638,7 +638,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -720,7 +720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.117", ] [[package]] @@ -742,7 +742,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -870,7 +870,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -955,6 +955,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -972,7 +983,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1037,7 +1048,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1198,7 +1209,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -1214,7 +1225,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -1273,7 +1284,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] diff --git a/libkernel/src/arch/x86_64/memory/pg_walk.rs b/libkernel/src/arch/x86_64/memory/pg_walk.rs index f28598ff..db730849 100644 --- a/libkernel/src/arch/x86_64/memory/pg_walk.rs +++ b/libkernel/src/arch/x86_64/memory/pg_walk.rs @@ -4,14 +4,14 @@ use crate::{ error::{MapError, Result}, memory::{ PAGE_SIZE, - address::{PA, TPA, VA}, + address::{Address, TPA, VA}, paging::{ NullTlbInvalidator, PaMapper, PageTableEntry, PageTableMapper, PgTable, PgTableArray, TableMapper, permissions::PtePermissions, - walk::{RecursiveWalker, Translator, WalkContext}, + walk::{RecursiveWalker, Translatable, Translator, WalkContext}, }, - region::{PhysMemoryRegion, VirtMemoryRegion}, + region::{MemoryRegion, VirtMemoryRegion}, }, }; @@ -115,17 +115,21 @@ pub fn get_pte( } impl Translator for PML4Table { - fn translate( - table_pa: TPA>, - va: VA, + fn translate>( + table_pa: Address>, + va: Address, ctx: &mut WalkContext, - ) -> Result> { + ) -> crate::error::Result, usize, PtePermissions)>> { let desc = unsafe { - ctx.mapper - .with_page_table(table_pa, |pgtable| Self::from_ptr(pgtable).get_desc(va))? + ctx.mapper.with_page_table(table_pa, |pgtable| { + Self::from_ptr(pgtable).get_desc(VA::from_value(va.value())) + })? }; match desc.next_table_address() { - Some(next_pa) => PDPTable::translate(next_pa, va, ctx), + Some(next_pa) => { + let next_pa = Address::from_value(next_pa.value()); + PDPTable::translate(next_pa, va, ctx) + } None if desc.is_valid() => Err(MapError::InvalidDescriptor.into()), None => Ok(None), } @@ -133,19 +137,20 @@ impl Translator for PML4Table { } impl Translator for PTable { - fn translate( - table_pa: TPA>, - va: VA, + fn translate>( + table_pa: Address>, + va: Address, ctx: &mut WalkContext, - ) -> Result> { + ) -> crate::error::Result, usize, PtePermissions)>> { let desc = unsafe { - ctx.mapper - .with_page_table(table_pa, |pgtable| Self::from_ptr(pgtable).get_desc(va))? + ctx.mapper.with_page_table(table_pa, |pgtable| { + Self::from_ptr(pgtable).get_desc(VA::from_value(va.value())) + })? }; match desc.mapped_address() { Some(pa) => Ok(Some(( - pa, + Address::from_value(pa.value()), 1 << Self::Descriptor::MAP_SHIFT, desc.permissions(), ))), @@ -155,12 +160,17 @@ impl Translator for PTable { } } +/// Result of a translation, returning the region which is mapped (could be +/// longer than [PAGE_SIZE] for block mappings), the offset of the virtual +/// address into the region and the permissions of the mapping. +pub type TranslationResult = (MemoryRegion, usize, PtePermissions); + /// Translates the VA into a physical region plus an offset and permissions. -pub fn translate( - pml4_table: TPA>, - va: VA, +pub fn translate>( + pml4_table: Address>, + va: Address, mapper: &mut PM, -) -> Result> { +) -> Result>> { let mut walk_ctx = WalkContext { mapper, // Safe to not invalidate the TLB, as we are not modifying any PTEs. @@ -172,7 +182,9 @@ pub fn translate( let offset = va.value() & (blk_sz - 1); - Ok(Some((PhysMemoryRegion::new(pa, blk_sz), offset, perms))) + let rgn = MemoryRegion::new(pa, blk_sz); + + Ok(Some((rgn, offset, perms))) } else { Ok(None) } diff --git a/libkernel/src/memory/address.rs b/libkernel/src/memory/address.rs index 8c86836d..ccc488da 100644 --- a/libkernel/src/memory/address.rs +++ b/libkernel/src/memory/address.rs @@ -57,6 +57,10 @@ pub struct Virtual; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Physical; +/// Marker for a virtual guest memory address type. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct GuestVirtual; + /// Marker for a physical guest memory address type. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct GuestPhysical; @@ -67,11 +71,13 @@ pub struct User; impl sealed::Sealed for Virtual {} impl sealed::Sealed for Physical {} +impl sealed::Sealed for GuestVirtual {} impl sealed::Sealed for GuestPhysical {} impl sealed::Sealed for User {} impl MemKind for Virtual {} impl MemKind for Physical {} +impl MemKind for GuestVirtual {} impl MemKind for GuestPhysical {} impl MemKind for User {} @@ -197,6 +203,8 @@ pub type TVA = Address; pub type TUA = Address; /// A typed guest physical address. pub type TGPA = Address; +/// A typed guest virtual address. +pub type TGVA = Address; /// A typed host physical address. pub type THPA = TPA; @@ -208,6 +216,8 @@ pub type VA = Address; pub type UA = Address; /// An untyped guest physical address. pub type GPA = Address; +/// An untyped guest virtual address. +pub type GVA = Address; /// An untyped host physical address. pub type HPA = PA; @@ -239,6 +249,20 @@ impl TPA { } } +impl TGPA { + /// Convert to an untyped guest physical address. + pub fn to_untyped(self) -> GPA { + GPA::from_value(self.value()) + } +} + +impl TGVA { + /// Convert to an untyped guest virtual address. + pub fn to_untyped(self) -> GVA { + GVA::from_value(self.value()) + } +} + impl Display for TPA { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Px{:08x}", self.inner) diff --git a/libkernel/src/memory/paging/mod.rs b/libkernel/src/memory/paging/mod.rs index 0e4093e1..49f08e28 100644 --- a/libkernel/src/memory/paging/mod.rs +++ b/libkernel/src/memory/paging/mod.rs @@ -2,7 +2,7 @@ use super::{ PAGE_SIZE, - address::{PA, TPA, TVA, VA}, + address::{Address, MemKind, PA, Physical, TPA, TVA, VA}, region::PhysMemoryRegion, }; use core::marker::PhantomData; @@ -159,7 +159,7 @@ impl Default for PgTableArray { } /// Trait for temporarily mapping and modifying a page table located at a -/// physical address. +/// (guest/host) physical address. /// /// During early boot, there are multiple mechanisms for accessing page table memory: /// - Identity mapping (idmap): active very early when VA = PA @@ -175,7 +175,7 @@ impl Default for PgTableArray { /// This function is `unsafe` because the caller must ensure: /// - The given physical address `pa` is valid and correctly aligned for type `T`. /// - The contents at that physical address represent a valid page table of type `T`. -pub trait PageTableMapper { +pub trait PageTableMapper { /// Map a physical address to a usable reference of the page table, run the /// closure, and unmap. /// @@ -185,7 +185,7 @@ pub trait PageTableMapper { /// - The contents at that physical address represent a valid page table of type `T`. unsafe fn with_page_table( &mut self, - pa: TPA>, + pa: Address>, f: impl FnOnce(TVA>) -> R, ) -> crate::error::Result; } diff --git a/libkernel/src/memory/paging/walk.rs b/libkernel/src/memory/paging/walk.rs index 34b88539..62d21038 100644 --- a/libkernel/src/memory/paging/walk.rs +++ b/libkernel/src/memory/paging/walk.rs @@ -3,7 +3,7 @@ use crate::{ error::MapError, memory::{ - address::{PA, TPA, VA}, + address::{Address, GuestPhysical, GuestVirtual, MemKind, Physical, TPA, VA, Virtual}, region::VirtMemoryRegion, }, }; @@ -13,11 +13,22 @@ use super::{ TableMapperTable, permissions::PtePermissions, }; +/// A virtual address kind that can be translated through page tables. +pub trait Translatable: MemKind { + /// The physical-side kind this translates into. + type Phys: MemKind; +} + +impl Translatable for Virtual { + type Phys = Physical; +} + +impl Translatable for GuestVirtual { + type Phys = GuestPhysical; +} + /// A collection of context required to modify page tables. -pub struct WalkContext<'a, PM> -where - PM: PageTableMapper + 'a, -{ +pub struct WalkContext<'a, PM> { /// The mapper used to temporarily access page tables by physical address. pub mapper: &'a mut PM, /// The TLB invalidator invoked after modifying page table entries. @@ -97,12 +108,14 @@ where } } +pub(crate) type TranslatorResult

= (Address, usize, PtePermissions); + pub(crate) trait Translator: PgTable + Sized { - fn translate( - table_pa: TPA>, - va: VA, + fn translate>( + table_pa: Address>, + va: Address, ctx: &mut WalkContext, - ) -> crate::error::Result>; + ) -> crate::error::Result>>; } impl Translator for T @@ -111,21 +124,32 @@ where T::Descriptor: PaMapper, ::NextLevel: Translator, { - fn translate( - table_pa: TPA>, - va: VA, + fn translate>( + table_pa: Address>, + va: Address, ctx: &mut WalkContext, - ) -> crate::error::Result> { + ) -> crate::error::Result, usize, PtePermissions)>> { let desc = unsafe { - ctx.mapper - .with_page_table(table_pa, |pgtable| T::from_ptr(pgtable).get_desc(va))? + ctx.mapper.with_page_table(table_pa, |pgtable| { + // Re-tag to a normal VA here. This is safe since `get_desc()` + // simply calculates the index into the table and returns the + // descriptor at that point. Given we've already forced pgtable + // to be a TVA, access to the table should be sound. + T::from_ptr(pgtable).get_desc(VA::from_value(va.value())) + })? }; if let Some(next_pa) = desc.next_table_address() { + // next_table_address() returns a hard-coded PA-type pointer. Recast + // this to the `M::Phys` address-space for the next-level lookup. + let next_pa = Address::from_value(next_pa.value()); ::NextLevel::translate(next_pa, va, ctx) } else if let Some(block_pa) = desc.mapped_address() { + // mapped_address() returns a hard-coded PA-type pointer. Recast + // this to the `M::Phys` address-space for final translation result. + let pa = Address::from_value(block_pa.value()); let block_size = 1usize << T::Descriptor::MAP_SHIFT; - Ok(Some((block_pa, block_size, desc.permissions().unwrap()))) + Ok(Some((pa, block_size, desc.permissions().unwrap()))) } else if desc.is_valid() { Err(MapError::InvalidDescriptor)? } else { diff --git a/libkernel/src/memory/region.rs b/libkernel/src/memory/region.rs index b2ddc86c..9ef666ca 100644 --- a/libkernel/src/memory/region.rs +++ b/libkernel/src/memory/region.rs @@ -31,7 +31,9 @@ use super::{ PAGE_SHIFT, PAGE_SIZE, - address::{Address, AddressTranslator, GuestPhysical, MemKind, Physical, User, Virtual}, + address::{ + Address, AddressTranslator, GuestPhysical, GuestVirtual, MemKind, Physical, User, Virtual, + }, page::PageFrame, }; @@ -442,6 +444,9 @@ pub type UserMemoryRegion = MemoryRegion; /// A memory region of guest-physical memory. pub type GuestPhysMemoryRegion = MemoryRegion; +/// A memory region of guest-virutal memory. +pub type GuestVirtualMemoryRegion = MemoryRegion; + /// A representation of a `MemoryRegion` that has been expanded to be page-aligned. /// /// This struct holds the new, larger, page-aligned region, as well as the diff --git a/src/arch/arm64/boot/linker.ld b/src/arch/arm64/boot/linker.ld index 3fe1aa23..6b92f39b 100644 --- a/src/arch/arm64/boot/linker.ld +++ b/src/arch/arm64/boot/linker.ld @@ -25,6 +25,7 @@ SECTIONS .data : { *(.data*) } .rodata : { *(.rodata*) + . = ALIGN(8); __driver_inits_start = .; *(.driver_inits*) __driver_inits_end = .; diff --git a/usertest/src/main.rs b/usertest/src/main.rs index e9fb6fe7..1c4b02e3 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -222,8 +222,9 @@ fn test_mincore() { panic!("mmap failed: {}", std::io::Error::last_os_error()); } - // Touch the page to fault it in - ptr::write(addr as *mut u8, 42); + // Touch the page to fault it in. Use a volatile write so the + // compiler can't elide the store. + ptr::write_volatile(addr as *mut u8, 42); let mut vec_byte: u8 = 0; let ret = libc::mincore(addr as *mut _, page_size, &mut vec_byte as *mut u8); diff --git a/usertest/src/signals.rs b/usertest/src/signals.rs index 09dc8b68..b51920ff 100644 --- a/usertest/src/signals.rs +++ b/usertest/src/signals.rs @@ -181,12 +181,13 @@ fn segfault_child(inner: impl FnOnce()) { fn test_segfault_read() { segfault_child(|| { let addr: *const u8 = std::hint::black_box(std::ptr::null()); - let _ = unsafe { std::ptr::read(addr) }; + // Use a volatile read so the compiler can't elide the (dead) load. + let _ = std::hint::black_box(unsafe { std::ptr::read_volatile(addr) }); }); segfault_child(|| { // Ensure reading from kernel stack fails - let addr = 0xffff_ba00_0000_0000 as *const u8; - let _ = unsafe { std::ptr::read(addr) }; + let addr = std::hint::black_box(0xffff_ba00_0000_0000 as *const u8); + let _ = std::hint::black_box(unsafe { std::ptr::read_volatile(addr) }); }); } @@ -195,11 +196,12 @@ register_test!(test_segfault_read); fn test_segfault_write() { segfault_child(|| { let addr: *mut u8 = std::hint::black_box(std::ptr::null_mut()); - unsafe { std::ptr::write(addr, 42) }; + // Use a volatile write so the compiler can't elide the UB store. + unsafe { std::ptr::write_volatile(addr, 42) }; }); segfault_child(|| { - let addr = 0xffff_ba00_0000_0000 as *mut u8; - unsafe { std::ptr::write(addr, 42) }; + let addr = std::hint::black_box(0xffff_ba00_0000_0000 as *mut u8); + unsafe { std::ptr::write_volatile(addr, 42) }; }); }