feat(core): implement RAII virtual memory mapper with page alignment

This commit is contained in:
katR 2026-09-29 17:04:02 +05:30
parent 2d0cf8c478
commit 4d245aa59f
3 changed files with 103 additions and 0 deletions

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pub mod elf;
pub mod mmap;
pub mod symbols;

View file

@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::ptr;
pub const PAGE_SIZE: usize = 4096;
pub struct MappedImage {
base: *mut u8,
size: usize,
}
impl MappedImage {
pub const fn page_align_down(addr: usize) -> usize {
addr & !(PAGE_SIZE - 1)
}
pub const fn page_align_up(addr: usize) -> usize {
(addr + PAGE_SIZE - 1) & !(PAGE_SIZE - 1)
}
pub fn allocate_anonymous(size: usize) -> Result<Self, String> {
let aligned_size = Self::page_align_up(size);
let ptr = unsafe {
libc::mmap(
ptr::null_mut(),
aligned_size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
)
};
if ptr == libc::MAP_FAILED {
Err("mmap failed to allocate anonymous memory".to_string())
} else {
Ok(Self {
base: ptr as *mut u8,
size: aligned_size,
})
}
}
pub fn base_addr(&self) -> *mut u8 {
self.base
}
pub fn size(&self) -> usize {
self.size
}
pub fn protect(&self, offset: usize, len: usize, prot: i32) -> Result<(), String> {
let page_start = Self::page_align_down(offset);
let page_end = Self::page_align_up(offset + len);
let aligned_len = page_end - page_start;
let ret = unsafe {
libc::mprotect(
self.base.add(page_start) as *mut libc::c_void,
aligned_len,
prot,
)
};
if ret == 0 {
Ok(())
} else {
Err(format!("mprotect failed with errno {}", std::io::Error::last_os_error()))
}
}
}
impl Drop for MappedImage {
fn drop(&mut self) {
if !self.base.is_null() {
unsafe {
libc::munmap(self.base as *mut libc::c_void, self.size);
}
}
}
}
unsafe impl Send for MappedImage {}
unsafe impl Sync for MappedImage {}

View file

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use molotov_core::mmap::MappedImage;
#[test]
fn test_page_alignment_helper() {
assert_eq!(MappedImage::page_align_down(4096), 4096);
assert_eq!(MappedImage::page_align_down(4097), 4096);
assert_eq!(MappedImage::page_align_up(4095), 4096);
assert_eq!(MappedImage::page_align_up(4096), 4096);
assert_eq!(MappedImage::page_align_up(4097), 8192);
}
#[test]
fn test_mmap_reservation_and_drop() {
let mapping = MappedImage::allocate_anonymous(65536).expect("Should mmap virtual address space");
assert!(!mapping.base_addr().is_null());
assert_eq!(mapping.size(), 65536);
// Dropping mapping unmaps memory automatically via RAII
}