mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
parent
27b967a38a
commit
4cfa009b87
@ -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)]
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user