Files
DragonOS/kernel/src/mm/syscall.rs
Samuel Dai 1074eb34e7 feat(filesystem): 引入Umount系统调用 (#719)
* feat(filesystem): 引入Umount系统调用

* 将所有ENOSYS误用更正

* 修复了一个使同一个挂载点可以挂载2个文件系统的bug

* 统一注释,增强程序稳定性,统一接口。注意:Umount时在fatfs的路径要使用大写,此受限于当前文件系统设计。
2024-04-15 13:02:04 +08:00

427 lines
12 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::intrinsics::unlikely;
use alloc::sync::Arc;
use system_error::SystemError;
use crate::{
arch::MMArch,
ipc::shm::ShmFlags,
kerror,
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, 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;
}
}
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;
}
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> {
// kdebug!("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 {
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)
{
kerror!(
"mmap: MAP_FIXED is not supported for address below {}",
DEFAULT_MMAP_MIN_ADDR
);
return Err(SystemError::EINVAL);
}
// 暂时不支持除匿名页以外的映射
if !map_flags.contains(MapFlags::MAP_ANONYMOUS) {
kerror!("mmap: not support file mapping");
return Err(SystemError::ENOSYS);
}
// 暂时不支持巨页映射
if map_flags.contains(MapFlags::MAP_HUGETLB) {
kerror!("mmap: not support huge page mapping");
return Err(SystemError::ENOSYS);
}
let current_address_space = AddressSpace::current()?;
let start_page = current_address_space.write().map_anonymous(
start_vaddr,
len,
prot_flags,
map_flags,
true,
)?;
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().vm_flags();
// 暂时不支持巨页映射
if vm_flags.contains(VmFlags::VM_HUGETLB) {
kerror!("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);
}
}