From b8d644c942896555e7df179109c2a2f5118585d3 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 4 Aug 2025 21:32:25 +0900 Subject: [PATCH 1/3] [add] add `split_memory_maps` --- hikami_core/src/memmap/page_table/sv39x4.rs | 75 ++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/hikami_core/src/memmap/page_table/sv39x4.rs b/hikami_core/src/memmap/page_table/sv39x4.rs index 2e44a86..45292b6 100644 --- a/hikami_core/src/memmap/page_table/sv39x4.rs +++ b/hikami_core/src/memmap/page_table/sv39x4.rs @@ -11,6 +11,7 @@ use crate::h_extension::csrs::hgatp; use crate::memmap::{GuestPhysicalAddress, HostPhysicalAddress, MemoryMap}; use alloc::boxed::Box; +use alloc::vec::Vec; use core::slice::from_raw_parts_mut; /// First page table size @@ -72,6 +73,75 @@ pub fn initialize_page_table(root_table_start_addr: HostPhysicalAddress) { first_lv_page_table.fill(PageTableEntry(0)); } +/// Splits a single MemoryMap into multiple MemoryMaps to satisfy superpage alignment requirements. +/// +/// This function takes a slice of MemoryMaps and returns a new Vec of MemoryMaps +/// where each one is properly aligned for the largest possible page size. +/// For example, a single large, unaligned region will be broken down into: +/// 1. A section mapped with 4KB pages to reach the first 2MB alignment boundary. +/// 2. A central section mapped with 2MB pages (or 1GB pages if possible). +/// 3. A final section mapped with 4KB pages for the remaining part. +fn split_memory_maps(memmaps: &[MemoryMap]) -> Vec { + let mut split_maps = Vec::new(); + + for memmap in memmaps { + let mut current_virt = memmap.virt.start; + let mut current_phys = memmap.phys.start; + + while current_virt < memmap.virt.end { + let remaining_len = memmap.virt.end.raw() - current_virt.raw(); + + // Determine the largest possible page size for the current address + let (page_level, page_size) = if remaining_len >= PageTableLevel::Lv1GB.size() + && current_virt % PageTableLevel::Lv1GB.size() == 0 + && current_phys % PageTableLevel::Lv1GB.size() == 0 + { + (PageTableLevel::Lv1GB, PageTableLevel::Lv1GB.size()) + } else if remaining_len >= PageTableLevel::Lv2MB.size() + && current_virt % PageTableLevel::Lv2MB.size() == 0 + && current_phys % PageTableLevel::Lv2MB.size() == 0 + { + (PageTableLevel::Lv2MB, PageTableLevel::Lv2MB.size()) + } else { + (PageTableLevel::Lv4KB, PageTableLevel::Lv4KB.size()) + }; + + // Calculate the next alignment boundary for the chosen page size + let next_align_boundary = (current_virt.raw() + page_size) & !(page_size - 1); + + // Determine the size of the current chunk to map + let chunk_end_virt = + core::cmp::min(memmap.virt.end, GuestPhysicalAddress(next_align_boundary)); + let chunk_size = chunk_end_virt.raw() - current_virt.raw(); + + let map_size = if page_level != PageTableLevel::Lv4KB { + // For superpages, find the largest aligned chunk possible + let end_of_aligned_chunk = memmap.virt.end.raw() & !(page_size - 1); + if current_virt.raw() < end_of_aligned_chunk { + end_of_aligned_chunk - current_virt.raw() + } else { + page_size + } + } else { + // For 4KB pages, just align to the next superpage boundary + chunk_size + }; + + let final_chunk_size = core::cmp::min(map_size, remaining_len); + + split_maps.push(MemoryMap::new( + current_virt..current_virt + final_chunk_size, + current_phys..current_phys + final_chunk_size, + &memmap.flags_as_array(), + )); + + current_virt = current_virt + final_chunk_size; + current_phys = current_phys + final_chunk_size; + } + } + split_maps +} + /// Generate third-level page table. (Sv39x4) /// /// The number of address translation stages is determined by the size of the range. @@ -91,7 +161,10 @@ pub fn generate_page_table(root_table_start_addr: HostPhysicalAddress, memmaps: ) }; - for memmap in memmaps { + // Split memory maps to ensure proper alignment for superpages. + let aligned_memmaps = split_memory_maps(memmaps); + + for memmap in &aligned_memmaps { assert!(memmap.virt.len() == memmap.phys.len()); // decide page level from memory range From fc1f2ddf45c0406bfa10a1e35ff704a6a1f55dad Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 4 Aug 2025 21:33:32 +0900 Subject: [PATCH 2/3] [add] add `MemoryMap::flags` --- hikami_core/src/memmap.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hikami_core/src/memmap.rs b/hikami_core/src/memmap.rs index a8e5ec9..9c0dd1b 100644 --- a/hikami_core/src/memmap.rs +++ b/hikami_core/src/memmap.rs @@ -121,6 +121,10 @@ impl MemoryMap { flags: flags.iter().fold(0, |pte_f, f| (pte_f | *f as u8)), } } + /// Return flags as raw u8. + pub fn flags(&self) -> u8 { + self.flags + } } impl From for MemoryMap { From cee034f63cddd9521745301ff87af61328926430 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 4 Aug 2025 21:33:58 +0900 Subject: [PATCH 3/3] [add] add `MemoryMap::flags_as_array` --- hikami_core/src/memmap.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hikami_core/src/memmap.rs b/hikami_core/src/memmap.rs index 9c0dd1b..218277a 100644 --- a/hikami_core/src/memmap.rs +++ b/hikami_core/src/memmap.rs @@ -4,6 +4,8 @@ pub mod constant; pub mod page_table; use crate::memmap::page_table::PteFlag; + +use alloc::vec::Vec; use core::ops::Range; /// Utility for `Range
` @@ -125,6 +127,36 @@ impl MemoryMap { pub fn flags(&self) -> u8 { self.flags } + + /// Return flags as an array of PteFlag. + pub fn flags_as_array(&self) -> Vec { + let mut result = Vec::new(); + if self.flags & PteFlag::Valid as u8 != 0 { + result.push(PteFlag::Valid); + } + if self.flags & PteFlag::Read as u8 != 0 { + result.push(PteFlag::Read); + } + if self.flags & PteFlag::Write as u8 != 0 { + result.push(PteFlag::Write); + } + if self.flags & PteFlag::Exec as u8 != 0 { + result.push(PteFlag::Exec); + } + if self.flags & PteFlag::User as u8 != 0 { + result.push(PteFlag::User); + } + if self.flags & PteFlag::Global as u8 != 0 { + result.push(PteFlag::Global); + } + if self.flags & PteFlag::Accessed as u8 != 0 { + result.push(PteFlag::Accessed); + } + if self.flags & PteFlag::Dirty as u8 != 0 { + result.push(PteFlag::Dirty); + } + result + } } impl From for MemoryMap {