Switch to a bump allocator for user virtual memory allocations

This commit is contained in:
pjht 2024-09-06 10:46:11 -05:00
parent 07393d8c71
commit d4df5b53ff
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E

View File

@ -32,6 +32,7 @@ pub struct AddressSpace {
pub alloc_force_user: bool,
pub mapper: OffsetPageTable<'static>,
bytes_allocated: AtomicUsize,
bump_base: Page,
}
impl fmt::Debug for AddressSpace {
@ -196,6 +197,7 @@ pub static KERNEL_SPACE: Lazy<ASpaceMutex> = Lazy::new(|| {
}
let mut kernel_space = AddressSpace::new_with_addr(table);
kernel_space.is_kernel = true;
kernel_space.bump_base = KERNEL_PAGE_RANGE.start;
let l4_virt = VirtAddr::from_ptr(ptr::from_ref(kernel_space.mapper.level_4_table()));
#[expect(
clippy::unwrap_used,
@ -251,6 +253,7 @@ impl AddressSpace {
alloc_force_user: false,
is_kernel: false,
bytes_allocated: AtomicUsize::new(0),
bump_base: USER_PAGE_RANGE.start,
}
}
@ -379,6 +382,9 @@ impl AddressSpace {
PhysFrame::from_start_address_unchecked(PhysAddr::new(0x000F_FFFF_FFFF_F000))
};
self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
}
#[expect(
clippy::arithmetic_side_effects,
reason = "This is the maximum physical frame, so there is no way the subtraction can underflow"
@ -455,6 +461,9 @@ impl AddressSpace {
flags: PageTableFlags,
) -> Result<*mut u8, PagingError> {
self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
}
#[expect(
clippy::arithmetic_side_effects,
reason = "check_request_valid guarentees this won't overflow"
@ -544,7 +553,8 @@ impl AddressSpace {
num_pages: usize,
flags: PageTableFlags,
) -> Result<*mut u8, PagingError> {
unsafe { self.map_to(self.find_free_pages(num_pages)?, phys_frame, num_pages, flags) }
let start_page = self.find_free_pages(num_pages)?;
unsafe { self.map_to(start_page, phys_frame, num_pages, flags) }
}
/// Maps new virtual pages to new physical memory and returns the starting address.
@ -555,9 +565,10 @@ impl AddressSpace {
num_pages: usize,
flags: PageTableFlags,
) -> Result<*mut u8, PagingError> {
let start_page = self.find_free_pages(num_pages)?;
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages.
let ptr = unsafe { self.map(self.find_free_pages(num_pages)?, num_pages, flags)? };
let ptr = unsafe { self.map(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr)
}
@ -571,10 +582,10 @@ impl AddressSpace {
num_pages: usize,
flags: PageTableFlags,
) -> Result<(*mut u8, u64), PagingError> {
let start_page = self.find_free_pages(num_pages)?;
// SAFETY: &mut aliasing is prevented by using free physical frames, and uninitialized
// values are prevented by using free virtual pages.
let ptr =
unsafe { self.map_cont_phys(self.find_free_pages(num_pages)?, num_pages, flags)? };
let ptr = unsafe { self.map_cont_phys(start_page, num_pages, flags)? };
self.record_alloc(num_pages * 4096);
Ok(ptr)
}
@ -602,6 +613,9 @@ impl AddressSpace {
flags: PageTableFlags,
) -> Result<*mut u8, PagingError> {
self.check_request_valid(page, num_pages)?;
if self.bump_base < page + u64(num_pages) {
self.bump_base = page + u64(num_pages);
}
assert!(!self.alloc_force_user);
#[expect(
clippy::arithmetic_side_effects,
@ -733,33 +747,41 @@ impl AddressSpace {
}
/// Finds a range of free pages and returns the starting page
fn find_free_pages(&self, num_pages: usize) -> Result<Page, PagingError> {
if num_pages == 0 {
return Err(PagingError::PageAllocationFailed);
}
let mut remaining_pages = num_pages;
let range = if self.is_kernel { KERNEL_PAGE_RANGE } else { USER_PAGE_RANGE };
for page in range {
if self.translate_addr(page.start_address()).is_none() {
#[expect(
clippy::arithmetic_side_effects,
reason = "remaining_pages can never be 0 here, thus this can't underflow"
)]
{
remaining_pages -= 1;
}
if remaining_pages == 0 {
fn find_free_pages(&mut self, num_pages: usize) -> Result<Page, PagingError> {
if self.is_kernel {
if num_pages == 0 {
return Err(PagingError::PageAllocationFailed);
}
let mut remaining_pages = num_pages;
let range = if self.is_kernel { KERNEL_PAGE_RANGE } else { USER_PAGE_RANGE };
for page in range {
if self.translate_addr(page.start_address()).is_none() {
#[expect(
clippy::arithmetic_side_effects,
reason = "page is at minimum num_pages - 1, thus this can't underflow"
reason = "remaining_pages can never be 0 here, thus this can't underflow"
)]
return Ok(page + 1 - u64(num_pages));
}
} else {
remaining_pages = num_pages;
};
{
remaining_pages -= 1;
}
if remaining_pages == 0 {
#[expect(
clippy::arithmetic_side_effects,
reason = "page is at minimum num_pages - 1, thus this can't underflow"
)]
return Ok(page + 1 - u64(num_pages));
}
} else {
remaining_pages = num_pages;
};
}
Err(PagingError::PageAllocationFailed)
} else if USER_PAGE_RANGE.end - self.bump_base < u64(num_pages) {
Err(PagingError::PageAllocationFailed)
} else {
let old_base = self.bump_base;
self.bump_base += u64(num_pages);
Ok(old_base)
}
Err(PagingError::PageAllocationFailed)
}
pub fn record_alloc(&self, size: usize) {