|
@@ -22,7 +22,7 @@ use crate::{
|
|
|
exception::InterruptArch,
|
|
|
libs::{
|
|
|
align::page_align_up,
|
|
|
- rwlock::{RwLock, RwLockWriteGuard},
|
|
|
+ rwlock::RwLock,
|
|
|
spinlock::{SpinLock, SpinLockGuard},
|
|
|
},
|
|
|
mm::page::page_manager_lock_irqsave,
|
|
@@ -35,7 +35,7 @@ use super::{
|
|
|
deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter,
|
|
|
},
|
|
|
page::{Flusher, InactiveFlusher, PageFlags, PageFlushAll},
|
|
|
- syscall::{MapFlags, MremapFlags, ProtFlags},
|
|
|
+ syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags},
|
|
|
MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags,
|
|
|
};
|
|
|
|
|
@@ -160,6 +160,11 @@ impl InnerAddressSpace {
|
|
|
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
|
|
let new_addr_space = AddressSpace::new(false)?;
|
|
|
let mut new_guard = new_addr_space.write();
|
|
|
+ unsafe {
|
|
|
+ new_guard
|
|
|
+ .user_mapper
|
|
|
+ .clone_from(&mut self.user_mapper, MMArch::PAGE_FAULT_ENABLED)
|
|
|
+ };
|
|
|
|
|
|
// 拷贝用户栈的结构体信息,但是不拷贝用户栈的内容(因为后面VMA的拷贝会拷贝用户栈的内容)
|
|
|
unsafe {
|
|
@@ -167,8 +172,6 @@ impl InnerAddressSpace {
|
|
|
}
|
|
|
let _current_stack_size = self.user_stack.as_ref().unwrap().stack_size();
|
|
|
|
|
|
- let current_mapper = &mut self.user_mapper.utable;
|
|
|
-
|
|
|
// 拷贝空洞
|
|
|
new_guard.mappings.vm_holes = self.mappings.vm_holes.clone();
|
|
|
|
|
@@ -176,55 +179,23 @@ impl InnerAddressSpace {
|
|
|
// TODO: 增加对VMA是否为文件映射的判断,如果是的话,就跳过
|
|
|
|
|
|
let vma_guard: SpinLockGuard<'_, VMA> = vma.lock();
|
|
|
- let old_flags = vma_guard.flags();
|
|
|
- let tmp_flags: PageFlags<MMArch> = PageFlags::new().set_write(true);
|
|
|
-
|
|
|
- // 分配内存页并创建新的VMA
|
|
|
- let new_vma = VMA::zeroed(
|
|
|
- VirtPageFrame::new(vma_guard.region.start()),
|
|
|
- PageFrameCount::new(vma_guard.region.size() / MMArch::PAGE_SIZE),
|
|
|
- *vma_guard.vm_flags(),
|
|
|
- tmp_flags,
|
|
|
- &mut new_guard.user_mapper.utable,
|
|
|
- (),
|
|
|
- )?;
|
|
|
+
|
|
|
+ // 仅拷贝VMA信息并添加反向映射,因为UserMapper克隆时已经分配了新的物理页
|
|
|
+ let new_vma = LockedVMA::new(vma_guard.clone_info_only());
|
|
|
new_guard.mappings.vmas.insert(new_vma.clone());
|
|
|
// kdebug!("new vma: {:x?}", new_vma);
|
|
|
- let mut new_vma_guard = new_vma.lock();
|
|
|
+ let new_vma_guard = new_vma.lock();
|
|
|
+ let new_mapper = &new_guard.user_mapper.utable;
|
|
|
+ let mut anon_vma_guard = page_manager_lock_irqsave();
|
|
|
for page in new_vma_guard.pages().map(|p| p.virt_address()) {
|
|
|
- // kdebug!("page: {:x?}", page);
|
|
|
- let current_frame = unsafe {
|
|
|
- MMArch::phys_2_virt(
|
|
|
- current_mapper
|
|
|
- .translate(page)
|
|
|
- .expect("VMA page not mapped")
|
|
|
- .0,
|
|
|
- )
|
|
|
- }
|
|
|
- .expect("Phys2Virt: vaddr overflow.")
|
|
|
- .data() as *mut u8;
|
|
|
-
|
|
|
- let new_frame = unsafe {
|
|
|
- MMArch::phys_2_virt(
|
|
|
- new_guard
|
|
|
- .user_mapper
|
|
|
- .utable
|
|
|
- .translate(page)
|
|
|
- .expect("VMA page not mapped")
|
|
|
- .0,
|
|
|
- )
|
|
|
- }
|
|
|
- .expect("Phys2Virt: vaddr overflow.")
|
|
|
- .data() as *mut u8;
|
|
|
-
|
|
|
- unsafe {
|
|
|
- // 拷贝数据
|
|
|
- new_frame.copy_from_nonoverlapping(current_frame, MMArch::PAGE_SIZE);
|
|
|
+ if let Some((paddr, _)) = new_mapper.translate(page) {
|
|
|
+ let page = anon_vma_guard.get_mut(&paddr);
|
|
|
+ page.insert_vma(new_vma.clone());
|
|
|
}
|
|
|
}
|
|
|
- drop(vma_guard);
|
|
|
|
|
|
- new_vma_guard.remap(old_flags, &mut new_guard.user_mapper.utable, ())?;
|
|
|
+ drop(anon_vma_guard);
|
|
|
+ drop(vma_guard);
|
|
|
drop(new_vma_guard);
|
|
|
}
|
|
|
drop(new_guard);
|
|
@@ -232,6 +203,24 @@ impl InnerAddressSpace {
|
|
|
return Ok(new_addr_space);
|
|
|
}
|
|
|
|
|
|
+ /// 拓展用户栈
|
|
|
+ /// ## 参数
|
|
|
+ ///
|
|
|
+ /// - `bytes`: 拓展大小
|
|
|
+ #[allow(dead_code)]
|
|
|
+ pub fn extend_stack(&mut self, mut bytes: usize) -> Result<(), SystemError> {
|
|
|
+ // kdebug!("extend user stack");
|
|
|
+ let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
|
|
|
+ let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN;
|
|
|
+ let stack = self.user_stack.as_mut().unwrap();
|
|
|
+
|
|
|
+ bytes = page_align_up(bytes);
|
|
|
+ stack.mapped_size += bytes;
|
|
|
+ let len = stack.stack_bottom - stack.mapped_size;
|
|
|
+ self.map_anonymous(len, bytes, prot_flags, map_flags, false, false)?;
|
|
|
+ return Ok(());
|
|
|
+ }
|
|
|
+
|
|
|
/// 判断当前的地址空间是否是当前进程的地址空间
|
|
|
#[inline]
|
|
|
pub fn is_current(&self) -> bool {
|
|
@@ -247,6 +236,7 @@ impl InnerAddressSpace {
|
|
|
/// - `prot_flags`:保护标志
|
|
|
/// - `map_flags`:映射标志
|
|
|
/// - `round_to_min`:是否将`start_vaddr`对齐到`mmap_min`,如果为`true`,则当`start_vaddr`不为0时,会对齐到`mmap_min`,否则仅向下对齐到页边界
|
|
|
+ /// - `allocate_at_once`:是否立即分配物理空间
|
|
|
///
|
|
|
/// ## 返回
|
|
|
///
|
|
@@ -258,7 +248,13 @@ impl InnerAddressSpace {
|
|
|
prot_flags: ProtFlags,
|
|
|
map_flags: MapFlags,
|
|
|
round_to_min: bool,
|
|
|
+ allocate_at_once: bool,
|
|
|
) -> Result<VirtPageFrame, SystemError> {
|
|
|
+ let allocate_at_once = if MMArch::PAGE_FAULT_ENABLED {
|
|
|
+ allocate_at_once
|
|
|
+ } else {
|
|
|
+ true
|
|
|
+ };
|
|
|
// 用于对齐hint的函数
|
|
|
let round_hint_to_min = |hint: VirtAddr| {
|
|
|
// 先把hint向下对齐到页边界
|
|
@@ -286,15 +282,38 @@ impl InnerAddressSpace {
|
|
|
|
|
|
// kdebug!("map_anonymous: len = {}", len);
|
|
|
|
|
|
- let start_page: VirtPageFrame = self.mmap(
|
|
|
- round_hint_to_min(start_vaddr),
|
|
|
- PageFrameCount::from_bytes(len).unwrap(),
|
|
|
- prot_flags,
|
|
|
- map_flags,
|
|
|
- move |page, count, flags, mapper, flusher| {
|
|
|
- VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)
|
|
|
- },
|
|
|
- )?;
|
|
|
+ let start_page: VirtPageFrame = if allocate_at_once {
|
|
|
+ self.mmap(
|
|
|
+ round_hint_to_min(start_vaddr),
|
|
|
+ PageFrameCount::from_bytes(len).unwrap(),
|
|
|
+ prot_flags,
|
|
|
+ map_flags,
|
|
|
+ move |page, count, flags, mapper, flusher| {
|
|
|
+ VMA::zeroed(page, count, vm_flags, flags, mapper, flusher)
|
|
|
+ },
|
|
|
+ )?
|
|
|
+ } else {
|
|
|
+ self.mmap(
|
|
|
+ round_hint_to_min(start_vaddr),
|
|
|
+ PageFrameCount::from_bytes(len).unwrap(),
|
|
|
+ prot_flags,
|
|
|
+ map_flags,
|
|
|
+ move |page, count, flags, _mapper, _flusher| {
|
|
|
+ Ok(LockedVMA::new(VMA {
|
|
|
+ region: VirtRegion::new(
|
|
|
+ page.virt_address(),
|
|
|
+ count.data() * MMArch::PAGE_SIZE,
|
|
|
+ ),
|
|
|
+ vm_flags,
|
|
|
+ flags,
|
|
|
+ mapped: true,
|
|
|
+ user_address_space: None,
|
|
|
+ self_ref: Weak::default(),
|
|
|
+ provider: Provider::Allocated,
|
|
|
+ }))
|
|
|
+ },
|
|
|
+ )?
|
|
|
+ };
|
|
|
|
|
|
return Ok(start_page);
|
|
|
}
|
|
@@ -428,7 +447,7 @@ impl InnerAddressSpace {
|
|
|
}
|
|
|
|
|
|
// 获取映射后的新内存页面
|
|
|
- let new_page = self.map_anonymous(new_vaddr, new_len, prot_flags, map_flags, true)?;
|
|
|
+ let new_page = self.map_anonymous(new_vaddr, new_len, prot_flags, map_flags, true, true)?;
|
|
|
let new_page_vaddr = new_page.virt_address();
|
|
|
|
|
|
// 拷贝旧内存区域内容到新内存区域
|
|
@@ -556,6 +575,47 @@ impl InnerAddressSpace {
|
|
|
return Ok(());
|
|
|
}
|
|
|
|
|
|
+ pub fn madvise(
|
|
|
+ &mut self,
|
|
|
+ start_page: VirtPageFrame,
|
|
|
+ page_count: PageFrameCount,
|
|
|
+ behavior: MadvFlags,
|
|
|
+ ) -> Result<(), SystemError> {
|
|
|
+ let (mut active, mut inactive);
|
|
|
+ let mut flusher = if self.is_current() {
|
|
|
+ active = PageFlushAll::new();
|
|
|
+ &mut active as &mut dyn Flusher<MMArch>
|
|
|
+ } else {
|
|
|
+ inactive = InactiveFlusher::new();
|
|
|
+ &mut inactive as &mut dyn Flusher<MMArch>
|
|
|
+ };
|
|
|
+
|
|
|
+ let mapper = &mut self.user_mapper.utable;
|
|
|
+
|
|
|
+ let region = VirtRegion::new(start_page.virt_address(), page_count.bytes());
|
|
|
+ let regions = self.mappings.conflicts(region).collect::<Vec<_>>();
|
|
|
+
|
|
|
+ for r in regions {
|
|
|
+ let r = *r.lock().region();
|
|
|
+ let r = self.mappings.remove_vma(&r).unwrap();
|
|
|
+
|
|
|
+ let intersection = r.lock().region().intersect(®ion).unwrap();
|
|
|
+ let split_result = r
|
|
|
+ .extract(intersection, mapper)
|
|
|
+ .expect("Failed to extract VMA");
|
|
|
+
|
|
|
+ if let Some(before) = split_result.prev {
|
|
|
+ self.mappings.insert_vma(before);
|
|
|
+ }
|
|
|
+ if let Some(after) = split_result.after {
|
|
|
+ self.mappings.insert_vma(after);
|
|
|
+ }
|
|
|
+ r.do_madvise(behavior, mapper, &mut flusher)?;
|
|
|
+ self.mappings.insert_vma(r);
|
|
|
+ }
|
|
|
+ Ok(())
|
|
|
+ }
|
|
|
+
|
|
|
/// 创建新的用户栈
|
|
|
///
|
|
|
/// ## 参数
|
|
@@ -605,7 +665,7 @@ impl InnerAddressSpace {
|
|
|
let len = new_brk - self.brk;
|
|
|
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
|
|
|
let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED;
|
|
|
- self.map_anonymous(old_brk, len, prot_flags, map_flags, true)?;
|
|
|
+ self.map_anonymous(old_brk, len, prot_flags, map_flags, true, false)?;
|
|
|
|
|
|
self.brk = new_brk;
|
|
|
return Ok(old_brk);
|
|
@@ -658,6 +718,16 @@ impl UserMapper {
|
|
|
pub fn new(utable: PageMapper) -> Self {
|
|
|
return Self { utable };
|
|
|
}
|
|
|
+
|
|
|
+ /// 拷贝用户空间映射
|
|
|
+ /// ## 参数
|
|
|
+ ///
|
|
|
+ /// - `umapper`: 要拷贝的用户空间
|
|
|
+ /// - `copy_on_write`: 是否写时复制
|
|
|
+ pub unsafe fn clone_from(&mut self, umapper: &mut Self, copy_on_write: bool) {
|
|
|
+ self.utable
|
|
|
+ .clone_user_mapping(&mut umapper.utable, copy_on_write);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl Drop for UserMapper {
|
|
@@ -710,6 +780,35 @@ impl UserMappings {
|
|
|
return None;
|
|
|
}
|
|
|
|
|
|
+ /// 向下寻找距离虚拟地址最近的VMA
|
|
|
+ /// ## 参数
|
|
|
+ ///
|
|
|
+ /// - `vaddr`: 虚拟地址
|
|
|
+ ///
|
|
|
+ /// ## 返回值
|
|
|
+ /// - Some(Arc<LockedVMA>): 虚拟地址所在的或最近的下一个VMA
|
|
|
+ /// - None: 未找到VMA
|
|
|
+ #[allow(dead_code)]
|
|
|
+ pub fn find_nearest(&self, vaddr: VirtAddr) -> Option<Arc<LockedVMA>> {
|
|
|
+ let mut nearest: Option<Arc<LockedVMA>> = None;
|
|
|
+ for v in self.vmas.iter() {
|
|
|
+ let guard = v.lock();
|
|
|
+ if guard.region.contains(vaddr) {
|
|
|
+ return Some(v.clone());
|
|
|
+ }
|
|
|
+ if guard.region.start > vaddr
|
|
|
+ && if let Some(ref nearest) = nearest {
|
|
|
+ guard.region.start < nearest.lock().region.start
|
|
|
+ } else {
|
|
|
+ true
|
|
|
+ }
|
|
|
+ {
|
|
|
+ nearest = Some(v.clone());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nearest;
|
|
|
+ }
|
|
|
+
|
|
|
/// 获取当前进程的地址空间中,与给定虚拟地址范围有重叠的VMA的迭代器。
|
|
|
pub fn conflicts(&self, request: VirtRegion) -> impl Iterator<Item = Arc<LockedVMA>> + '_ {
|
|
|
let r = self
|
|
@@ -959,6 +1058,9 @@ impl LockedVMA {
|
|
|
let mut page_manager_guard: SpinLockGuard<'_, crate::mm::page::PageManager> =
|
|
|
page_manager_lock_irqsave();
|
|
|
for page in guard.region.pages() {
|
|
|
+ if mapper.translate(page.virt_address()).is_none() {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) }
|
|
|
.expect("Failed to unmap, beacuse of some page is not mapped");
|
|
|
|
|
@@ -1065,6 +1167,39 @@ impl LockedVMA {
|
|
|
after,
|
|
|
));
|
|
|
}
|
|
|
+
|
|
|
+ /// 判断VMA是否为外部(非当前进程空间)的VMA
|
|
|
+ pub fn is_foreign(&self) -> bool {
|
|
|
+ let guard = self.lock();
|
|
|
+ if let Some(space) = guard.user_address_space.clone() {
|
|
|
+ if let Some(space) = space.upgrade() {
|
|
|
+ return AddressSpace::is_current(&space);
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 判断VMA是否可访问
|
|
|
+ pub fn is_accessible(&self) -> bool {
|
|
|
+ let guard = self.lock();
|
|
|
+ let vm_access_flags: VmFlags = VmFlags::VM_READ | VmFlags::VM_WRITE | VmFlags::VM_EXEC;
|
|
|
+ guard.vm_flags().intersects(vm_access_flags)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 判断VMA是否为匿名映射
|
|
|
+ pub fn is_anonymous(&self) -> bool {
|
|
|
+ //TODO: 实现匿名映射判断逻辑,目前仅支持匿名映射
|
|
|
+ true
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 判断VMA是否为大页映射
|
|
|
+ pub fn is_hugepage(&self) -> bool {
|
|
|
+ //TODO: 实现巨页映射判断逻辑,目前不支持巨页映射
|
|
|
+ false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
impl Drop for LockedVMA {
|
|
@@ -1182,6 +1317,18 @@ impl VMA {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ pub fn clone_info_only(&self) -> Self {
|
|
|
+ return Self {
|
|
|
+ region: self.region,
|
|
|
+ vm_flags: self.vm_flags,
|
|
|
+ flags: self.flags,
|
|
|
+ mapped: self.mapped,
|
|
|
+ user_address_space: None,
|
|
|
+ self_ref: Weak::default(),
|
|
|
+ provider: Provider::Allocated,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
#[inline(always)]
|
|
|
pub fn flags(&self) -> PageFlags<MMArch> {
|
|
|
return self.flags;
|
|
@@ -1203,15 +1350,15 @@ impl VMA {
|
|
|
assert!(self.mapped);
|
|
|
for page in self.region.pages() {
|
|
|
// kdebug!("remap page {:?}", page.virt_address());
|
|
|
- // 暂时要求所有的页帧都已经映射到页表
|
|
|
- // TODO: 引入Lazy Mapping, 通过缺页中断来映射页帧,这里就不必要求所有的页帧都已经映射到页表了
|
|
|
- let r = unsafe {
|
|
|
- mapper
|
|
|
- .remap(page.virt_address(), flags)
|
|
|
- .expect("Failed to remap, beacuse of some page is not mapped")
|
|
|
- };
|
|
|
+ if mapper.translate(page.virt_address()).is_some() {
|
|
|
+ let r = unsafe {
|
|
|
+ mapper
|
|
|
+ .remap(page.virt_address(), flags)
|
|
|
+ .expect("Failed to remap")
|
|
|
+ };
|
|
|
+ flusher.consume(r);
|
|
|
+ }
|
|
|
// kdebug!("consume page {:?}", page.virt_address());
|
|
|
- flusher.consume(r);
|
|
|
// kdebug!("remap page {:?} done", page.virt_address());
|
|
|
}
|
|
|
self.flags = flags;
|
|
@@ -1426,8 +1573,10 @@ impl UserStack {
|
|
|
let actual_stack_bottom = stack_bottom - guard_size;
|
|
|
|
|
|
let mut prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE;
|
|
|
- let map_flags =
|
|
|
- MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_FIXED_NOREPLACE;
|
|
|
+ let map_flags = MapFlags::MAP_PRIVATE
|
|
|
+ | MapFlags::MAP_ANONYMOUS
|
|
|
+ | MapFlags::MAP_FIXED_NOREPLACE
|
|
|
+ | MapFlags::MAP_GROWSDOWN;
|
|
|
// kdebug!(
|
|
|
// "map anonymous stack: {:?} {}",
|
|
|
// actual_stack_bottom,
|
|
@@ -1439,6 +1588,7 @@ impl UserStack {
|
|
|
prot_flags,
|
|
|
map_flags,
|
|
|
false,
|
|
|
+ false,
|
|
|
)?;
|
|
|
// test_buddy();
|
|
|
// 设置保护页只读
|
|
@@ -1479,7 +1629,7 @@ impl UserStack {
|
|
|
mut bytes: usize,
|
|
|
) -> Result<(), SystemError> {
|
|
|
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
|
|
|
- let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS;
|
|
|
+ let map_flags = MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS | MapFlags::MAP_GROWSDOWN;
|
|
|
|
|
|
bytes = page_align_up(bytes);
|
|
|
self.mapped_size += bytes;
|
|
@@ -1490,6 +1640,7 @@ impl UserStack {
|
|
|
prot_flags,
|
|
|
map_flags,
|
|
|
false,
|
|
|
+ false,
|
|
|
)?;
|
|
|
|
|
|
return Ok(());
|
|
@@ -1509,7 +1660,7 @@ impl UserStack {
|
|
|
#[allow(dead_code)]
|
|
|
pub fn extend(
|
|
|
&mut self,
|
|
|
- vm: &mut RwLockWriteGuard<InnerAddressSpace>,
|
|
|
+ vm: &mut InnerAddressSpace,
|
|
|
mut bytes: usize,
|
|
|
) -> Result<(), SystemError> {
|
|
|
let prot_flags = ProtFlags::PROT_READ | ProtFlags::PROT_WRITE | ProtFlags::PROT_EXEC;
|
|
@@ -1524,6 +1675,7 @@ impl UserStack {
|
|
|
prot_flags,
|
|
|
map_flags,
|
|
|
false,
|
|
|
+ false,
|
|
|
)?;
|
|
|
|
|
|
return Ok(());
|