实现页面反向映射 (#670)

* 实现页面反向映射

* 完善PAGE_MANAGER初始化时机 && 封装lock函数 && 删掉过时注释
This commit is contained in:
Jomo 2024-03-31 16:33:49 +08:00 committed by GitHub
parent 924d64de8d
commit 56cc4dbe27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 222 additions and 48 deletions

View File

@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
use crate::arch::MMArch; use crate::arch::MMArch;
use crate::mm::kernel_mapper::KernelMapper; use crate::mm::kernel_mapper::KernelMapper;
use crate::mm::page::PageFlags; use crate::mm::page::{page_manager_lock_irasave, PageFlags};
use crate::mm::{ use crate::mm::{
allocator::page_frame::{ allocator::page_frame::{
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame, allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
@ -57,7 +57,11 @@ pub unsafe fn dma_dealloc(paddr: usize, vaddr: NonNull<u8>, pages: usize) -> i32
flusher.flush(); flusher.flush();
unsafe { unsafe {
deallocate_page_frames(PhysPageFrame::new(PhysAddr::new(paddr)), page_count); deallocate_page_frames(
PhysPageFrame::new(PhysAddr::new(paddr)),
page_count,
&mut page_manager_lock_irasave(),
);
} }
return 0; return 0;
} }

View File

@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
use crate::arch::MMArch; use crate::arch::MMArch;
use crate::mm::kernel_mapper::KernelMapper; use crate::mm::kernel_mapper::KernelMapper;
use crate::mm::page::PageFlags; use crate::mm::page::{page_manager_lock_irasave, PageFlags};
use crate::mm::{ use crate::mm::{
allocator::page_frame::{ allocator::page_frame::{
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame, allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
@ -68,7 +68,11 @@ unsafe impl Hal for HalImpl {
flusher.flush(); flusher.flush();
unsafe { unsafe {
deallocate_page_frames(PhysPageFrame::new(PhysAddr::new(paddr)), page_count); deallocate_page_frames(
PhysPageFrame::new(PhysAddr::new(paddr)),
page_count,
&mut page_manager_lock_irasave(),
);
} }
return 0; return 0;
} }

View File

@ -5,6 +5,7 @@ use core::{
use crate::{ use crate::{
arch::{mm::LockedFrameAllocator, MMArch}, arch::{mm::LockedFrameAllocator, MMArch},
libs::spinlock::SpinLockGuard,
mm::{MemoryManagementArch, PhysAddr, VirtAddr}, mm::{MemoryManagementArch, PhysAddr, VirtAddr},
}; };
@ -348,8 +349,20 @@ pub unsafe fn allocate_page_frames(count: PageFrameCount) -> Option<(PhysAddr, P
/// ///
/// @param frame 要释放的第一个页帧 /// @param frame 要释放的第一个页帧
/// @param count 要释放的页帧数量 (必须是2的n次幂) /// @param count 要释放的页帧数量 (必须是2的n次幂)
pub unsafe fn deallocate_page_frames(frame: PhysPageFrame, count: PageFrameCount) { pub unsafe fn deallocate_page_frames(
frame: PhysPageFrame,
count: PageFrameCount,
page_manager: &mut SpinLockGuard<'_, crate::mm::page::PageManager>,
) {
unsafe { unsafe {
LockedFrameAllocator.free(frame.phys_address(), count); LockedFrameAllocator.free(frame.phys_address(), count);
} }
// 将已回收的物理页面对应的Page从PAGE_MANAGER中删去
let mut frame = frame;
for _ in 0..count.data() {
let paddr = frame.phys_address();
page_manager.remove_page(&paddr);
frame = frame.next();
}
} }

View File

@ -1,8 +1,11 @@
use core::{fmt::Write, sync::atomic::Ordering}; use core::{fmt::Write, sync::atomic::Ordering};
use crate::{ use crate::{
arch::MMArch, driver::serial::serial8250::send_to_default_serial8250_port, arch::MMArch,
filesystem::procfs::kmsg::kmsg_init, libs::printk::PrintkWriter, mm::mmio_buddy::mmio_init, driver::serial::serial8250::send_to_default_serial8250_port,
filesystem::procfs::kmsg::kmsg_init,
libs::printk::PrintkWriter,
mm::{mmio_buddy::mmio_init, page::page_manager_init},
}; };
use super::MemoryManagementArch; use super::MemoryManagementArch;
@ -44,6 +47,8 @@ pub unsafe fn mm_init() {
mmio_init(); mmio_init();
// enable KMSG // enable KMSG
kmsg_init(); kmsg_init();
// enable PAGE_MANAGER
page_manager_init();
MM_INIT MM_INIT
.compare_exchange( .compare_exchange(

View File

@ -6,17 +6,102 @@ use core::{
sync::atomic::{compiler_fence, Ordering}, sync::atomic::{compiler_fence, Ordering},
}; };
use alloc::sync::Arc;
use hashbrown::{HashMap, HashSet};
use crate::{ use crate::{
arch::{interrupt::ipi::send_ipi, MMArch}, arch::{interrupt::ipi::send_ipi, MMArch},
exception::ipi::{IpiKind, IpiTarget}, exception::ipi::{IpiKind, IpiTarget},
kerror, kwarn, kerror, kwarn,
libs::spinlock::{SpinLock, SpinLockGuard},
}; };
use super::{ use super::{
allocator::page_frame::FrameAllocator, syscall::ProtFlags, MemoryManagementArch, PageTableKind, allocator::page_frame::FrameAllocator, syscall::ProtFlags, ucontext::LockedVMA,
PhysAddr, VirtAddr, MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
}; };
/// 全局物理页信息管理器
pub static mut PAGE_MANAGER: Option<SpinLock<PageManager>> = None;
/// 初始化PAGE_MANAGER
pub fn page_manager_init() {
kinfo!("page_manager_init");
let page_manager = SpinLock::new(PageManager::new());
compiler_fence(Ordering::SeqCst);
unsafe { PAGE_MANAGER = Some(page_manager) };
compiler_fence(Ordering::SeqCst);
kinfo!("page_manager_init done");
}
pub fn page_manager_lock_irasave() -> SpinLockGuard<'static, PageManager> {
unsafe { PAGE_MANAGER.as_ref().unwrap().lock_irqsave() }
}
// 物理页管理器
pub struct PageManager {
phys2page: HashMap<PhysAddr, Page>,
}
impl PageManager {
pub fn new() -> Self {
Self {
phys2page: HashMap::new(),
}
}
pub fn get_mut(&mut self, paddr: &PhysAddr) -> &mut Page {
self.phys2page.get_mut(paddr).unwrap()
}
pub fn insert(&mut self, paddr: PhysAddr, page: Page) {
self.phys2page.insert(paddr, page);
}
pub fn remove_page(&mut self, paddr: &PhysAddr) {
self.phys2page.remove(paddr);
}
}
/// 物理页面信息
pub struct Page {
/// 映射计数
map_count: usize,
/// 是否为共享页
shared: bool,
/// 映射到当前page的VMA
anon_vma: HashSet<Arc<LockedVMA>>,
}
impl Page {
pub fn new(shared: bool) -> Self {
Self {
map_count: 0,
shared,
anon_vma: HashSet::new(),
}
}
/// 将vma加入anon_vma
pub fn insert_vma(&mut self, vma: Arc<LockedVMA>) {
self.anon_vma.insert(vma);
self.map_count += 1;
}
/// 将vma从anon_vma中删去
pub fn remove_vma(&mut self, vma: &LockedVMA) {
self.anon_vma.remove(vma);
self.map_count -= 1;
}
/// 判断当前物理页是否能被回
pub fn can_deallocate(&self) -> bool {
self.map_count == 0 && !self.shared
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct PageTable<Arch> { pub struct PageTable<Arch> {
/// 当前页表表示的虚拟地址空间的起始地址 /// 当前页表表示的虚拟地址空间的起始地址
@ -591,6 +676,8 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
let phys: PhysAddr = self.frame_allocator.allocate_one()?; let phys: PhysAddr = self.frame_allocator.allocate_one()?;
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
page_manager_lock_irasave().insert(phys, Page::new(false));
return self.map_phys(virt, phys, flags); return self.map_phys(virt, phys, flags);
} }

View File

@ -14,6 +14,7 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use hashbrown::HashSet; use hashbrown::HashSet;
use ida::IdAllocator;
use system_error::SystemError; use system_error::SystemError;
use crate::{ use crate::{
@ -24,6 +25,7 @@ use crate::{
rwlock::{RwLock, RwLockWriteGuard}, rwlock::{RwLock, RwLockWriteGuard},
spinlock::{SpinLock, SpinLockGuard}, spinlock::{SpinLock, SpinLockGuard},
}, },
mm::page::page_manager_lock_irasave,
process::ProcessManager, process::ProcessManager,
syscall::user_access::{UserBufferReader, UserBufferWriter}, syscall::user_access::{UserBufferReader, UserBufferWriter},
}; };
@ -50,6 +52,9 @@ use super::{
// protection by setting the value to 0. // protection by setting the value to 0.
pub const DEFAULT_MMAP_MIN_ADDR: usize = 65536; pub const DEFAULT_MMAP_MIN_ADDR: usize = 65536;
/// LockedVMA的id分配器
static LOCKEDVMA_ID_ALLOCATOR: IdAllocator = IdAllocator::new(0, usize::MAX);
#[derive(Debug)] #[derive(Debug)]
pub struct AddressSpace { pub struct AddressSpace {
inner: RwLock<InnerAddressSpace>, inner: RwLock<InnerAddressSpace>,
@ -464,7 +469,7 @@ impl InnerAddressSpace {
let r = r.lock().region; let r = r.lock().region;
let r = self.mappings.remove_vma(&r).unwrap(); let r = self.mappings.remove_vma(&r).unwrap();
let intersection = r.lock().region().intersect(&to_unmap).unwrap(); let intersection = r.lock().region().intersect(&to_unmap).unwrap();
let split_result = r.extract(intersection).unwrap(); let split_result = r.extract(intersection, &self.user_mapper.utable).unwrap();
// TODO: 当引入后备页映射后,这里需要增加通知文件的逻辑 // TODO: 当引入后备页映射后,这里需要增加通知文件的逻辑
@ -519,7 +524,9 @@ impl InnerAddressSpace {
let r = self.mappings.remove_vma(&r).unwrap(); let r = self.mappings.remove_vma(&r).unwrap();
let intersection = r.lock().region().intersect(&region).unwrap(); let intersection = r.lock().region().intersect(&region).unwrap();
let split_result = r.extract(intersection).expect("Failed to extract VMA"); let split_result = r
.extract(intersection, mapper)
.expect("Failed to extract VMA");
if let Some(before) = split_result.prev { if let Some(before) = split_result.prev {
self.mappings.insert_vma(before); self.mappings.insert_vma(before);
@ -663,6 +670,7 @@ impl Drop for UserMapper {
deallocate_page_frames( deallocate_page_frames(
PhysPageFrame::new(self.utable.table().phys()), PhysPageFrame::new(self.utable.table().phys()),
PageFrameCount::new(1), PageFrameCount::new(1),
&mut page_manager_lock_irasave(),
) )
}; };
} }
@ -870,17 +878,21 @@ impl Default for UserMappings {
/// ///
/// 备注进行性能测试看看SpinLock和RwLock哪个更快。 /// 备注进行性能测试看看SpinLock和RwLock哪个更快。
#[derive(Debug)] #[derive(Debug)]
pub struct LockedVMA(SpinLock<VMA>); pub struct LockedVMA {
/// 用于计算哈希值避免总是获取vma锁来计算哈希值
id: usize,
vma: SpinLock<VMA>,
}
impl core::hash::Hash for LockedVMA { impl core::hash::Hash for LockedVMA {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.0.lock().hash(state); self.id.hash(state);
} }
} }
impl PartialEq for LockedVMA { impl PartialEq for LockedVMA {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.0.lock().eq(&other.0.lock()) self.id.eq(&other.id)
} }
} }
@ -889,13 +901,16 @@ impl Eq for LockedVMA {}
#[allow(dead_code)] #[allow(dead_code)]
impl LockedVMA { impl LockedVMA {
pub fn new(vma: VMA) -> Arc<Self> { pub fn new(vma: VMA) -> Arc<Self> {
let r = Arc::new(Self(SpinLock::new(vma))); let r = Arc::new(Self {
r.0.lock().self_ref = Arc::downgrade(&r); id: LOCKEDVMA_ID_ALLOCATOR.alloc().unwrap(),
vma: SpinLock::new(vma),
});
r.vma.lock().self_ref = Arc::downgrade(&r);
return r; return r;
} }
pub fn lock(&self) -> SpinLockGuard<VMA> { pub fn lock(&self) -> SpinLockGuard<VMA> {
return self.0.lock(); return self.vma.lock();
} }
/// 调整当前VMA的页面的标志位 /// 调整当前VMA的页面的标志位
@ -933,19 +948,28 @@ impl LockedVMA {
let mut guard = self.lock(); let mut guard = self.lock();
assert!(guard.mapped); assert!(guard.mapped);
// 获取物理页的anon_vma的守卫
let mut anon_vma_guard: SpinLockGuard<'_, crate::mm::page::PageManager> =
page_manager_lock_irasave();
for page in guard.region.pages() { for page in guard.region.pages() {
let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) } let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) }
.expect("Failed to unmap, beacuse of some page is not mapped"); .expect("Failed to unmap, beacuse of some page is not mapped");
// todo: 获取物理页的anon_vma的守卫 // 从anon_vma中删除当前VMA
let page = anon_vma_guard.get_mut(&paddr);
page.remove_vma(self);
// todo: 从anon_vma中删除当前VMA // 如果物理页的anon_vma链表长度为0并且不是共享页则释放物理页.
if page.can_deallocate() {
// todo: 如果物理页的anon_vma链表长度为0则释放物理页. unsafe {
deallocate_page_frames(
// 目前由于还没有实现共享页,所以直接释放物理页也没问题。 PhysPageFrame::new(paddr),
// 但是在实现共享页之后就不能直接释放物理页了需要在anon_vma链表长度为0的时候才能释放物理页 PageFrameCount::new(1),
unsafe { deallocate_page_frames(PhysPageFrame::new(paddr), PageFrameCount::new(1)) }; &mut anon_vma_guard,
)
};
}
flusher.consume(flush); flusher.consume(flush);
} }
@ -953,7 +977,7 @@ impl LockedVMA {
} }
pub fn mapped(&self) -> bool { pub fn mapped(&self) -> bool {
return self.0.lock().mapped; return self.vma.lock().mapped;
} }
/// 将当前VMA进行切分切分成3个VMA分别是 /// 将当前VMA进行切分切分成3个VMA分别是
@ -961,7 +985,7 @@ impl LockedVMA {
/// 1. 前面的VMA如果没有则为None /// 1. 前面的VMA如果没有则为None
/// 2. 中间的VMA也就是传入的Region /// 2. 中间的VMA也就是传入的Region
/// 3. 后面的VMA如果没有则为None /// 3. 后面的VMA如果没有则为None
pub fn extract(&self, region: VirtRegion) -> Option<VMASplitResult> { pub fn extract(&self, region: VirtRegion, utable: &PageMapper) -> Option<VMASplitResult> {
assert!(region.start().check_aligned(MMArch::PAGE_SIZE)); assert!(region.start().check_aligned(MMArch::PAGE_SIZE));
assert!(region.end().check_aligned(MMArch::PAGE_SIZE)); assert!(region.end().check_aligned(MMArch::PAGE_SIZE));
@ -1005,9 +1029,29 @@ impl LockedVMA {
vma vma
}); });
guard.region = region; // 重新设置before、after这两个VMA里面的物理页的anon_vma
let mut anon_vma_guard = page_manager_lock_irasave();
if let Some(before) = before.clone() {
let virt_iter = before.lock().region.iter_pages();
for frame in virt_iter {
let paddr = utable.translate(frame.virt_address()).unwrap().0;
let page = anon_vma_guard.get_mut(&paddr);
page.insert_vma(before.clone());
page.remove_vma(self);
}
}
// TODO: 重新设置before、after这两个VMA里面的物理页的anon_vma if let Some(after) = after.clone() {
let virt_iter = after.lock().region.iter_pages();
for frame in virt_iter {
let paddr = utable.translate(frame.virt_address()).unwrap().0;
let page = anon_vma_guard.get_mut(&paddr);
page.insert_vma(after.clone());
page.remove_vma(self);
}
}
guard.region = region;
return Some(VMASplitResult::new( return Some(VMASplitResult::new(
before, before,
@ -1017,6 +1061,12 @@ impl LockedVMA {
} }
} }
impl Drop for LockedVMA {
fn drop(&mut self) {
LOCKEDVMA_ID_ALLOCATOR.free(self.id);
}
}
/// VMA切分结果 /// VMA切分结果
pub struct VMASplitResult { pub struct VMASplitResult {
pub prev: Option<Arc<LockedVMA>>, pub prev: Option<Arc<LockedVMA>>,
@ -1194,27 +1244,22 @@ impl VMA {
mapper: &mut PageMapper, mapper: &mut PageMapper,
mut flusher: impl Flusher<MMArch>, mut flusher: impl Flusher<MMArch>,
) -> Result<Arc<LockedVMA>, SystemError> { ) -> Result<Arc<LockedVMA>, SystemError> {
{ let mut cur_phy = phys;
let mut cur_phy = phys; let mut cur_dest = destination;
let mut cur_dest = destination;
for _ in 0..count.data() { for _ in 0..count.data() {
// 将物理页帧映射到虚拟页帧 // 将物理页帧映射到虚拟页帧
let r = unsafe { let r =
mapper.map_phys(cur_dest.virt_address(), cur_phy.phys_address(), flags) unsafe { mapper.map_phys(cur_dest.virt_address(), cur_phy.phys_address(), flags) }
} .expect("Failed to map phys, may be OOM error");
.expect("Failed to map phys, may be OOM error");
// todo: 增加OOM处理 // todo: 增加OOM处理
// todo: 将VMA加入到anon_vma中 // 刷新TLB
flusher.consume(r);
// 刷新TLB cur_phy = cur_phy.next();
flusher.consume(r); cur_dest = cur_dest.next();
cur_phy = cur_phy.next();
cur_dest = cur_dest.next();
}
} }
let r: Arc<LockedVMA> = LockedVMA::new(VMA { let r: Arc<LockedVMA> = LockedVMA::new(VMA {
@ -1226,6 +1271,17 @@ impl VMA {
self_ref: Weak::default(), self_ref: Weak::default(),
provider: Provider::Allocated, provider: Provider::Allocated,
}); });
// 将VMA加入到anon_vma中
let mut anon_vma_guard = page_manager_lock_irasave();
cur_phy = phys;
for _ in 0..count.data() {
let paddr = cur_phy.phys_address();
let page = anon_vma_guard.get_mut(&paddr);
page.insert_vma(r.clone());
cur_phy = cur_phy.next();
}
return Ok(r); return Ok(r);
} }
@ -1258,7 +1314,6 @@ impl VMA {
// ); // );
let r = unsafe { mapper.map(cur_dest.virt_address(), flags) } let r = unsafe { mapper.map(cur_dest.virt_address(), flags) }
.expect("Failed to map zero, may be OOM error"); .expect("Failed to map zero, may be OOM error");
// todo: 将VMA加入到anon_vma中
// todo: 增加OOM处理 // todo: 增加OOM处理
// 稍后再刷新TLB这里取消刷新 // 稍后再刷新TLB这里取消刷新
@ -1280,12 +1335,18 @@ impl VMA {
drop(flusher); drop(flusher);
// kdebug!("VMA::zeroed: flusher dropped"); // kdebug!("VMA::zeroed: flusher dropped");
// 清空这些内存 // 清空这些内存并将VMA加入到anon_vma中
let mut anon_vma_guard = page_manager_lock_irasave();
let virt_iter: VirtPageFrameIter = let virt_iter: VirtPageFrameIter =
VirtPageFrameIter::new(destination, destination.add(page_count)); VirtPageFrameIter::new(destination, destination.add(page_count));
for frame in virt_iter { for frame in virt_iter {
let paddr = mapper.translate(frame.virt_address()).unwrap().0; let paddr = mapper.translate(frame.virt_address()).unwrap().0;
// 将VMA加入到anon_vma
let page = anon_vma_guard.get_mut(&paddr);
page.insert_vma(r.clone());
// 清空内存
unsafe { unsafe {
let vaddr = MMArch::phys_2_virt(paddr).unwrap(); let vaddr = MMArch::phys_2_virt(paddr).unwrap();
MMArch::write_bytes(vaddr, 0, MMArch::PAGE_SIZE); MMArch::write_bytes(vaddr, 0, MMArch::PAGE_SIZE);