use alloc::vec;
use ax_errno::{AxError, AxResult};
use ax_memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr};
use ax_runtime::hal::paging::MappingFlags;
use ax_task::current;
use starry_vm::vm_write_slice;
use crate::task::AsThread;
pub fn sys_mincore(addr: usize, length: usize, vec: *mut u8) -> AxResult<isize> {
let start_addr = VirtAddr::from(addr);
if !start_addr.is_aligned(PAGE_SIZE_4K) {
return Err(AxError::InvalidInput);
}
if vec.is_null() {
return Err(AxError::BadAddress);
}
debug!("sys_mincore <= addr: {addr:#x}, length: {length:#x}, vec: {vec:?}");
if length == 0 {
return Ok(0);
}
let page_count = length.div_ceil(PAGE_SIZE_4K);
let mut result = vec![0u8; page_count];
{
let curr = current();
let aspace_arc = curr.as_thread().proc_data.aspace();
let aspace = aspace_arc.lock();
let mut i = 0;
while i < page_count {
let addr = start_addr + i * PAGE_SIZE_4K;
let area = aspace.find_area(addr).ok_or(AxError::NoMemory)?;
if !area.flags().contains(MappingFlags::USER) {
return Err(AxError::NoMemory);
}
let (is_resident, size) = match aspace.page_table().query(addr) {
Ok((_, _, size)) => {
(true, size as _)
}
Err(_) => {
(false, PAGE_SIZE_4K)
}
};
let n = size / PAGE_SIZE_4K;
if is_resident {
let end = (i + n).min(page_count);
result[i..end].fill(1);
}
i += n;
}
}
vm_write_slice(vec, result.as_slice())?;
Ok(0)
}
#[cfg(axtest)]
pub(crate) fn mincore_validation_rules_hold_for_test() -> bool {
use ax_memory_addr::{MemoryAddr, PAGE_SIZE_4K, VirtAddr};
let aligned_addr = VirtAddr::from(0x1000usize);
assert!(aligned_addr.is_aligned(PAGE_SIZE_4K));
let unaligned_addr = VirtAddr::from(0x1001usize);
assert!(!unaligned_addr.is_aligned(PAGE_SIZE_4K));
let zero_addr = VirtAddr::from(0usize);
assert!(zero_addr.is_aligned(PAGE_SIZE_4K));
let length: usize = 4096;
let page_count = length.div_ceil(PAGE_SIZE_4K);
assert!(page_count == 1);
let length: usize = 8192;
let page_count = length.div_ceil(PAGE_SIZE_4K);
assert!(page_count == 2);
let length: usize = 1;
let page_count = length.div_ceil(PAGE_SIZE_4K);
assert!(page_count == 1);
true
}