mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
refactor(mm/syscall): 重构mm下的系统调用 (#1185)
* refactor(mm/syscall): 把sys_brk加到调用表 * refactor(mm/syscall): 把sys_sbrk加到调用表 * refactor(mm/syscall): 把sys_mmap加到调用表 * refactor(mm/syscall): 把sys_munmap加到调用表 * refactor(mm/syscall): 把sys_mremap加到调用表 * refactor(mm/syscall): 把sys_mprotect加到调用表 * refactor(mm/syscall): 把sys_madvise加到调用表 * refactor(mm/syscall): 把sys_msync加到调用表
This commit is contained in:
parent
8ff7cd5546
commit
0b358b9db5
@ -1,654 +0,0 @@
|
|||||||
use core::{intrinsics::unlikely, slice::from_raw_parts};
|
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
use log::error;
|
|
||||||
use system_error::SystemError;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
arch::MMArch,
|
|
||||||
driver::base::block::SeekFrom,
|
|
||||||
ipc::shm::ShmFlags,
|
|
||||||
libs::align::{check_aligned, page_align_up},
|
|
||||||
mm::MemoryManagementArch,
|
|
||||||
syscall::Syscall,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
allocator::page_frame::{PageFrameCount, VirtPageFrame},
|
|
||||||
ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
|
|
||||||
verify_area, MsFlags, VirtAddr, VmFlags,
|
|
||||||
};
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
/// Memory protection flags
|
|
||||||
pub struct ProtFlags: u64 {
|
|
||||||
const PROT_NONE = 0x0;
|
|
||||||
const PROT_READ = 0x1;
|
|
||||||
const PROT_WRITE = 0x2;
|
|
||||||
const PROT_EXEC = 0x4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Memory mapping flags
|
|
||||||
pub struct MapFlags: u64 {
|
|
||||||
const MAP_NONE = 0x0;
|
|
||||||
/// share changes
|
|
||||||
const MAP_SHARED = 0x1;
|
|
||||||
/// changes are private
|
|
||||||
const MAP_PRIVATE = 0x2;
|
|
||||||
/// Interpret addr exactly
|
|
||||||
const MAP_FIXED = 0x10;
|
|
||||||
/// don't use a file
|
|
||||||
const MAP_ANONYMOUS = 0x20;
|
|
||||||
// linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
|
|
||||||
/// stack-like segment
|
|
||||||
const MAP_GROWSDOWN = 0x100;
|
|
||||||
/// ETXTBSY
|
|
||||||
const MAP_DENYWRITE = 0x800;
|
|
||||||
/// Mark it as an executable
|
|
||||||
const MAP_EXECUTABLE = 0x1000;
|
|
||||||
/// Pages are locked
|
|
||||||
const MAP_LOCKED = 0x2000;
|
|
||||||
/// don't check for reservations
|
|
||||||
const MAP_NORESERVE = 0x4000;
|
|
||||||
/// populate (prefault) pagetables
|
|
||||||
const MAP_POPULATE = 0x8000;
|
|
||||||
/// do not block on IO
|
|
||||||
const MAP_NONBLOCK = 0x10000;
|
|
||||||
/// give out an address that is best suited for process/thread stacks
|
|
||||||
const MAP_STACK = 0x20000;
|
|
||||||
/// create a huge page mapping
|
|
||||||
const MAP_HUGETLB = 0x40000;
|
|
||||||
/// perform synchronous page faults for the mapping
|
|
||||||
const MAP_SYNC = 0x80000;
|
|
||||||
/// MAP_FIXED which doesn't unmap underlying mapping
|
|
||||||
const MAP_FIXED_NOREPLACE = 0x100000;
|
|
||||||
|
|
||||||
/// For anonymous mmap, memory could be uninitialized
|
|
||||||
const MAP_UNINITIALIZED = 0x4000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Memory mremapping flags
|
|
||||||
pub struct MremapFlags: u8 {
|
|
||||||
const MREMAP_MAYMOVE = 1;
|
|
||||||
const MREMAP_FIXED = 2;
|
|
||||||
const MREMAP_DONTUNMAP = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct MadvFlags: u64 {
|
|
||||||
/// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景
|
|
||||||
const MADV_NORMAL = 0;
|
|
||||||
/// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景
|
|
||||||
const MADV_RANDOM = 1;
|
|
||||||
/// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景
|
|
||||||
const MADV_SEQUENTIAL = 2;
|
|
||||||
/// 通知系统预读某些页面,用于应用程序提前准备数据
|
|
||||||
const MADV_WILLNEED = 3;
|
|
||||||
/// 通知系统应用程序不再需要某些页面,内核可以释放相关资源
|
|
||||||
const MADV_DONTNEED = 4;
|
|
||||||
|
|
||||||
/// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时
|
|
||||||
const MADV_FREE = 8;
|
|
||||||
/// 应用程序请求释放指定范围的页面和相关的后备存储
|
|
||||||
const MADV_REMOVE = 9;
|
|
||||||
/// 在 fork 时排除指定区域
|
|
||||||
const MADV_DONTFORK = 10;
|
|
||||||
/// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域
|
|
||||||
const MADV_DOFORK = 11;
|
|
||||||
/// 模拟内存硬件错误,触发内存错误处理器处理
|
|
||||||
const MADV_HWPOISON = 100;
|
|
||||||
/// 尝试软下线指定的内存范围
|
|
||||||
const MADV_SOFT_OFFLINE = 101;
|
|
||||||
|
|
||||||
/// 应用程序建议内核尝试合并指定范围内内容相同的页面
|
|
||||||
const MADV_MERGEABLE = 12;
|
|
||||||
/// 取消 MADV_MERGEABLE 的效果,不再合并页面
|
|
||||||
const MADV_UNMERGEABLE = 13;
|
|
||||||
|
|
||||||
/// 应用程序希望将指定范围以透明大页方式支持
|
|
||||||
const MADV_HUGEPAGE = 14;
|
|
||||||
/// 将指定范围标记为不值得用透明大页支持
|
|
||||||
const MADV_NOHUGEPAGE = 15;
|
|
||||||
|
|
||||||
/// 应用程序请求在核心转储时排除指定范围内的页面
|
|
||||||
const MADV_DONTDUMP = 16;
|
|
||||||
/// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面
|
|
||||||
const MADV_DODUMP = 17;
|
|
||||||
|
|
||||||
/// 在 fork 时将子进程的该区域内存填充为零
|
|
||||||
const MADV_WIPEONFORK = 18;
|
|
||||||
/// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存
|
|
||||||
const MADV_KEEPONFORK = 19;
|
|
||||||
|
|
||||||
/// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收
|
|
||||||
const MADV_COLD = 20;
|
|
||||||
/// 应用程序不会立刻使用这些内存,内核立即将这些页面换出
|
|
||||||
const MADV_PAGEOUT = 21;
|
|
||||||
|
|
||||||
/// 预先填充页面表,可读,通过触发读取故障
|
|
||||||
const MADV_POPULATE_READ = 22;
|
|
||||||
/// 预先填充页面表,可写,通过触发写入故障
|
|
||||||
const MADV_POPULATE_WRITE = 23;
|
|
||||||
|
|
||||||
/// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放
|
|
||||||
const MADV_DONTNEED_LOCKED = 24;
|
|
||||||
|
|
||||||
/// 同步将页面合并为新的透明大页
|
|
||||||
const MADV_COLLAPSE = 25;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MapFlags> for VmFlags {
|
|
||||||
fn from(map_flags: MapFlags) -> Self {
|
|
||||||
let mut vm_flags = VmFlags::VM_NONE;
|
|
||||||
|
|
||||||
if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
|
|
||||||
vm_flags |= VmFlags::VM_GROWSDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if map_flags.contains(MapFlags::MAP_LOCKED) {
|
|
||||||
vm_flags |= VmFlags::VM_LOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if map_flags.contains(MapFlags::MAP_SYNC) {
|
|
||||||
vm_flags |= VmFlags::VM_SYNC;
|
|
||||||
}
|
|
||||||
|
|
||||||
if map_flags.contains(MapFlags::MAP_SHARED) {
|
|
||||||
vm_flags |= VmFlags::VM_SHARED;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ProtFlags> for VmFlags {
|
|
||||||
fn from(prot_flags: ProtFlags) -> Self {
|
|
||||||
let mut vm_flags = VmFlags::VM_NONE;
|
|
||||||
|
|
||||||
if prot_flags.contains(ProtFlags::PROT_READ) {
|
|
||||||
vm_flags |= VmFlags::VM_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if prot_flags.contains(ProtFlags::PROT_WRITE) {
|
|
||||||
vm_flags |= VmFlags::VM_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if prot_flags.contains(ProtFlags::PROT_EXEC) {
|
|
||||||
vm_flags |= VmFlags::VM_EXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ShmFlags> for VmFlags {
|
|
||||||
fn from(shm_flags: ShmFlags) -> Self {
|
|
||||||
let mut vm_flags = VmFlags::VM_NONE;
|
|
||||||
|
|
||||||
if shm_flags.contains(ShmFlags::SHM_RDONLY) {
|
|
||||||
vm_flags |= VmFlags::VM_READ;
|
|
||||||
} else {
|
|
||||||
vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if shm_flags.contains(ShmFlags::SHM_EXEC) {
|
|
||||||
vm_flags |= VmFlags::VM_EXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
if shm_flags.contains(ShmFlags::SHM_HUGETLB) {
|
|
||||||
vm_flags |= VmFlags::VM_HUGETLB;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<VmFlags> for MapFlags {
|
|
||||||
fn from(value: VmFlags) -> Self {
|
|
||||||
let mut map_flags = MapFlags::MAP_NONE;
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_GROWSDOWN) {
|
|
||||||
map_flags |= MapFlags::MAP_GROWSDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_LOCKED) {
|
|
||||||
map_flags |= MapFlags::MAP_LOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_SYNC) {
|
|
||||||
map_flags |= MapFlags::MAP_SYNC;
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_MAYSHARE) {
|
|
||||||
map_flags |= MapFlags::MAP_SHARED;
|
|
||||||
}
|
|
||||||
|
|
||||||
map_flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<VmFlags> for ProtFlags {
|
|
||||||
fn from(value: VmFlags) -> Self {
|
|
||||||
let mut prot_flags = ProtFlags::PROT_NONE;
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_READ) {
|
|
||||||
prot_flags |= ProtFlags::PROT_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_WRITE) {
|
|
||||||
prot_flags |= ProtFlags::PROT_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.contains(VmFlags::VM_EXEC) {
|
|
||||||
prot_flags |= ProtFlags::PROT_EXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
prot_flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Syscall {
|
|
||||||
pub fn brk(new_addr: VirtAddr) -> Result<VirtAddr, SystemError> {
|
|
||||||
// log::debug!("brk: new_addr={:?}", new_addr);
|
|
||||||
let address_space = AddressSpace::current()?;
|
|
||||||
let mut address_space = address_space.write();
|
|
||||||
|
|
||||||
if new_addr < address_space.brk_start || new_addr >= MMArch::USER_END_VADDR {
|
|
||||||
return Ok(address_space.brk);
|
|
||||||
}
|
|
||||||
if new_addr == address_space.brk {
|
|
||||||
return Ok(address_space.brk);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// log::debug!("brk: set_brk new_addr={:?}", new_addr);
|
|
||||||
address_space
|
|
||||||
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
return Ok(address_space.sbrk(0).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sbrk(incr: isize) -> Result<VirtAddr, SystemError> {
|
|
||||||
let address_space = AddressSpace::current()?;
|
|
||||||
assert!(address_space.read().user_mapper.utable.is_current());
|
|
||||||
let mut address_space = address_space.write();
|
|
||||||
let r = unsafe { address_space.sbrk(incr) };
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## mmap系统调用
|
|
||||||
///
|
|
||||||
/// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `start_vaddr`:映射的起始地址
|
|
||||||
/// - `len`:映射的长度
|
|
||||||
/// - `prot`:保护标志
|
|
||||||
/// - `flags`:映射标志
|
|
||||||
/// - `fd`:文件描述符(暂时不支持)
|
|
||||||
/// - `offset`:文件偏移量 (暂时不支持)
|
|
||||||
///
|
|
||||||
/// ## 返回值
|
|
||||||
///
|
|
||||||
/// 成功时返回映射的起始地址,失败时返回错误码
|
|
||||||
pub fn mmap(
|
|
||||||
start_vaddr: VirtAddr,
|
|
||||||
len: usize,
|
|
||||||
prot_flags: usize,
|
|
||||||
map_flags: usize,
|
|
||||||
fd: i32,
|
|
||||||
offset: usize,
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
|
|
||||||
let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
|
|
||||||
|
|
||||||
if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
|
|
||||||
&& map_flags.contains(MapFlags::MAP_FIXED)
|
|
||||||
{
|
|
||||||
error!(
|
|
||||||
"mmap: MAP_FIXED is not supported for address below {}",
|
|
||||||
DEFAULT_MMAP_MIN_ADDR
|
|
||||||
);
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暂时不支持巨页映射
|
|
||||||
if map_flags.contains(MapFlags::MAP_HUGETLB) {
|
|
||||||
error!("mmap: not support huge page mapping");
|
|
||||||
return Err(SystemError::ENOSYS);
|
|
||||||
}
|
|
||||||
let current_address_space = AddressSpace::current()?;
|
|
||||||
let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) {
|
|
||||||
// 匿名映射
|
|
||||||
current_address_space.write().map_anonymous(
|
|
||||||
start_vaddr,
|
|
||||||
len,
|
|
||||||
prot_flags,
|
|
||||||
map_flags,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
// 文件映射
|
|
||||||
current_address_space.write().file_mapping(
|
|
||||||
start_vaddr,
|
|
||||||
len,
|
|
||||||
prot_flags,
|
|
||||||
map_flags,
|
|
||||||
fd,
|
|
||||||
offset,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
return Ok(start_page.virt_address().data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## mremap系统调用
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `old_vaddr`:原映射的起始地址
|
|
||||||
/// - `old_len`:原映射的长度
|
|
||||||
/// - `new_len`:重新映射的长度
|
|
||||||
/// - `mremap_flags`:重映射标志
|
|
||||||
/// - `new_vaddr`:重新映射的起始地址
|
|
||||||
///
|
|
||||||
/// ## 返回值
|
|
||||||
///
|
|
||||||
/// 成功时返回重映射的起始地址,失败时返回错误码
|
|
||||||
pub fn mremap(
|
|
||||||
old_vaddr: VirtAddr,
|
|
||||||
old_len: usize,
|
|
||||||
new_len: usize,
|
|
||||||
mremap_flags: MremapFlags,
|
|
||||||
new_vaddr: VirtAddr,
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
// 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
|
|
||||||
if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
|
|
||||||
&& (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
|
|
||||||
|| new_vaddr == VirtAddr::new(0))
|
|
||||||
{
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
|
|
||||||
if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
|
|
||||||
&& (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
|
|
||||||
{
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 旧内存地址必须对齐
|
|
||||||
if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将old_len、new_len 对齐页面大小
|
|
||||||
let old_len = page_align_up(old_len);
|
|
||||||
let new_len = page_align_up(new_len);
|
|
||||||
|
|
||||||
// 不允许重映射内存区域大小为0
|
|
||||||
if new_len == 0 {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_address_space = AddressSpace::current()?;
|
|
||||||
let vma = current_address_space.read().mappings.contains(old_vaddr);
|
|
||||||
if vma.is_none() {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
let vma = vma.unwrap();
|
|
||||||
let vm_flags = *vma.lock_irqsave().vm_flags();
|
|
||||||
|
|
||||||
// 暂时不支持巨页映射
|
|
||||||
if vm_flags.contains(VmFlags::VM_HUGETLB) {
|
|
||||||
error!("mmap: not support huge page mapping");
|
|
||||||
return Err(SystemError::ENOSYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缩小旧内存映射区域
|
|
||||||
if old_len > new_len {
|
|
||||||
Self::munmap(old_vaddr + new_len, old_len - new_len)?;
|
|
||||||
return Ok(old_vaddr.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重映射到新内存区域
|
|
||||||
let r = current_address_space.write().mremap(
|
|
||||||
old_vaddr,
|
|
||||||
old_len,
|
|
||||||
new_len,
|
|
||||||
mremap_flags,
|
|
||||||
new_vaddr,
|
|
||||||
vm_flags,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
|
|
||||||
Self::munmap(old_vaddr, old_len)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(r.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## munmap系统调用
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
|
|
||||||
/// - `len`:取消映射的字节数(已经对齐到页)
|
|
||||||
///
|
|
||||||
/// ## 返回值
|
|
||||||
///
|
|
||||||
/// 成功时返回0,失败时返回错误码
|
|
||||||
pub fn munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
|
|
||||||
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
|
|
||||||
assert!(check_aligned(len, MMArch::PAGE_SIZE));
|
|
||||||
|
|
||||||
if unlikely(verify_area(start_vaddr, len).is_err()) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
if unlikely(len == 0) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
|
||||||
let start_frame = VirtPageFrame::new(start_vaddr);
|
|
||||||
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
|
||||||
|
|
||||||
current_address_space
|
|
||||||
.write()
|
|
||||||
.munmap(start_frame, page_count)
|
|
||||||
.map_err(|_| SystemError::EINVAL)?;
|
|
||||||
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## mprotect系统调用
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `start_vaddr`:起始地址(已经对齐到页)
|
|
||||||
/// - `len`:长度(已经对齐到页)
|
|
||||||
/// - `prot_flags`:保护标志
|
|
||||||
pub fn mprotect(
|
|
||||||
start_vaddr: VirtAddr,
|
|
||||||
len: usize,
|
|
||||||
prot_flags: usize,
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
|
|
||||||
assert!(check_aligned(len, MMArch::PAGE_SIZE));
|
|
||||||
|
|
||||||
if unlikely(verify_area(start_vaddr, len).is_err()) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
if unlikely(len == 0) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let prot_flags = ProtFlags::from_bits(prot_flags as u64).ok_or(SystemError::EINVAL)?;
|
|
||||||
|
|
||||||
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
|
||||||
let start_frame = VirtPageFrame::new(start_vaddr);
|
|
||||||
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
|
||||||
|
|
||||||
current_address_space
|
|
||||||
.write()
|
|
||||||
.mprotect(start_frame, page_count, prot_flags)
|
|
||||||
.map_err(|_| SystemError::EINVAL)?;
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## madvise系统调用
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `start_vaddr`:起始地址(已经对齐到页)
|
|
||||||
/// - `len`:长度(已经对齐到页)
|
|
||||||
/// - `madv_flags`:建议标志
|
|
||||||
pub fn madvise(
|
|
||||||
start_vaddr: VirtAddr,
|
|
||||||
len: usize,
|
|
||||||
madv_flags: usize,
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if unlikely(verify_area(start_vaddr, len).is_err()) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
if unlikely(len == 0) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let madv_flags = MadvFlags::from_bits(madv_flags as u64).ok_or(SystemError::EINVAL)?;
|
|
||||||
|
|
||||||
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
|
||||||
let start_frame = VirtPageFrame::new(start_vaddr);
|
|
||||||
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
|
||||||
|
|
||||||
current_address_space
|
|
||||||
.write()
|
|
||||||
.madvise(start_frame, page_count, madv_flags)
|
|
||||||
.map_err(|_| SystemError::EINVAL)?;
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ## msync系统调用
|
|
||||||
///
|
|
||||||
/// ## 参数
|
|
||||||
///
|
|
||||||
/// - `start`:起始地址(已经对齐到页)
|
|
||||||
/// - `len`:长度(已经对齐到页)
|
|
||||||
/// - `flags`:标志
|
|
||||||
pub fn msync(start: VirtAddr, len: usize, flags: usize) -> Result<usize, SystemError> {
|
|
||||||
if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if unlikely(verify_area(start, len).is_err()) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
if unlikely(len == 0) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut start = start.data();
|
|
||||||
let end = start + len;
|
|
||||||
let flags = MsFlags::from_bits_truncate(flags);
|
|
||||||
let mut unmapped_error = Ok(0);
|
|
||||||
|
|
||||||
if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) {
|
|
||||||
return Err(SystemError::EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if end < start {
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if start == end {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_address_space = AddressSpace::current()?;
|
|
||||||
let mut err = Err(SystemError::ENOMEM);
|
|
||||||
let mut next_vma = current_address_space
|
|
||||||
.read()
|
|
||||||
.mappings
|
|
||||||
.find_nearest(VirtAddr::new(start));
|
|
||||||
loop {
|
|
||||||
if let Some(vma) = next_vma.clone() {
|
|
||||||
let guard = vma.lock_irqsave();
|
|
||||||
let vm_start = guard.region().start().data();
|
|
||||||
let vm_end = guard.region().end().data();
|
|
||||||
if start < vm_start {
|
|
||||||
if flags == MsFlags::MS_ASYNC {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start = vm_start;
|
|
||||||
if start >= vm_end {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
unmapped_error = Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
let vm_flags = *guard.vm_flags();
|
|
||||||
if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) {
|
|
||||||
err = Err(SystemError::EBUSY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let file = guard.vm_file();
|
|
||||||
let fstart = (start - vm_start)
|
|
||||||
+ (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT);
|
|
||||||
let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1;
|
|
||||||
let old_start = start;
|
|
||||||
start = vm_end;
|
|
||||||
// log::info!("flags: {:?}", flags);
|
|
||||||
// log::info!("vm_flags: {:?}", vm_flags);
|
|
||||||
// log::info!("file: {:?}", file);
|
|
||||||
if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) {
|
|
||||||
if let Some(file) = file {
|
|
||||||
let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap();
|
|
||||||
file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap();
|
|
||||||
err = file.write(len, unsafe {
|
|
||||||
from_raw_parts(old_start as *mut u8, fend - fstart + 1)
|
|
||||||
});
|
|
||||||
file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap();
|
|
||||||
if err.is_err() {
|
|
||||||
break;
|
|
||||||
} else if start >= end {
|
|
||||||
err = unmapped_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next_vma = current_address_space
|
|
||||||
.read()
|
|
||||||
.mappings
|
|
||||||
.find_nearest(VirtAddr::new(start));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if start >= end {
|
|
||||||
err = unmapped_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next_vma = current_address_space
|
|
||||||
.read()
|
|
||||||
.mappings
|
|
||||||
.find_nearest(VirtAddr::new(vm_end));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(SystemError::ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
245
kernel/src/mm/syscall/mod.rs
Normal file
245
kernel/src/mm/syscall/mod.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use crate::{
|
||||||
|
ipc::shm::ShmFlags,
|
||||||
|
libs::align::{check_aligned, page_align_up},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{allocator::page_frame::PageFrameCount, MsFlags, VmFlags};
|
||||||
|
|
||||||
|
mod sys_brk;
|
||||||
|
mod sys_madvise;
|
||||||
|
mod sys_mmap;
|
||||||
|
mod sys_mprotect;
|
||||||
|
mod sys_mremap;
|
||||||
|
mod sys_msync;
|
||||||
|
mod sys_munmap;
|
||||||
|
mod sys_sbrk;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
/// Memory protection flags
|
||||||
|
pub struct ProtFlags: u64 {
|
||||||
|
const PROT_NONE = 0x0;
|
||||||
|
const PROT_READ = 0x1;
|
||||||
|
const PROT_WRITE = 0x2;
|
||||||
|
const PROT_EXEC = 0x4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Memory mapping flags
|
||||||
|
pub struct MapFlags: u64 {
|
||||||
|
const MAP_NONE = 0x0;
|
||||||
|
/// share changes
|
||||||
|
const MAP_SHARED = 0x1;
|
||||||
|
/// changes are private
|
||||||
|
const MAP_PRIVATE = 0x2;
|
||||||
|
/// Interpret addr exactly
|
||||||
|
const MAP_FIXED = 0x10;
|
||||||
|
/// don't use a file
|
||||||
|
const MAP_ANONYMOUS = 0x20;
|
||||||
|
// linux-6.1-rc5/include/uapi/asm-generic/mman.h#7
|
||||||
|
/// stack-like segment
|
||||||
|
const MAP_GROWSDOWN = 0x100;
|
||||||
|
/// ETXTBSY
|
||||||
|
const MAP_DENYWRITE = 0x800;
|
||||||
|
/// Mark it as an executable
|
||||||
|
const MAP_EXECUTABLE = 0x1000;
|
||||||
|
/// Pages are locked
|
||||||
|
const MAP_LOCKED = 0x2000;
|
||||||
|
/// don't check for reservations
|
||||||
|
const MAP_NORESERVE = 0x4000;
|
||||||
|
/// populate (prefault) pagetables
|
||||||
|
const MAP_POPULATE = 0x8000;
|
||||||
|
/// do not block on IO
|
||||||
|
const MAP_NONBLOCK = 0x10000;
|
||||||
|
/// give out an address that is best suited for process/thread stacks
|
||||||
|
const MAP_STACK = 0x20000;
|
||||||
|
/// create a huge page mapping
|
||||||
|
const MAP_HUGETLB = 0x40000;
|
||||||
|
/// perform synchronous page faults for the mapping
|
||||||
|
const MAP_SYNC = 0x80000;
|
||||||
|
/// MAP_FIXED which doesn't unmap underlying mapping
|
||||||
|
const MAP_FIXED_NOREPLACE = 0x100000;
|
||||||
|
|
||||||
|
/// For anonymous mmap, memory could be uninitialized
|
||||||
|
const MAP_UNINITIALIZED = 0x4000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Memory mremapping flags
|
||||||
|
pub struct MremapFlags: u8 {
|
||||||
|
const MREMAP_MAYMOVE = 1;
|
||||||
|
const MREMAP_FIXED = 2;
|
||||||
|
const MREMAP_DONTUNMAP = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct MadvFlags: u64 {
|
||||||
|
/// 默认行为,系统会进行一定的预读和预写,适用于一般读取场景
|
||||||
|
const MADV_NORMAL = 0;
|
||||||
|
/// 随机访问模式,系统会尽量最小化数据读取量,适用于随机访问的场景
|
||||||
|
const MADV_RANDOM = 1;
|
||||||
|
/// 顺序访问模式,系统会进行积极的预读,访问后的页面可以尽快释放,适用于顺序读取场景
|
||||||
|
const MADV_SEQUENTIAL = 2;
|
||||||
|
/// 通知系统预读某些页面,用于应用程序提前准备数据
|
||||||
|
const MADV_WILLNEED = 3;
|
||||||
|
/// 通知系统应用程序不再需要某些页面,内核可以释放相关资源
|
||||||
|
const MADV_DONTNEED = 4;
|
||||||
|
|
||||||
|
/// 将指定范围的页面标记为延迟释放,真正的释放会延迟至内存压力发生时
|
||||||
|
const MADV_FREE = 8;
|
||||||
|
/// 应用程序请求释放指定范围的页面和相关的后备存储
|
||||||
|
const MADV_REMOVE = 9;
|
||||||
|
/// 在 fork 时排除指定区域
|
||||||
|
const MADV_DONTFORK = 10;
|
||||||
|
/// 取消 MADV_DONTFORK 的效果,不再在 fork 时排除指定区域
|
||||||
|
const MADV_DOFORK = 11;
|
||||||
|
/// 模拟内存硬件错误,触发内存错误处理器处理
|
||||||
|
const MADV_HWPOISON = 100;
|
||||||
|
/// 尝试软下线指定的内存范围
|
||||||
|
const MADV_SOFT_OFFLINE = 101;
|
||||||
|
|
||||||
|
/// 应用程序建议内核尝试合并指定范围内内容相同的页面
|
||||||
|
const MADV_MERGEABLE = 12;
|
||||||
|
/// 取消 MADV_MERGEABLE 的效果,不再合并页面
|
||||||
|
const MADV_UNMERGEABLE = 13;
|
||||||
|
|
||||||
|
/// 应用程序希望将指定范围以透明大页方式支持
|
||||||
|
const MADV_HUGEPAGE = 14;
|
||||||
|
/// 将指定范围标记为不值得用透明大页支持
|
||||||
|
const MADV_NOHUGEPAGE = 15;
|
||||||
|
|
||||||
|
/// 应用程序请求在核心转储时排除指定范围内的页面
|
||||||
|
const MADV_DONTDUMP = 16;
|
||||||
|
/// 取消 MADV_DONTDUMP 的效果,不再排除核心转储时的页面
|
||||||
|
const MADV_DODUMP = 17;
|
||||||
|
|
||||||
|
/// 在 fork 时将子进程的该区域内存填充为零
|
||||||
|
const MADV_WIPEONFORK = 18;
|
||||||
|
/// 取消 `MADV_WIPEONFORK` 的效果,不再在 fork 时填充子进程的内存
|
||||||
|
const MADV_KEEPONFORK = 19;
|
||||||
|
|
||||||
|
/// 应用程序不会立刻使用这些内存,内核将页面设置为非活动状态以便在内存压力发生时轻松回收
|
||||||
|
const MADV_COLD = 20;
|
||||||
|
/// 应用程序不会立刻使用这些内存,内核立即将这些页面换出
|
||||||
|
const MADV_PAGEOUT = 21;
|
||||||
|
|
||||||
|
/// 预先填充页面表,可读,通过触发读取故障
|
||||||
|
const MADV_POPULATE_READ = 22;
|
||||||
|
/// 预先填充页面表,可写,通过触发写入故障
|
||||||
|
const MADV_POPULATE_WRITE = 23;
|
||||||
|
|
||||||
|
/// 与 `MADV_DONTNEED` 类似,会将被锁定的页面释放
|
||||||
|
const MADV_DONTNEED_LOCKED = 24;
|
||||||
|
|
||||||
|
/// 同步将页面合并为新的透明大页
|
||||||
|
const MADV_COLLAPSE = 25;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MapFlags> for VmFlags {
|
||||||
|
fn from(map_flags: MapFlags) -> Self {
|
||||||
|
let mut vm_flags = VmFlags::VM_NONE;
|
||||||
|
|
||||||
|
if map_flags.contains(MapFlags::MAP_GROWSDOWN) {
|
||||||
|
vm_flags |= VmFlags::VM_GROWSDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if map_flags.contains(MapFlags::MAP_LOCKED) {
|
||||||
|
vm_flags |= VmFlags::VM_LOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if map_flags.contains(MapFlags::MAP_SYNC) {
|
||||||
|
vm_flags |= VmFlags::VM_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if map_flags.contains(MapFlags::MAP_SHARED) {
|
||||||
|
vm_flags |= VmFlags::VM_SHARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ProtFlags> for VmFlags {
|
||||||
|
fn from(prot_flags: ProtFlags) -> Self {
|
||||||
|
let mut vm_flags = VmFlags::VM_NONE;
|
||||||
|
|
||||||
|
if prot_flags.contains(ProtFlags::PROT_READ) {
|
||||||
|
vm_flags |= VmFlags::VM_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if prot_flags.contains(ProtFlags::PROT_WRITE) {
|
||||||
|
vm_flags |= VmFlags::VM_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if prot_flags.contains(ProtFlags::PROT_EXEC) {
|
||||||
|
vm_flags |= VmFlags::VM_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ShmFlags> for VmFlags {
|
||||||
|
fn from(shm_flags: ShmFlags) -> Self {
|
||||||
|
let mut vm_flags = VmFlags::VM_NONE;
|
||||||
|
|
||||||
|
if shm_flags.contains(ShmFlags::SHM_RDONLY) {
|
||||||
|
vm_flags |= VmFlags::VM_READ;
|
||||||
|
} else {
|
||||||
|
vm_flags |= VmFlags::VM_READ | VmFlags::VM_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if shm_flags.contains(ShmFlags::SHM_EXEC) {
|
||||||
|
vm_flags |= VmFlags::VM_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if shm_flags.contains(ShmFlags::SHM_HUGETLB) {
|
||||||
|
vm_flags |= VmFlags::VM_HUGETLB;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm_flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VmFlags> for MapFlags {
|
||||||
|
fn from(value: VmFlags) -> Self {
|
||||||
|
let mut map_flags = MapFlags::MAP_NONE;
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_GROWSDOWN) {
|
||||||
|
map_flags |= MapFlags::MAP_GROWSDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_LOCKED) {
|
||||||
|
map_flags |= MapFlags::MAP_LOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_SYNC) {
|
||||||
|
map_flags |= MapFlags::MAP_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_MAYSHARE) {
|
||||||
|
map_flags |= MapFlags::MAP_SHARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<VmFlags> for ProtFlags {
|
||||||
|
fn from(value: VmFlags) -> Self {
|
||||||
|
let mut prot_flags = ProtFlags::PROT_NONE;
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_READ) {
|
||||||
|
prot_flags |= ProtFlags::PROT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_WRITE) {
|
||||||
|
prot_flags |= ProtFlags::PROT_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.contains(VmFlags::VM_EXEC) {
|
||||||
|
prot_flags |= ProtFlags::PROT_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
prot_flags
|
||||||
|
}
|
||||||
|
}
|
68
kernel/src/mm/syscall/sys_brk.rs
Normal file
68
kernel/src/mm/syscall/sys_brk.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//! System call handler for the brk system call.
|
||||||
|
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_BRK};
|
||||||
|
use crate::mm::ucontext::AddressSpace;
|
||||||
|
use crate::mm::MemoryManagementArch;
|
||||||
|
use crate::mm::VirtAddr;
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handler for the brk system call, which sets the end of the data segment (heap).
|
||||||
|
pub struct SysBrkHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysBrkHandle {
|
||||||
|
/// Returns the number of arguments this syscall takes.
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the brk system call.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `args` - The syscall arguments, where args[0] is the new end address of the heap.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * On success, returns the new program break (heap end) as usize.
|
||||||
|
/// * On failure, returns a SystemError.
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let addr = Self::addr(args);
|
||||||
|
let new_addr = VirtAddr::new(addr);
|
||||||
|
let address_space = AddressSpace::current()?;
|
||||||
|
let mut address_space = address_space.write();
|
||||||
|
|
||||||
|
if new_addr < address_space.brk_start || new_addr >= crate::arch::MMArch::USER_END_VADDR {
|
||||||
|
return Ok(address_space.brk.data());
|
||||||
|
}
|
||||||
|
if new_addr == address_space.brk {
|
||||||
|
return Ok(address_space.brk.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
address_space
|
||||||
|
.set_brk(VirtAddr::new(crate::libs::align::page_align_up(
|
||||||
|
new_addr.data(),
|
||||||
|
)))
|
||||||
|
.ok();
|
||||||
|
return Ok(address_space.sbrk(0).unwrap().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![FormattedSyscallParam::new(
|
||||||
|
"addr",
|
||||||
|
format!("{:#x}", Self::addr(args)),
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysBrkHandle {
|
||||||
|
/// Extracts the address argument from syscall parameters.
|
||||||
|
fn addr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_BRK, SysBrkHandle);
|
84
kernel/src/mm/syscall/sys_madvise.rs
Normal file
84
kernel/src/mm/syscall/sys_madvise.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//! System call handler for the madvise system call.
|
||||||
|
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MADVISE, MMArch};
|
||||||
|
use crate::mm::{
|
||||||
|
syscall::{check_aligned, MadvFlags, PageFrameCount},
|
||||||
|
ucontext::AddressSpace,
|
||||||
|
MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr},
|
||||||
|
};
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handles the madvise system call, which gives advice about the use of memory.
|
||||||
|
pub struct SysMadviseHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMadviseHandle {
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## madvise系统调用
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
/// - `start_vaddr`:起始地址(已经对齐到页)
|
||||||
|
/// - `len`:长度(已经对齐到页)
|
||||||
|
/// - `madv_flags`:建议标志
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let start_vaddr = VirtAddr::new(Self::start_vaddr(args));
|
||||||
|
let len = Self::len(args);
|
||||||
|
let madv_flags =
|
||||||
|
MadvFlags::from_bits(Self::madv_flags(args) as u64).ok_or(SystemError::EINVAL)?;
|
||||||
|
if Self::start_vaddr(args) & (MMArch::PAGE_SIZE - 1) != 0 {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !start_vaddr.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if verify_area(start_vaddr, len).is_err() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if len == 0 {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
||||||
|
let start_frame = VirtPageFrame::new(start_vaddr);
|
||||||
|
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
||||||
|
|
||||||
|
current_address_space
|
||||||
|
.write()
|
||||||
|
.madvise(start_frame, page_count, madv_flags)
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))),
|
||||||
|
FormattedSyscallParam::new("madv_flags", format!("{:#x}", Self::madv_flags(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMadviseHandle {
|
||||||
|
/// Extracts the start_vaddr argument from syscall parameters.
|
||||||
|
fn start_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the len argument from syscall parameters.
|
||||||
|
fn len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
/// Extracts the madv_flags argument from syscall parameters.
|
||||||
|
fn madv_flags(args: &[usize]) -> usize {
|
||||||
|
args[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MADVISE, SysMadviseHandle);
|
137
kernel/src/mm/syscall/sys_mmap.rs
Normal file
137
kernel/src/mm/syscall/sys_mmap.rs
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
//! System call handler for the mmap system call.
|
||||||
|
|
||||||
|
use super::ProtFlags;
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MMAP};
|
||||||
|
use crate::mm::syscall::page_align_up;
|
||||||
|
use crate::mm::syscall::MapFlags;
|
||||||
|
use crate::mm::ucontext::DEFAULT_MMAP_MIN_ADDR;
|
||||||
|
use crate::mm::verify_area;
|
||||||
|
use crate::mm::AddressSpace;
|
||||||
|
use crate::mm::VirtAddr;
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use log::error;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handler for the mmap system call, which maps files or devices into memory.
|
||||||
|
pub struct SysMmapHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMmapHandle {
|
||||||
|
/// Returns the number of arguments this syscall takes.
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
6
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## mmap系统调用
|
||||||
|
///
|
||||||
|
/// 该函数的实现参考了Linux内核的实现,但是并不完全相同。因为有些功能咱们还没实现
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `start_vaddr`:映射的起始地址
|
||||||
|
/// - `len`:映射的长度
|
||||||
|
/// - `prot`:保护标志
|
||||||
|
/// - `flags`:映射标志
|
||||||
|
/// - `fd`:文件描述符(暂时不支持)
|
||||||
|
/// - `offset`:文件偏移量 (暂时不支持)
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// 成功时返回映射的起始地址,失败时返回错误码
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let start_vaddr = VirtAddr::new(Self::start_vaddr(args));
|
||||||
|
let len = page_align_up(Self::len(args));
|
||||||
|
let prot_flags = Self::prot(args);
|
||||||
|
let map_flags = Self::flags(args);
|
||||||
|
let fd = Self::fd(args);
|
||||||
|
let offset = Self::offset(args);
|
||||||
|
if verify_area(start_vaddr, len).is_err() {
|
||||||
|
return Err(SystemError::EFAULT);
|
||||||
|
} else {
|
||||||
|
let map_flags = MapFlags::from_bits_truncate(map_flags as u64);
|
||||||
|
let prot_flags = ProtFlags::from_bits_truncate(prot_flags as u64);
|
||||||
|
|
||||||
|
if start_vaddr < VirtAddr::new(DEFAULT_MMAP_MIN_ADDR)
|
||||||
|
&& map_flags.contains(MapFlags::MAP_FIXED)
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"mmap: MAP_FIXED is not supported for address below {}",
|
||||||
|
DEFAULT_MMAP_MIN_ADDR
|
||||||
|
);
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂时不支持巨页映射
|
||||||
|
if map_flags.contains(MapFlags::MAP_HUGETLB) {
|
||||||
|
error!("mmap: not support huge page mapping");
|
||||||
|
return Err(SystemError::ENOSYS);
|
||||||
|
}
|
||||||
|
let current_address_space = AddressSpace::current()?;
|
||||||
|
let start_page = if map_flags.contains(MapFlags::MAP_ANONYMOUS) {
|
||||||
|
// 匿名映射
|
||||||
|
current_address_space.write().map_anonymous(
|
||||||
|
start_vaddr,
|
||||||
|
len,
|
||||||
|
prot_flags,
|
||||||
|
map_flags,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
// 文件映射
|
||||||
|
current_address_space.write().file_mapping(
|
||||||
|
start_vaddr,
|
||||||
|
len,
|
||||||
|
prot_flags,
|
||||||
|
map_flags,
|
||||||
|
fd,
|
||||||
|
offset,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
return Ok(start_page.virt_address().data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))),
|
||||||
|
FormattedSyscallParam::new("prot", format!("{:#x}", Self::prot(args))),
|
||||||
|
FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))),
|
||||||
|
FormattedSyscallParam::new("fd", format!("{}", Self::fd(args))),
|
||||||
|
FormattedSyscallParam::new("offset", format!("{:#x}", Self::offset(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMmapHandle {
|
||||||
|
/// Extracts the start virtual address argument from syscall parameters.
|
||||||
|
fn start_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the length argument from syscall parameters.
|
||||||
|
fn len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
/// Extracts the protection flags argument from syscall parameters.
|
||||||
|
fn prot(args: &[usize]) -> usize {
|
||||||
|
args[2]
|
||||||
|
}
|
||||||
|
/// Extracts the mapping flags argument from syscall parameters.
|
||||||
|
fn flags(args: &[usize]) -> usize {
|
||||||
|
args[3]
|
||||||
|
}
|
||||||
|
/// Extracts the file descriptor argument from syscall parameters.
|
||||||
|
fn fd(args: &[usize]) -> i32 {
|
||||||
|
args[4] as i32
|
||||||
|
}
|
||||||
|
/// Extracts the file offset argument from syscall parameters.
|
||||||
|
fn offset(args: &[usize]) -> usize {
|
||||||
|
args[5]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MMAP, SysMmapHandle);
|
83
kernel/src/mm/syscall/sys_mprotect.rs
Normal file
83
kernel/src/mm/syscall/sys_mprotect.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
//! System call handler for the mprotect system call.
|
||||||
|
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MPROTECT, MMArch};
|
||||||
|
use crate::mm::{
|
||||||
|
syscall::{check_aligned, PageFrameCount, ProtFlags},
|
||||||
|
ucontext::AddressSpace,
|
||||||
|
MemoryManagementArch, VirtPageFrame, {verify_area, VirtAddr},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handles the mprotect system call.
|
||||||
|
pub struct SysMprotectHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMprotectHandle {
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## mprotect系统调用
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `start_vaddr`:起始地址(已经对齐到页)
|
||||||
|
/// - `len`:长度(已经对齐到页)
|
||||||
|
/// - `prot_flags`:保护标志
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let start_vaddr = VirtAddr::new(Self::start_vaddr(args));
|
||||||
|
let len = Self::len(args);
|
||||||
|
let prot_flags =
|
||||||
|
ProtFlags::from_bits(Self::prot_flags(args) as u64).ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
|
||||||
|
assert!(check_aligned(len, MMArch::PAGE_SIZE));
|
||||||
|
|
||||||
|
if verify_area(start_vaddr, len).is_err() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if len == 0 {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
||||||
|
let start_frame = VirtPageFrame::new(start_vaddr);
|
||||||
|
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
||||||
|
|
||||||
|
current_address_space
|
||||||
|
.write()
|
||||||
|
.mprotect(start_frame, page_count, prot_flags)
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))),
|
||||||
|
FormattedSyscallParam::new("prot_flags", format!("{:#x}", Self::prot_flags(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMprotectHandle {
|
||||||
|
/// Extracts the start_vaddr argument from syscall parameters.
|
||||||
|
fn start_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the len argument from syscall parameters.
|
||||||
|
fn len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
/// Extracts the prot_flags argument from syscall parameters.
|
||||||
|
fn prot_flags(args: &[usize]) -> usize {
|
||||||
|
args[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MPROTECT, SysMprotectHandle);
|
145
kernel/src/mm/syscall/sys_mremap.rs
Normal file
145
kernel/src/mm/syscall/sys_mremap.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
//! System call handler for the mremap system call.
|
||||||
|
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MREMAP};
|
||||||
|
use crate::mm::syscall::page_align_up;
|
||||||
|
use crate::mm::syscall::sys_munmap::do_munmap;
|
||||||
|
use crate::mm::syscall::MremapFlags;
|
||||||
|
use crate::mm::ucontext::AddressSpace;
|
||||||
|
use crate::mm::MemoryManagementArch;
|
||||||
|
use crate::mm::{MMArch, VirtAddr, VmFlags};
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
/// Handles the mremap system call.
|
||||||
|
pub struct SysMremapHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMremapHandle {
|
||||||
|
/// Returns the number of arguments this syscall takes.
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
5
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ## mremap系统调用
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `old_vaddr`:原映射的起始地址
|
||||||
|
/// - `old_len`:原映射的长度
|
||||||
|
/// - `new_len`:重新映射的长度
|
||||||
|
/// - `mremap_flags`:重映射标志
|
||||||
|
/// - `new_vaddr`:重新映射的起始地址
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// 成功时返回重映射的起始地址,失败时返回错误码
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let old_vaddr = VirtAddr::new(Self::old_vaddr(args));
|
||||||
|
let old_len = Self::old_len(args);
|
||||||
|
let new_len = Self::new_len(args);
|
||||||
|
let mremap_flags = MremapFlags::from_bits_truncate(Self::mremap_flags(args) as u8);
|
||||||
|
let new_vaddr = VirtAddr::new(Self::new_vaddr(args));
|
||||||
|
|
||||||
|
// 需要重映射到新内存区域的情况下,必须包含MREMAP_MAYMOVE并且指定新地址
|
||||||
|
if mremap_flags.contains(MremapFlags::MREMAP_FIXED)
|
||||||
|
&& (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE)
|
||||||
|
|| new_vaddr == VirtAddr::new(0))
|
||||||
|
{
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不取消旧映射的情况下,必须包含MREMAP_MAYMOVE并且新内存大小等于旧内存大小
|
||||||
|
if mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP)
|
||||||
|
&& (!mremap_flags.contains(MremapFlags::MREMAP_MAYMOVE) || old_len != new_len)
|
||||||
|
{
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 旧内存地址必须对齐
|
||||||
|
if !old_vaddr.check_aligned(MMArch::PAGE_SIZE) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将old_len、new_len 对齐页面大小
|
||||||
|
let old_len = page_align_up(old_len);
|
||||||
|
let new_len = page_align_up(new_len);
|
||||||
|
|
||||||
|
// 不允许重映射内存区域大小为0
|
||||||
|
if new_len == 0 {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_address_space = AddressSpace::current()?;
|
||||||
|
let vma = current_address_space.read().mappings.contains(old_vaddr);
|
||||||
|
if vma.is_none() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
let vma = vma.unwrap();
|
||||||
|
let vm_flags = *vma.lock_irqsave().vm_flags();
|
||||||
|
|
||||||
|
// 暂时不支持巨页映射
|
||||||
|
if vm_flags.contains(VmFlags::VM_HUGETLB) {
|
||||||
|
log::error!("mmap: not support huge page mapping");
|
||||||
|
return Err(SystemError::ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩小旧内存映射区域
|
||||||
|
if old_len > new_len {
|
||||||
|
do_munmap(old_vaddr + new_len, old_len - new_len)?;
|
||||||
|
return Ok(old_vaddr.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重映射到新内存区域
|
||||||
|
let r = current_address_space.write().mremap(
|
||||||
|
old_vaddr,
|
||||||
|
old_len,
|
||||||
|
new_len,
|
||||||
|
mremap_flags,
|
||||||
|
new_vaddr,
|
||||||
|
vm_flags,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if !mremap_flags.contains(MremapFlags::MREMAP_DONTUNMAP) {
|
||||||
|
do_munmap(old_vaddr, old_len)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(r.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("old_vaddr", format!("{:#x}", Self::old_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("old_len", format!("{:#x}", Self::old_len(args))),
|
||||||
|
FormattedSyscallParam::new("new_len", format!("{:#x}", Self::new_len(args))),
|
||||||
|
FormattedSyscallParam::new("mremap_flags", format!("{:#x}", Self::mremap_flags(args))),
|
||||||
|
FormattedSyscallParam::new("new_vaddr", format!("{:#x}", Self::new_vaddr(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMremapHandle {
|
||||||
|
/// Extracts the old_vaddr argument from syscall parameters.
|
||||||
|
fn old_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the old_len argument from syscall parameters.
|
||||||
|
fn old_len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
/// Extracts the new_len argument from syscall parameters.
|
||||||
|
fn new_len(args: &[usize]) -> usize {
|
||||||
|
args[2]
|
||||||
|
}
|
||||||
|
/// Extracts the mremap_flags argument from syscall parameters.
|
||||||
|
fn mremap_flags(args: &[usize]) -> usize {
|
||||||
|
args[3]
|
||||||
|
}
|
||||||
|
/// Extracts the new_vaddr argument from syscall parameters.
|
||||||
|
fn new_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MREMAP, SysMremapHandle);
|
158
kernel/src/mm/syscall/sys_msync.rs
Normal file
158
kernel/src/mm/syscall/sys_msync.rs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
//! System call handler for the msync system call.
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::{interrupt::TrapFrame, syscall::nr::SYS_MSYNC, MMArch},
|
||||||
|
driver::base::block::SeekFrom,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::mm::{
|
||||||
|
syscall::{check_aligned, MsFlags, VmFlags},
|
||||||
|
ucontext::AddressSpace,
|
||||||
|
unlikely, verify_area, MemoryManagementArch, VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handles the msync system call.
|
||||||
|
pub struct SysMsyncHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMsyncHandle {
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
/// ## msync系统调用
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `start`:起始地址(已经对齐到页)
|
||||||
|
/// - `len`:长度(已经对齐到页)
|
||||||
|
/// - `flags`:标志
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let start = VirtAddr::new(Self::start_vaddr(args));
|
||||||
|
let len = Self::len(args);
|
||||||
|
let flags = MsFlags::from_bits_truncate(Self::flags(args));
|
||||||
|
|
||||||
|
if !start.check_aligned(MMArch::PAGE_SIZE) || !check_aligned(len, MMArch::PAGE_SIZE) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if unlikely(verify_area(start, len).is_err()) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if unlikely(len == 0) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut start = start.data();
|
||||||
|
let end = start + len;
|
||||||
|
let mut unmapped_error = Ok(0);
|
||||||
|
|
||||||
|
if !flags.intersects(MsFlags::MS_ASYNC | MsFlags::MS_INVALIDATE | MsFlags::MS_SYNC) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if flags.contains(MsFlags::MS_ASYNC | MsFlags::MS_SYNC) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if end < start {
|
||||||
|
return Err(SystemError::ENOMEM);
|
||||||
|
}
|
||||||
|
if start == end {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_address_space = AddressSpace::current()?;
|
||||||
|
let mut err = Err(SystemError::ENOMEM);
|
||||||
|
let mut next_vma = current_address_space
|
||||||
|
.read()
|
||||||
|
.mappings
|
||||||
|
.find_nearest(VirtAddr::new(start));
|
||||||
|
loop {
|
||||||
|
if let Some(vma) = next_vma.clone() {
|
||||||
|
let guard = vma.lock_irqsave();
|
||||||
|
let vm_start = guard.region().start().data();
|
||||||
|
let vm_end = guard.region().end().data();
|
||||||
|
if start < vm_start {
|
||||||
|
if flags == MsFlags::MS_ASYNC {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start = vm_start;
|
||||||
|
if start >= vm_end {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unmapped_error = Err(SystemError::ENOMEM);
|
||||||
|
}
|
||||||
|
let vm_flags = *guard.vm_flags();
|
||||||
|
if flags.contains(MsFlags::MS_INVALIDATE) && vm_flags.contains(VmFlags::VM_LOCKED) {
|
||||||
|
err = Err(SystemError::EBUSY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let file = guard.vm_file();
|
||||||
|
let fstart = (start - vm_start)
|
||||||
|
+ (guard.file_page_offset().unwrap_or(0) << MMArch::PAGE_SHIFT);
|
||||||
|
let fend = fstart + (core::cmp::min(end, vm_end) - start) - 1;
|
||||||
|
let old_start = start;
|
||||||
|
start = vm_end;
|
||||||
|
if flags.contains(MsFlags::MS_SYNC) && vm_flags.contains(VmFlags::VM_SHARED) {
|
||||||
|
if let Some(file) = file {
|
||||||
|
let old_pos = file.lseek(SeekFrom::SeekCurrent(0)).unwrap();
|
||||||
|
file.lseek(SeekFrom::SeekSet(fstart as i64)).unwrap();
|
||||||
|
err = file.write(len, unsafe {
|
||||||
|
core::slice::from_raw_parts(old_start as *mut u8, fend - fstart + 1)
|
||||||
|
});
|
||||||
|
file.lseek(SeekFrom::SeekSet(old_pos as i64)).unwrap();
|
||||||
|
if err.is_err() {
|
||||||
|
break;
|
||||||
|
} else if start >= end {
|
||||||
|
err = unmapped_error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_vma = current_address_space
|
||||||
|
.read()
|
||||||
|
.mappings
|
||||||
|
.find_nearest(VirtAddr::new(start));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if start >= end {
|
||||||
|
err = unmapped_error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_vma = current_address_space
|
||||||
|
.read()
|
||||||
|
.mappings
|
||||||
|
.find_nearest(VirtAddr::new(vm_end));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(SystemError::ENOMEM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))),
|
||||||
|
FormattedSyscallParam::new("flags", format!("{:#x}", Self::flags(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMsyncHandle {
|
||||||
|
/// Extracts the start_vaddr argument from syscall parameters.
|
||||||
|
fn start_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the len argument from syscall parameters.
|
||||||
|
fn len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
/// Extracts the flags argument from syscall parameters.
|
||||||
|
fn flags(args: &[usize]) -> usize {
|
||||||
|
args[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MSYNC, SysMsyncHandle);
|
89
kernel/src/mm/syscall/sys_munmap.rs
Normal file
89
kernel/src/mm/syscall/sys_munmap.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
//! System call handler for the munmap system call.
|
||||||
|
|
||||||
|
use crate::arch::{interrupt::TrapFrame, syscall::nr::SYS_MUNMAP};
|
||||||
|
use crate::mm::syscall::check_aligned;
|
||||||
|
use crate::mm::syscall::page_align_up;
|
||||||
|
use crate::mm::syscall::PageFrameCount;
|
||||||
|
use crate::mm::ucontext::AddressSpace;
|
||||||
|
use crate::mm::unlikely;
|
||||||
|
use crate::mm::MemoryManagementArch;
|
||||||
|
use crate::mm::{verify_area, MMArch, VirtAddr, VirtPageFrame};
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
/// ## munmap系统调用
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `start_vaddr`:取消映射的起始地址(已经对齐到页)
|
||||||
|
/// - `len`:取消映射的字节数(已经对齐到页)
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
///
|
||||||
|
/// 成功时返回0,失败时返回错误码
|
||||||
|
pub struct SysMunmapHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysMunmapHandle {
|
||||||
|
/// Returns the number of arguments this syscall takes.
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the munmap system call.
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let addr = args[0];
|
||||||
|
let len = page_align_up(args[1]);
|
||||||
|
if addr & (MMArch::PAGE_SIZE - 1) != 0 {
|
||||||
|
// The addr argument is not a multiple of the page size
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
} else {
|
||||||
|
do_munmap(VirtAddr::new(addr), len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![
|
||||||
|
FormattedSyscallParam::new("start_vaddr", format!("{:#x}", Self::start_vaddr(args))),
|
||||||
|
FormattedSyscallParam::new("len", format!("{:#x}", Self::len(args))),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysMunmapHandle {
|
||||||
|
/// Extracts the start virtual address argument from syscall parameters.
|
||||||
|
fn start_vaddr(args: &[usize]) -> usize {
|
||||||
|
args[0]
|
||||||
|
}
|
||||||
|
/// Extracts the length argument from syscall parameters.
|
||||||
|
fn len(args: &[usize]) -> usize {
|
||||||
|
args[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_MUNMAP, SysMunmapHandle);
|
||||||
|
|
||||||
|
pub(super) fn do_munmap(start_vaddr: VirtAddr, len: usize) -> Result<usize, SystemError> {
|
||||||
|
assert!(start_vaddr.check_aligned(MMArch::PAGE_SIZE));
|
||||||
|
assert!(check_aligned(len, MMArch::PAGE_SIZE));
|
||||||
|
|
||||||
|
if unlikely(verify_area(start_vaddr, len).is_err()) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
if unlikely(len == 0) {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_address_space: Arc<AddressSpace> = AddressSpace::current()?;
|
||||||
|
let start_frame = VirtPageFrame::new(start_vaddr);
|
||||||
|
let page_count = PageFrameCount::new(len / MMArch::PAGE_SIZE);
|
||||||
|
|
||||||
|
current_address_space
|
||||||
|
.write()
|
||||||
|
.munmap(start_frame, page_count)
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
return Ok(0);
|
||||||
|
}
|
53
kernel/src/mm/syscall/sys_sbrk.rs
Normal file
53
kernel/src/mm/syscall/sys_sbrk.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//! System call handler for the sbrk system call.
|
||||||
|
|
||||||
|
use crate::arch::interrupt::TrapFrame;
|
||||||
|
use crate::mm::ucontext::AddressSpace;
|
||||||
|
use crate::syscall::table::{FormattedSyscallParam, Syscall};
|
||||||
|
use crate::syscall::SYS_SBRK;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
/// Handler for the sbrk system call, which increments the program's data space (heap).
|
||||||
|
pub struct SysSbrkHandle;
|
||||||
|
|
||||||
|
impl Syscall for SysSbrkHandle {
|
||||||
|
/// Returns the number of arguments this syscall takes.
|
||||||
|
fn num_args(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the sbrk system call.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `args` - The syscall arguments, where args[0] is the increment value (isize).
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * On success, returns the previous program break (heap end) as usize.
|
||||||
|
/// * On failure, returns a SystemError.
|
||||||
|
fn handle(&self, args: &[usize], _frame: &mut TrapFrame) -> Result<usize, SystemError> {
|
||||||
|
let incr = Self::incr(args);
|
||||||
|
let address_space = AddressSpace::current()?;
|
||||||
|
assert!(address_space.read().user_mapper.utable.is_current());
|
||||||
|
let mut address_space = address_space.write();
|
||||||
|
let r = unsafe { address_space.sbrk(incr) }?;
|
||||||
|
return Ok(r.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the syscall arguments for display/debugging purposes.
|
||||||
|
fn entry_format(&self, args: &[usize]) -> Vec<FormattedSyscallParam> {
|
||||||
|
vec![FormattedSyscallParam::new(
|
||||||
|
"incr",
|
||||||
|
format!("{}", Self::incr(args)),
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysSbrkHandle {
|
||||||
|
/// Extracts the increment argument from syscall parameters.
|
||||||
|
fn incr(args: &[usize]) -> isize {
|
||||||
|
args[0] as isize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_table_macros::declare_syscall!(SYS_SBRK, SysSbrkHandle);
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
arch::syscall::nr::*,
|
arch::syscall::nr::*,
|
||||||
filesystem::vfs::syscall::PosixStatfs,
|
filesystem::vfs::syscall::PosixStatfs,
|
||||||
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
||||||
mm::{page::PAGE_4K_SIZE, syscall::MremapFlags},
|
mm::page::PAGE_4K_SIZE,
|
||||||
net::syscall::MsgHdr,
|
net::syscall::MsgHdr,
|
||||||
process::{ProcessFlags, ProcessManager},
|
process::{ProcessFlags, ProcessManager},
|
||||||
sched::{schedule, SchedMode},
|
sched::{schedule, SchedMode},
|
||||||
@ -21,13 +21,12 @@ use system_error::SystemError;
|
|||||||
use table::{syscall_table, syscall_table_init};
|
use table::{syscall_table, syscall_table_init};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, MMArch},
|
arch::interrupt::TrapFrame,
|
||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
fcntl::{AtFlags, FcntlCommand},
|
fcntl::{AtFlags, FcntlCommand},
|
||||||
syscall::{ModeType, UtimensFlags},
|
syscall::{ModeType, UtimensFlags},
|
||||||
},
|
},
|
||||||
libs::align::page_align_up,
|
mm::{verify_area, VirtAddr},
|
||||||
mm::{verify_area, MemoryManagementArch, VirtAddr},
|
|
||||||
net::syscall::SockAddr,
|
net::syscall::SockAddr,
|
||||||
time::{
|
time::{
|
||||||
syscall::{PosixTimeZone, PosixTimeval},
|
syscall::{PosixTimeZone, PosixTimeval},
|
||||||
@ -188,16 +187,6 @@ impl Syscall {
|
|||||||
Self::pwrite(fd, buf, len, offset)
|
Self::pwrite(fd, buf, len, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_BRK => {
|
|
||||||
let new_brk = VirtAddr::new(args[0]);
|
|
||||||
Self::brk(new_brk).map(|vaddr| vaddr.data())
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_SBRK => {
|
|
||||||
let increment = args[0] as isize;
|
|
||||||
Self::sbrk(increment).map(|vaddr: VirtAddr| vaddr.data())
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_REBOOT => {
|
SYS_REBOOT => {
|
||||||
let magic1 = args[0] as u32;
|
let magic1 = args[0] as u32;
|
||||||
let magic2 = args[1] as u32;
|
let magic2 = args[1] as u32;
|
||||||
@ -498,51 +487,6 @@ impl Syscall {
|
|||||||
let timezone_ptr = args[1] as *mut PosixTimeZone;
|
let timezone_ptr = args[1] as *mut PosixTimeZone;
|
||||||
Self::gettimeofday(timeval, timezone_ptr)
|
Self::gettimeofday(timeval, timezone_ptr)
|
||||||
}
|
}
|
||||||
SYS_MMAP => {
|
|
||||||
let len = page_align_up(args[1]);
|
|
||||||
let virt_addr = VirtAddr::new(args[0]);
|
|
||||||
if verify_area(virt_addr, len).is_err() {
|
|
||||||
Err(SystemError::EFAULT)
|
|
||||||
} else {
|
|
||||||
Self::mmap(
|
|
||||||
VirtAddr::new(args[0]),
|
|
||||||
len,
|
|
||||||
args[2],
|
|
||||||
args[3],
|
|
||||||
args[4] as i32,
|
|
||||||
args[5],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SYS_MREMAP => {
|
|
||||||
let old_vaddr = VirtAddr::new(args[0]);
|
|
||||||
let old_len = args[1];
|
|
||||||
let new_len = args[2];
|
|
||||||
let mremap_flags = MremapFlags::from_bits_truncate(args[3] as u8);
|
|
||||||
let new_vaddr = VirtAddr::new(args[4]);
|
|
||||||
|
|
||||||
Self::mremap(old_vaddr, old_len, new_len, mremap_flags, new_vaddr)
|
|
||||||
}
|
|
||||||
SYS_MUNMAP => {
|
|
||||||
let addr = args[0];
|
|
||||||
let len = page_align_up(args[1]);
|
|
||||||
if addr & (MMArch::PAGE_SIZE - 1) != 0 {
|
|
||||||
// The addr argument is not a multiple of the page size
|
|
||||||
Err(SystemError::EINVAL)
|
|
||||||
} else {
|
|
||||||
Self::munmap(VirtAddr::new(addr), len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SYS_MPROTECT => {
|
|
||||||
let addr = args[0];
|
|
||||||
let len = page_align_up(args[1]);
|
|
||||||
if addr & (MMArch::PAGE_SIZE - 1) != 0 {
|
|
||||||
// The addr argument is not a multiple of the page size
|
|
||||||
Err(SystemError::EINVAL)
|
|
||||||
} else {
|
|
||||||
Self::mprotect(VirtAddr::new(addr), len, args[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_GETCWD => {
|
SYS_GETCWD => {
|
||||||
let buf = args[0] as *mut u8;
|
let buf = args[0] as *mut u8;
|
||||||
@ -694,16 +638,6 @@ impl Syscall {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
SYS_MADVISE => {
|
|
||||||
let addr = args[0];
|
|
||||||
let len = page_align_up(args[1]);
|
|
||||||
if addr & (MMArch::PAGE_SIZE - 1) != 0 {
|
|
||||||
Err(SystemError::EINVAL)
|
|
||||||
} else {
|
|
||||||
Self::madvise(VirtAddr::new(addr), len, args[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_SYSLOG => {
|
SYS_SYSLOG => {
|
||||||
let syslog_action_type = args[0];
|
let syslog_action_type = args[0];
|
||||||
let buf_vaddr = args[1];
|
let buf_vaddr = args[1];
|
||||||
@ -878,12 +812,7 @@ impl Syscall {
|
|||||||
let second = args[0] as u32;
|
let second = args[0] as u32;
|
||||||
Self::alarm(second)
|
Self::alarm(second)
|
||||||
}
|
}
|
||||||
SYS_MSYNC => {
|
|
||||||
let start = page_align_up(args[0]);
|
|
||||||
let len = page_align_up(args[1]);
|
|
||||||
let flags = args[2];
|
|
||||||
Self::msync(VirtAddr::new(start), len, flags)
|
|
||||||
}
|
|
||||||
SYS_UTIMENSAT => Self::sys_utimensat(
|
SYS_UTIMENSAT => Self::sys_utimensat(
|
||||||
args[0] as i32,
|
args[0] as i32,
|
||||||
args[1] as *const u8,
|
args[1] as *const u8,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user