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:
kaleidoscope416 2025-06-05 20:06:57 +08:00 committed by GitHub
parent 8ff7cd5546
commit 0b358b9db5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 1066 additions and 729 deletions

View File

@ -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;
}
}

View 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
}
}

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);

View 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);
}

View 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);

View File

@ -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,