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