feat(core): implement RAII virtual memory mapper with page alignment
This commit is contained in:
parent
2d0cf8c478
commit
4d245aa59f
3 changed files with 103 additions and 0 deletions
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
pub mod elf;
|
||||
pub mod mmap;
|
||||
pub mod symbols;
|
||||
|
|
|
|||
83
crates/molotov-core/src/mmap.rs
Normal file
83
crates/molotov-core/src/mmap.rs
Normal 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 {}
|
||||
19
crates/molotov-core/tests/mmap_test.rs
Normal file
19
crates/molotov-core/tests/mmap_test.rs
Normal 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
|
||||
}
|
||||
Reference in a new issue