Skip to content
Draft
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: 2 additions & 0 deletions litebox/src/mm/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,4 +1055,6 @@ pub enum PageFaultError {
AllocationFailed,
#[error("given page is part of an already mapped huge page")]
HugePage,
#[error("invalid frame address: {0:#x}")]
InvalidFrameAddress(u64),
}
12 changes: 12 additions & 0 deletions litebox/src/platform/page_mgmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ pub enum DeallocationError {
Unaligned,
#[error("provided range contains unallocated pages")]
AlreadyUnallocated,
#[error("invalid frame address: {0:#x}")]
InvalidFrameAddress(u64),
}

/// Possible errors for [`PageManagementProvider::remap_pages`]
Expand All @@ -251,6 +253,12 @@ pub enum RemapError {
AlreadyAllocated,
#[error("out of memory")]
OutOfMemory,
#[error("operation encountered a huge page")]
HugePage,
#[error("invalid frame address: {0:#x}")]
InvalidFrameAddress(u64),
#[error("failed to restore original mapping after remap failure (frame leaked)")]
RestoreFailed,
}

/// Possible errors for [`PageManagementProvider::update_permissions`]
Expand All @@ -261,6 +269,10 @@ pub enum PermissionUpdateError {
Unaligned,
#[error("provided range contains unallocated pages")]
Unallocated,
#[error("operation encountered a huge page")]
HugePage,
#[error("invalid frame address: {0:#x}")]
InvalidFrameAddress(u64),
}

/// Possible errors for [`PageManagementProvider::try_allocate_cow_pages`]
Expand Down
70 changes: 53 additions & 17 deletions litebox_platform_linux_kernel/src/arch/x86/mm/paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,36 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
Ok((frame, fl)) => {
match unsafe { inner.map_to(new_start, frame, flags, &mut allocator) } {
Ok(_) => {}
Err(e) => match e {
MapToError::PageAlreadyMapped(_) => {
return Err(page_mgmt::RemapError::AlreadyAllocated);
}
MapToError::ParentEntryHugePage => {
todo!("return Err(page_mgmt::RemapError::RemapToHugePage);")
Err(e) => {
// Restore the original mapping so the frame is not leaked.
// Safety: `start` was just unmapped so its PTE slot is free.
if let Ok(restore_flush) =
unsafe { inner.map_to(start, frame, flags, &mut allocator) }
{
if FLUSH_TLB {
restore_flush.flush();
}
} else {
// The frame is now orphaned — we cannot recover it.
debug_assert!(
false,
"remap_pages: failed to restore mapping, frame leaked"
);
return Err(page_mgmt::RemapError::RestoreFailed);
}
MapToError::FrameAllocationFailed => {
return Err(page_mgmt::RemapError::OutOfMemory);
}
},

return match e {
MapToError::PageAlreadyMapped(_) => {
Err(page_mgmt::RemapError::AlreadyAllocated)
}
MapToError::ParentEntryHugePage => {
Err(page_mgmt::RemapError::HugePage)
}
MapToError::FrameAllocationFailed => {
Err(page_mgmt::RemapError::OutOfMemory)
}
};
}
}
if FLUSH_TLB {
fl.flush();
Expand All @@ -194,15 +213,15 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
unreachable!()
}
Err(X64UnmapError::ParentEntryHugePage) => {
todo!("return Err(page_mgmt::RemapError::RemapToHugePage);")
return Err(page_mgmt::RemapError::HugePage);
}
Err(X64UnmapError::InvalidFrameAddress(pa)) => {
panic!("Invalid frame address: {:#x}", pa);
return Err(page_mgmt::RemapError::InvalidFrameAddress(pa.as_u64()));
}
},
TranslateResult::NotMapped => {}
TranslateResult::InvalidFrameAddress(pa) => {
panic!("Invalid frame address: {:#x}", pa);
return Err(page_mgmt::RemapError::InvalidFrameAddress(pa.as_u64()));
}
}
start += 1;
Expand Down Expand Up @@ -234,15 +253,18 @@ impl<M: MemoryProvider, const ALIGN: usize> X64PageTable<'_, M, ALIGN> {
offset: _,
flags,
} => {
// If it is changed to writable, we leave it to page fault handler (COW)
// If write access is requested on a read-only mapping, leave the PTE
// read-only for now and let the write-fault path enable writes lazily.
// Keep this split explicit so a future real COW implementation can hook
// into the same fault path.
let change_to_write = new_flags.contains(PageTableFlags::WRITABLE)
&& !flags.contains(PageTableFlags::WRITABLE);
let new_flags = if change_to_write {
new_flags - PageTableFlags::WRITABLE
} else {
new_flags
};
if flags != new_flags {
if flags & Self::MPROTECT_PTE_MASK != new_flags {
match unsafe {
inner.update_flags(page, (flags & !Self::MPROTECT_PTE_MASK) | new_flags)
} {
Expand Down Expand Up @@ -308,8 +330,22 @@ impl<M: MemoryProvider, const ALIGN: usize> PageTableImpl<ALIGN> for X64PageTabl
// probably set by other threads concurrently
return Ok(());
} else {
// Copy-on-Write
todo!("COW");
// This is the deferred write-enable path used by mprotect today, not a
// real COW implementation. Keep the write-fault handling separate so a
// future COW path can replace this flag update.
match unsafe { inner.update_flags(page, flags | PageTableFlags::WRITABLE) }
{
Ok(flush) => {
if FLUSH_TLB {
flush.flush();
}
return Ok(());
}
Err(FlagUpdateError::PageNotMapped) => unreachable!(),
Err(FlagUpdateError::ParentEntryHugePage) => {
return Err(PageFaultError::HugePage);
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_linux_kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ impl<Host: HostInterface, const ALIGN: usize> PageManagementProvider<ALIGN> for
.ok_or(litebox::platform::page_mgmt::RemapError::Unaligned)?;
let new_range = PageRange::new(new_range.start, new_range.end)
.ok_or(litebox::platform::page_mgmt::RemapError::Unaligned)?;
if old_range.start.max(new_range.start) <= old_range.end.min(new_range.end) {
if old_range.start.max(new_range.start) < old_range.end.min(new_range.end) {
return Err(litebox::platform::page_mgmt::RemapError::Overlapping);
}
unsafe { self.page_table.remap_pages(old_range, new_range) }
Expand Down
Loading
Loading