implement mincore

This commit is contained in:
Ashwin Naren
2026-01-14 22:17:54 -08:00
parent 76d4d0023f
commit aca5c0db79
5 changed files with 116 additions and 3 deletions

View File

@@ -98,7 +98,7 @@
| 0x5f (95) | waitid | (int which, pid_t upid, struct siginfo *infop, int options, struct rusage *ru) | __arm64_sys_waitid | false |
| 0x60 (96) | set_tid_address | (int *tidptr) | __arm64_sys_set_tid_address | dummy |
| 0x61 (97) | unshare | (unsigned long unshare_flags) | __arm64_sys_unshare | false |
| 0x62 (98) | futex | (u32 *uaddr, int op, u32 val, const struct __kernel_timespec *utime, u32 *uaddr2, u32 val3) | __arm64_sys_futex | false |
| 0x62 (98) | futex | (u32 *uaddr, int op, u32 val, const struct __kernel_timespec *utime, u32 *uaddr2, u32 val3) | __arm64_sys_futex | true |
| 0x63 (99) | set_robust_list | (struct robust_list_head *head, size_t len) | __arm64_sys_set_robust_list | true |
| 0x64 (100) | get_robust_list | (int pid, struct robust_list_head **head_ptr, size_t *len_ptr) | __arm64_sys_get_robust_list | false |
| 0x65 (101) | nanosleep | (struct __kernel_timespec *rqtp, struct __kernel_timespec *rmtp) | __arm64_sys_nanosleep | true |
@@ -232,7 +232,7 @@
| 0xe5 (229) | munlock | (unsigned long start, size_t len) | __arm64_sys_munlock | false |
| 0xe6 (230) | mlockall | (int flags) | __arm64_sys_mlockall | false |
| 0xe7 (231) | munlockall | () | __arm64_sys_munlockall | false |
| 0xe8 (232) | mincore | (unsigned long start, size_t len, unsigned char *vec) | __arm64_sys_mincore | false |
| 0xe8 (232) | mincore | (unsigned long start, size_t len, unsigned char *vec) | __arm64_sys_mincore | true |
| 0xe9 (233) | madvise | (unsigned long start, size_t len_in, int behavior) | __arm64_sys_madvise | noop |
| 0xea (234) | remap_file_pages | (unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long flags) | __arm64_sys_remap_file_pages | false |
| 0xeb (235) | mbind | (unsigned long start, unsigned long len, unsigned long mode, const unsigned long *nmask, unsigned long maxnode, unsigned int flags) | __arm64_sys_mbind | false |

View File

@@ -45,6 +45,7 @@ use crate::{
kernel::{power::sys_reboot, rand::sys_getrandom, sysinfo::sys_sysinfo, uname::sys_uname},
memory::{
brk::sys_brk,
mincore::sys_mincore,
mmap::{sys_mmap, sys_mprotect, sys_munmap},
process_vm::sys_process_vm_readv,
},
@@ -511,6 +512,7 @@ pub async fn handle_syscall() {
0xde => sys_mmap(arg1, arg2, arg3, arg4, arg5.into(), arg6).await,
0xdf => Ok(0), // fadvise64_64 is a no-op
0xe2 => sys_mprotect(VA::from_value(arg1 as _), arg2 as _, arg3 as _),
0xe8 => sys_mincore(arg1, arg2 as _, TUA::from_value(arg3 as _)).await,
0xe9 => Ok(0), // sys_madvise is a no-op
0x104 => {
sys_wait4(

66
src/memory/mincore.rs Normal file
View File

@@ -0,0 +1,66 @@
use alloc::vec;
use alloc::vec::Vec;
use crate::memory::uaccess::copy_to_user_slice;
use crate::sched::current::current_task;
use libkernel::memory::region::VirtMemoryRegion;
use libkernel::{
UserAddressSpace,
error::{KernelError, Result},
memory::PAGE_SHIFT,
memory::address::{UA, VA},
};
pub async fn sys_mincore(start: u64, len: usize, vec: UA) -> Result<usize> {
// addr must be a multiple of the system page size
// len must be > 0
let start_va = VA::from_value(start as usize);
if !start_va.is_page_aligned() {
return Err(KernelError::InvalidValue);
}
if len == 0 {
return Err(KernelError::InvalidValue);
}
let region = VirtMemoryRegion::new(start_va, len)
.to_mappable_region()
.region();
if region.size() == 0 {
return Err(KernelError::InvalidValue);
}
// Vector length must be number of pages covering the region
let pages = region.size() >> PAGE_SHIFT;
let mut buf: Vec<u8> = vec![0; pages];
{
let task = current_task();
let mut vm_guard = task.vm.lock_save_irq();
let mm = vm_guard.mm_mut();
// Validate the entire region is covered by VMAs
for va in region.iter_pages() {
if mm.find_vma(va).is_none() {
return Err(KernelError::NoMemory);
}
}
let as_ref = mm.address_space_mut();
for (i, va) in region.iter_pages().enumerate() {
let resident = as_ref.translate(va).is_some();
if resident {
buf[i] |= 1;
} else {
buf[i] &= !1;
}
}
}
copy_to_user_slice(&buf, vec)
.await
.map_err(|_| KernelError::Fault)?;
Ok(0)
}

View File

@@ -10,6 +10,7 @@ use libkernel::memory::{
pub mod brk;
pub mod fault;
pub mod mincore;
pub mod mmap;
pub mod page;
pub mod process_vm;

View File

@@ -151,6 +151,50 @@ fn test_thread_with_name() {
register_test!(test_thread_with_name, "Testing thread with name");
fn test_mincore() {
use std::ptr;
unsafe {
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as usize;
assert!(page_size > 0);
// Map exactly one page, read-write, anonymous private
let addr = libc::mmap(
ptr::null_mut(),
page_size,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
-1,
0,
);
if addr == libc::MAP_FAILED {
panic!("mmap failed: {}", std::io::Error::last_os_error());
}
// Touch the page to fault it in
ptr::write(addr as *mut u8, 42);
let mut vec_byte: u8 = 0;
let ret = libc::mincore(addr as *mut _, page_size, &mut vec_byte as *mut u8);
if ret != 0 {
let err = std::io::Error::last_os_error();
panic!("mincore failed: {}", err);
}
// LSB set indicates resident
assert!(
vec_byte & 0x1 == 0x1,
"Expected page to be resident, vec={:02x}",
vec_byte
);
// Cleanup
let rc = libc::munmap(addr, page_size);
assert_eq!(rc, 0, "munmap failed: {}", std::io::Error::last_os_error());
}
}
register_test!(test_mincore, "Testing mincore syscall");
fn run_test(test_fn: fn()) {
// Fork a new process to run the test
unsafe {
@@ -167,7 +211,7 @@ fn run_test(test_fn: fn()) {
libc::waitpid(pid, &mut status, 0);
if !libc::WIFEXITED(status) || libc::WEXITSTATUS(status) != 0 {
panic!(
"Test failed in child process: {}",
"Test failed in child process: {} (this might be incorrect)",
std::io::Error::last_os_error()
);
}