Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,7 @@ fn ratchet_globals() -> Result<()> {
("litebox_runner_lvbs/", 5),
("litebox_runner_snp/", 2),
("litebox_shim_linux/", 1),
("litebox_shim_optee/", 5),
("litebox_shim_optee/", 4),
],
|file| {
Ok(file
Expand Down
35 changes: 3 additions & 32 deletions litebox_platform_lvbs/src/arch/x86/mm/paging.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -558,42 +558,13 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va)
}

/// Map physical frame range to the page table using the direct-map offset
/// ([`MemoryProvider::pa_to_va_direct`], i.e., `PA + GVA_OFFSET`).
///
/// Use this for VTL0 / external physical memory that should be accessible
/// through the direct-map region.
pub(crate) fn map_phys_frame_range_direct(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
) -> Result<*mut u8, MapToError<Size4KiB>> {
self.map_phys_frame_range_with(frame_range, flags, exec_ranges, M::pa_to_va_direct)
}

/// Common implementation for [`Self::map_phys_frame_range`] and
/// [`Self::map_phys_frame_range_direct`].
///
/// `pa_to_va` selects how physical addresses are translated to virtual
/// addresses — either via `KERNEL_OFFSET` or `GVA_OFFSET`.
fn map_phys_frame_range_with(
&self,
frame_range: PhysFrameRange<Size4KiB>,
flags: PageTableFlags,
exec_ranges: Option<&[Range<PhysAddr>]>,
pa_to_va: fn(PhysAddr) -> VirtAddr,
) -> Result<*mut u8, MapToError<Size4KiB>> {
let mut allocator = PageTableAllocator::<M>::new();

let mut inner = self.inner.lock();
for target_frame in frame_range {
let page: Page<Size4KiB> =
Page::containing_address(pa_to_va(target_frame.start_address()));
Page::containing_address(M::pa_to_va(target_frame.start_address()));

match inner.translate(page.start_address()) {
TranslateResult::Mapped {
Expand DownExpand Up@@ -655,12 +626,12 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
}

let start_page =
Page::<Size4KiB>::containing_address(pa_to_va(frame_range.start.start_address()));
Page::<Size4KiB>::containing_address(M::pa_to_va(frame_range.start.start_address()));
let count =
(frame_range.end.start_address() - frame_range.start.start_address()) / Size4KiB::SIZE;
flush_tlb_range(start_page, count.trunc());

Ok(pa_to_va(frame_range.start.start_address()).as_mut_ptr())
Ok(M::pa_to_va(frame_range.start.start_address()).as_mut_ptr())
}

/// Map non-contiguous physical frames to virtually contiguous addresses.
Expand Down
166 changes: 61 additions & 105 deletions litebox_platform_lvbs/src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -23,7 +23,7 @@ use litebox::{
};
use litebox_common_linux::errno::Errno;
use litebox_common_linux::vmap::{
GlobalVmapManager, PhysPageAddr, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
GlobalVmapManager, PhysPageAddrArray, PhysPageMapInfo, PhysPageMapPermissions,
PhysPointerError, VmapManager,
};
use x86_64::{
Expand DownExpand Up@@ -94,7 +94,7 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// 0xFFFF_C000_0000_0000 ├─────────────────────────────────┤
// │ Direct map region (64 TiB) │
// │ VA = PA + GVA_OFFSET │
// │ VTL0 memory mapped on demand
// │ Currently unused
// │ │
// │ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ ┄ │
// │ VTL1 PA range = unmapped gap │
Expand All@@ -108,12 +108,13 @@ pub const BASE_PAGE_TABLE_ID: usize = 0;
// │ mmap / TA memory │
// 0x0000_0000_0001_0000 └─────────────────────────────────┘ ← USER_ADDR_MIN
//
// The 64 TiB direct map reservation ensures that any physical address
// up to 64 TiB can be mapped via the simple PA + GVA_OFFSET formula
// without colliding with the vmap region. A 1 TiB guard gap between
// the direct map and the vmap region catches stray accesses.
// VTL1 memory is never mapped in the direct map; it lives exclusively
// in the VTL1 kernel region at KERNEL_OFFSET.
// The 64 TiB direct map region is reserved for possible future use (e.g., device
// drivers, persistent mapping). Foreign physical memory currently uses private
// mappings in the vmap region instead. If direct mapping is restored, physical
// addresses up to 64 TiB can use the PA + GVA_OFFSET formula without colliding
// with vmap. A 1 TiB guard gap catches stray accesses. VTL1 memory must never
// be mapped in the direct map; it lives exclusively in the VTL1 kernel region
// at KERNEL_OFFSET.
//
// The VTL1 kernel region at the top of the address space maps the
// entire VTL1 kernel via PA + KERNEL_OFFSET. A 1 TiB guard gap
Expand DownExpand Up@@ -1106,22 +1107,6 @@ impl<Host: HostInterface> litebox::platform::SystemInfoProvider for LinuxKernel<
}
}

/// Checks whether the given physical addresses are contiguous with respect to ALIGN.
fn is_contiguous<const ALIGN: usize>(addrs: &[PhysPageAddr<ALIGN>]) -> bool {
for window in addrs.windows(2) {
let first = window[0].as_usize();
let second = window[1].as_usize();
if let Some(expected) = first.checked_add(ALIGN) {
if second != expected {
return false;
}
} else {
return false;
}
}
true
}

unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for LinuxKernel<Host> {
type MapInfo = LvbsPhysPageMapInfo;

Expand DownExpand Up@@ -1162,7 +1147,8 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu

// Reject duplicates early as an API-level validation. The page-table implementation also
// rejects duplicate/shared mappings, but this keeps the error local to the input array.
if !is_contiguous(pages) {
// A single page can never collide with itself, so skip the set allocation.
if pages.len() > 1 {
let mut seen = hashbrown::HashSet::with_capacity(pages.len());
for page in pages {
if !seen.insert(page.as_usize()) {
Expand All@@ -1177,79 +1163,54 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
flags |= PageTableFlags::WRITABLE;
}

// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages
// are foreign. Contiguous foreign PA uses the foreign direct-map VA range; non-contiguous
// foreign PA uses the vmap VA range. Neither range aliases VTL1-owned Rust memory.
if is_contiguous(pages) {
let phys_start = x86_64::PhysAddr::new(pages[0].as_usize() as u64);
let phys_end = x86_64::PhysAddr::new(
pages
.last()
.unwrap()
.as_usize()
.checked_add(ALIGN)
.ok_or(PhysPointerError::Overflow)? as u64,
);
let frame_range = PhysFrame::range(
PhysFrame::<Size4KiB>::containing_address(phys_start),
PhysFrame::<Size4KiB>::containing_address(phys_end),
);

match self
.page_table_manager
.current_page_table()
.map_phys_frame_range_direct(frame_range, flags, None)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(MapToError::PageAlreadyMapped(_)) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
// Always allocate a fresh, private virtual address window for the mapping. This lets
// multiple cores map the same physical frame(s) concurrently at distinct VAs (used only for
// transient data copy in/out via raw pointers), so a core unmapping its window never
// disturbs another core's access to the same frame.
//
// `validate_unowned` rejects VTL1-owned PA before callers reach `vmap`, so these pages are
// foreign and the vmap VA range never aliases VTL1-owned Rust memory.
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| {
let address = p.as_usize();
x86_64::PhysAddr::try_new(address as u64)
.map(PhysFrame::containing_address)
.map_err(|_| PhysPointerError::InvalidPhysicalAddress(address))
})
.collect::<Result<_, _>>()?;

let base_va = vmap_allocator()
.allocate_va(frames.len())
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
Err(MapToError::FrameAllocationFailed) => {
Err(PhysPointerError::FrameAllocationFailed)
// `pages` was checked non-empty above and `frames` is built 1:1 from it, so the
// allocator cannot report an empty input here.
crate::mm::vmap::VmapAllocError::EmptyInput => {
unreachable!("frames is derived 1:1 from a non-empty pages slice")
}
Err(MapToError::ParentEntryHugePage) => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
} else {
let frames: alloc::vec::Vec<PhysFrame<Size4KiB>> = pages
.iter()
.map(|p| PhysFrame::containing_address(x86_64::PhysAddr::new(p.as_usize() as u64)))
.collect();

let base_va = vmap_allocator()
.allocate_va_and_register_map(&frames)
.map_err(|e| match e {
crate::mm::vmap::VmapAllocError::EmptyInput => {
PhysPointerError::InvalidPhysicalAddress(0)
}
crate::mm::vmap::VmapAllocError::DuplicateMapping => {
PhysPointerError::AlreadyMapped(pages[0].as_usize())
}
crate::mm::vmap::VmapAllocError::VaSpaceExhausted => {
PhysPointerError::VaSpaceExhausted
}
})?;
})?;

match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
let _ = vmap_allocator().unregister_allocation(base_va);
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
match self
.page_table_manager
.current_page_table()
.map_non_contiguous_phys_frames(&frames, base_va, flags)
{
Ok(page_addr) => Ok(LvbsPhysPageMapInfo::new(page_addr, pages.len() * ALIGN)),
Err(e) => {
vmap_allocator().free_va(base_va, frames.len());
match e {
MapToError::PageAlreadyMapped(_) => {
Err(PhysPointerError::AlreadyMapped(pages[0].as_usize()))
}
MapToError::FrameAllocationFailed => {
Err(PhysPointerError::FrameAllocationFailed)
}
MapToError::ParentEntryHugePage => Err(
PhysPointerError::InvalidPhysicalAddress(pages[0].as_usize()),
),
}
}
}
Expand All@@ -1275,17 +1236,12 @@ unsafe impl<Host: HostInterface, const ALIGN: usize> VmapManager<ALIGN> for Linu
}

// PTEs are already cleared at this point, so the mapping is functionally gone
// and a retry would only re-fail against empty page-table entries. If the VA
// allocator's bookkeeping is inconsistent, surface it via `debug_assert!`. The
// VA region is leaked but cannot be safely recycled.
let unregister_ok = !crate::mm::vmap::is_vmap_address(base_va)
|| crate::mm::vmap::vmap_allocator()
.unregister_allocation(base_va)
.is_some();
debug_assert!(
unregister_ok,
"vmap allocator unregister failed at {base_va:?}",
);
// and a retry would only re-fail against empty page-table entries. Return the VA
// range to the allocator. `vmap_info` is consumed by value and never cloned, so this
// range is freed exactly once.
if crate::mm::vmap::is_vmap_address(base_va) {
crate::mm::vmap::vmap_allocator().free_va(base_va, size / ALIGN);
}

Ok(())
}
Expand Down
22 changes: 0 additions & 22 deletions litebox_platform_lvbs/src/mm/mod.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,28 +40,6 @@ pub trait MemoryProvider {
/// The caller must ensure that the memory range is valid and not used by any others.
unsafe fn mem_fill_pages(start: usize, size: usize);

/// Obtain physical address (PA) of a page given its direct-map VA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn va_to_pa_direct(va: VirtAddr) -> PhysAddr {
PhysAddr::new_truncate(va - Self::GVA_OFFSET)
}

/// Obtain the direct-map virtual address (VA) of a page given its PA.
///
/// The direct map covers all physical memory via `VA = PA + GVA_OFFSET`.
/// Use this for VTL0 / external physical memory.
fn pa_to_va_direct(pa: PhysAddr) -> VirtAddr {
let pa = pa.as_u64() & !Self::PRIVATE_PTE_MASK;
let va = VirtAddr::new_truncate(pa + Self::GVA_OFFSET.as_u64());
assert!(
va.as_u64() < crate::VMAP_START as u64,
"VA {va:#x} is out of range for direct mapping"
);
va
}

/// Obtain physical address (PA) of a page given its kernel VA.
///
/// The VTL1 kernel region maps kernel memory via `VA = PA + KERNEL_OFFSET`.
Expand Down
Loading