Skip to content
Merged
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
4 changes: 2 additions & 2 deletions etc/syscalls_linux_aarch64.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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 |
Expand Down
2 changes: 2 additions & 0 deletions src/arch/arm64/exceptions/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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(
Expand Down
66 changes: 66 additions & 0 deletions src/memory/mincore.rs
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
46 changes: 45 additions & 1 deletion usertest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()
);
}
Expand Down