use axerrno::LinuxError;
use axhal::paging::MappingFlags;
use axtask::{current, TaskExtRef};
use memory_addr::{VirtAddr, VirtAddrRange};
use crate::syscall_body;
bitflags::bitflags! {
#[derive(Debug)]
struct MmapProt: i32 {
const PROT_READ = 1 << 0;
const PROT_WRITE = 1 << 1;
const PROT_EXEC = 1 << 2;
}
}
impl From<MmapProt> for MappingFlags {
fn from(value: MmapProt) -> Self {
let mut flags = MappingFlags::USER;
if value.contains(MmapProt::PROT_READ) {
flags |= MappingFlags::READ;
}
if value.contains(MmapProt::PROT_WRITE) {
flags |= MappingFlags::WRITE;
}
if value.contains(MmapProt::PROT_EXEC) {
flags |= MappingFlags::EXECUTE;
}
flags
}
}
bitflags::bitflags! {
#[derive(Debug)]
struct MmapFlags: i32 {
const MAP_SHARED = 1 << 0;
const MAP_PRIVATE = 1 << 1;
const MAP_FIXED = 1 << 4;
const MAP_ANONYMOUS = 1 << 5;
const MAP_NORESERVE = 1 << 14;
const MAP_STACK = 0x20000;
}
}
pub(crate) fn sys_mmap(
addr: *mut usize,
length: usize,
prot: i32,
flags: i32,
_fd: i32,
_offset: isize,
) -> usize {
syscall_body!(sys_mmap, {
let curr = current();
let curr_ext = curr.task_ext();
let mut aspace = curr_ext.aspace.lock();
let permission_flags = MmapProt::from_bits_truncate(prot);
let map_flags = MmapFlags::from_bits_truncate(flags);
let start_addr = if map_flags.contains(MmapFlags::MAP_FIXED) {
VirtAddr::from(addr as usize)
} else {
aspace
.find_free_area(
VirtAddr::from(addr as usize),
length,
VirtAddrRange::new(aspace.base(), aspace.end()),
)
.or(aspace.find_free_area(
aspace.base(),
length,
VirtAddrRange::new(aspace.base(), aspace.end()),
))
.ok_or(LinuxError::ENOMEM)?
};
aspace.map_alloc(start_addr, length, permission_flags.into(), false)?;
Ok(start_addr.as_usize())
})
}