实现mremap系统调用 (#518)

* mremap系统调用
This commit is contained in:
Jomo 2024-02-19 14:54:11 +08:00 committed by GitHub
parent 27b967a38a
commit 4cfa009b87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 342 additions and 4 deletions

View File

@ -35,6 +35,45 @@ pub mod ucontext;
/// 内核INIT进程的用户地址空间结构体仅在process_init中初始化
static mut __INITIAL_PROCESS_ADDRESS_SPACE: Option<Arc<AddressSpace>> = None;
bitflags! {
/// Virtual memory flags
pub struct VmFlags:u32{
const VM_NONE = 0x00000000;
const VM_READ = 0x00000001;
const VM_WRITE = 0x00000002;
const VM_EXEC = 0x00000004;
const VM_SHARED = 0x00000008;
const VM_MAYREAD = 0x00000010;
const VM_MAYWRITE = 0x00000020;
const VM_MAYEXEC = 0x00000040;
const VM_MAYSHARE = 0x00000080;
const VM_GROWSDOWN = 0x00000100;
const VM_UFFD_MISSING = 0x00000200;
const VM_PFNMAP = 0x00000400;
const VM_UFFD_WP = 0x00001000;
const VM_LOCKED = 0x00002000;
const VM_IO = 0x00004000;
const VM_SEQ_READ = 0x00008000;
const VM_RAND_READ = 0x00010000;
const VM_DONTCOPY = 0x00020000;
const VM_DONTEXPAND = 0x00040000;
const VM_LOCKONFAULT = 0x00080000;
const VM_ACCOUNT = 0x00100000;
const VM_NORESERVE = 0x00200000;
const VM_HUGETLB = 0x00400000;
const VM_SYNC = 0x00800000;
const VM_ARCH_1 = 0x01000000;
const VM_WIPEONFORK = 0x02000000;
const VM_DONTDUMP = 0x04000000;
}
}
/// 获取内核INIT进程的用户地址空间结构体
#[allow(non_snake_case)]
#[inline(always)]

View File

@ -14,7 +14,7 @@ use crate::{
use super::{
allocator::page_frame::{PageFrameCount, VirtPageFrame},
ucontext::{AddressSpace, DEFAULT_MMAP_MIN_ADDR},
verify_area, VirtAddr,
verify_area, VirtAddr, VmFlags,
};
bitflags! {
@ -63,7 +63,93 @@ bitflags! {
/// 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 Into<MapFlags> for VmFlags {
fn into(self) -> MapFlags {
let mut map_flags = MapFlags::MAP_NONE;
if self.contains(VmFlags::VM_GROWSDOWN) {
map_flags |= MapFlags::MAP_GROWSDOWN;
}
if self.contains(VmFlags::VM_LOCKED) {
map_flags |= MapFlags::MAP_LOCKED;
}
if self.contains(VmFlags::VM_SYNC) {
map_flags |= MapFlags::MAP_SYNC;
}
map_flags
}
}
impl Into<ProtFlags> for VmFlags {
fn into(self) -> ProtFlags {
let mut prot_flags = ProtFlags::PROT_NONE;
if self.contains(VmFlags::VM_READ) {
prot_flags |= ProtFlags::PROT_READ;
}
if self.contains(VmFlags::VM_WRITE) {
prot_flags |= ProtFlags::PROT_WRITE;
}
if self.contains(VmFlags::VM_EXEC) {
prot_flags |= ProtFlags::PROT_EXEC;
}
prot_flags
}
}
@ -156,6 +242,93 @@ impl Syscall {
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().clone();
// 暂时不支持巨页映射
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系统调用
///
/// ## 参数
@ -185,6 +358,7 @@ impl Syscall {
.write()
.munmap(start_frame, page_count)
.map_err(|_| SystemError::EINVAL)?;
return Ok(0);
}

View File

@ -25,6 +25,7 @@ use crate::{
spinlock::{SpinLock, SpinLockGuard},
},
process::ProcessManager,
syscall::user_access::{UserBufferReader, UserBufferWriter},
};
use super::{
@ -32,8 +33,8 @@ use super::{
deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter,
},
page::{Flusher, InactiveFlusher, PageFlags, PageFlushAll},
syscall::{MapFlags, ProtFlags},
MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion,
syscall::{MapFlags, MremapFlags, ProtFlags},
MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags,
};
/// MMAP_MIN_ADDR的默认值
@ -177,6 +178,7 @@ impl InnerAddressSpace {
let new_vma = VMA::zeroed(
VirtPageFrame::new(vma_guard.region.start()),
PageFrameCount::new(vma_guard.region.size() / MMArch::PAGE_SIZE),
vma_guard.vm_flags().clone(),
tmp_flags,
&mut new_guard.user_mapper.utable,
(),
@ -271,6 +273,12 @@ impl InnerAddressSpace {
let len = page_align_up(len);
let vm_flags = VmFlags::from(prot_flags)
| VmFlags::from(map_flags)
| VmFlags::VM_MAYREAD
| VmFlags::VM_MAYWRITE
| VmFlags::VM_MAYEXEC;
// kdebug!("map_anonymous: len = {}", len);
let start_page: VirtPageFrame = self.mmap(
@ -279,7 +287,7 @@ impl InnerAddressSpace {
prot_flags,
map_flags,
move |page, count, flags, mapper, flusher| {
Ok(VMA::zeroed(page, count, flags, mapper, flusher)?)
Ok(VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)?)
},
)?;
@ -362,6 +370,76 @@ impl InnerAddressSpace {
return Ok(page);
}
/// 重映射内存区域
///
/// # 参数
///
/// - `old_vaddr`:原映射的起始地址
/// - `old_len`:原映射的长度
/// - `new_len`:重新映射的长度
/// - `mremap_flags`:重映射标志
/// - `new_vaddr`:重新映射的起始地址
/// - `vm_flags`:旧内存区域标志
///
/// # Returns
///
/// 返回重映射的起始虚拟页帧地址
///
/// # Errors
///
/// - `EINVAL`:参数错误
pub fn mremap(
&mut self,
old_vaddr: VirtAddr,
old_len: usize,
new_len: usize,
mremap_flags: MremapFlags,
new_vaddr: VirtAddr,
vm_flags: VmFlags,
) -> Result<VirtAddr, SystemError> {
// 检查新内存地址是否对齐
if !new_vaddr.check_aligned(MMArch::PAGE_SIZE) {
return Err(SystemError::EINVAL);
}
// 检查新、旧内存区域是否冲突
let old_region = VirtRegion::new(old_vaddr, old_len);
let new_region = VirtRegion::new(new_vaddr, new_len);
if old_region.collide(&new_region) {
return Err(SystemError::EINVAL);
}
// 取消新内存区域的原映射
if mremap_flags.contains(MremapFlags::MREMAP_FIXED) {
let start_page = VirtPageFrame::new(new_vaddr);
let page_count = PageFrameCount::from_bytes(new_len).unwrap();
self.munmap(start_page, page_count)?;
}
// 初始化映射标志
let map_flags: MapFlags = vm_flags.into();
// 初始化内存区域保护标志
let prot_flags: ProtFlags = vm_flags.into();
// 获取映射后的新内存页面
let new_page = self.map_anonymous(new_vaddr, new_len, prot_flags, map_flags, true)?;
let new_page_vaddr = new_page.virt_address();
// 拷贝旧内存区域内容到新内存区域
let old_buffer_reader =
UserBufferReader::new(old_vaddr.data() as *const u8, old_len, true)?;
let old_buf: &[u8] = old_buffer_reader.read_from_user(0)?;
let mut new_buffer_writer =
UserBufferWriter::new(new_page_vaddr.data() as *mut u8, new_len, true)?;
let new_buf: &mut [u8] = new_buffer_writer.buffer(0)?;
let len = old_buf.len().min(new_buf.len());
for i in 0..len {
new_buf[i] = old_buf[i];
}
return Ok(new_page_vaddr);
}
/// 取消进程的地址空间中的映射
///
/// # 参数
@ -660,6 +738,7 @@ impl UserMappings {
// 创建一个新的虚拟内存范围。
let region = VirtRegion::new(cmp::max(*hole_vaddr, min_vaddr), *size);
return Some(region);
}
@ -943,6 +1022,8 @@ impl LockedVMA {
pub struct VMA {
/// 虚拟内存区域对应的虚拟地址范围
region: VirtRegion,
/// 虚拟内存区域标志
vm_flags: VmFlags,
/// VMA内的页帧的标志
flags: PageFlags<MMArch>,
/// VMA内的页帧是否已经映射到页表
@ -970,10 +1051,39 @@ pub enum Provider {
#[allow(dead_code)]
impl VMA {
pub fn new(
region: VirtRegion,
vm_flags: VmFlags,
flags: PageFlags<MMArch>,
mapped: bool,
) -> Self {
VMA {
region,
vm_flags,
flags,
mapped,
user_address_space: None,
self_ref: Weak::default(),
provider: Provider::Allocated,
}
}
pub fn region(&self) -> &VirtRegion {
return &self.region;
}
pub fn vm_flags(&self) -> &VmFlags {
return &self.vm_flags;
}
pub fn set_vm_flags(&mut self, vm_flags: VmFlags) {
self.vm_flags = vm_flags;
}
pub fn set_region_size(&mut self, new_region_size: usize) {
self.region.set_size(new_region_size);
}
/// # 拷贝当前VMA的内容
///
/// ### 安全性
@ -982,6 +1092,7 @@ impl VMA {
pub unsafe fn clone(&self) -> Self {
return Self {
region: self.region,
vm_flags: self.vm_flags,
flags: self.flags,
mapped: self.mapped,
user_address_space: self.user_address_space.clone(),
@ -1057,6 +1168,7 @@ impl VMA {
phys: PhysPageFrame,
destination: VirtPageFrame,
count: PageFrameCount,
vm_flags: VmFlags,
flags: PageFlags<MMArch>,
mapper: &mut PageMapper,
mut flusher: impl Flusher<MMArch>,
@ -1086,6 +1198,7 @@ impl VMA {
let r: Arc<LockedVMA> = LockedVMA::new(VMA {
region: VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE),
vm_flags,
flags,
mapped: true,
user_address_space: None,
@ -1107,6 +1220,7 @@ impl VMA {
pub fn zeroed(
destination: VirtPageFrame,
page_count: PageFrameCount,
vm_flags: VmFlags,
flags: PageFlags<MMArch>,
mapper: &mut PageMapper,
mut flusher: impl Flusher<MMArch>,
@ -1135,6 +1249,7 @@ impl VMA {
destination.virt_address(),
page_count.data() * MMArch::PAGE_SIZE,
),
vm_flags,
flags,
mapped: true,
user_address_space: None,

View File

@ -7,6 +7,7 @@ use crate::{
arch::{ipc::signal::SigSet, syscall::nr::*},
driver::base::device::device_number::DeviceNumber,
libs::{futex::constant::FutexFlag, rand::GRandFlags},
mm::syscall::MremapFlags,
net::syscall::MsgHdr,
process::{
fork::KernelCloneArgs,
@ -612,6 +613,15 @@ impl Syscall {
)
}
}
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]);