mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
parent
924d64de8d
commit
56cc4dbe27
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::PageFlags;
|
||||
use crate::mm::page::{page_manager_lock_irasave, PageFlags};
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::PageFlags;
|
||||
use crate::mm::page::{page_manager_lock_irasave, PageFlags};
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
|
||||
@ -68,7 +68,11 @@ unsafe impl Hal for HalImpl {
|
||||
flusher.flush();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use core::{
|
||||
|
||||
use crate::{
|
||||
arch::{mm::LockedFrameAllocator, MMArch},
|
||||
libs::spinlock::SpinLockGuard,
|
||||
mm::{MemoryManagementArch, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
@ -348,8 +349,20 @@ pub unsafe fn allocate_page_frames(count: PageFrameCount) -> Option<(PhysAddr, P
|
||||
///
|
||||
/// @param frame 要释放的第一个页帧
|
||||
/// @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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
use core::{fmt::Write, sync::atomic::Ordering};
|
||||
|
||||
use crate::{
|
||||
arch::MMArch, driver::serial::serial8250::send_to_default_serial8250_port,
|
||||
filesystem::procfs::kmsg::kmsg_init, libs::printk::PrintkWriter, mm::mmio_buddy::mmio_init,
|
||||
arch::MMArch,
|
||||
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;
|
||||
@ -44,6 +47,8 @@ pub unsafe fn mm_init() {
|
||||
mmio_init();
|
||||
// enable KMSG
|
||||
kmsg_init();
|
||||
// enable PAGE_MANAGER
|
||||
page_manager_init();
|
||||
|
||||
MM_INIT
|
||||
.compare_exchange(
|
||||
|
@ -6,17 +6,102 @@ use core::{
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::ipi::send_ipi, MMArch},
|
||||
exception::ipi::{IpiKind, IpiTarget},
|
||||
kerror, kwarn,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
};
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::FrameAllocator, syscall::ProtFlags, MemoryManagementArch, PageTableKind,
|
||||
PhysAddr, VirtAddr,
|
||||
allocator::page_frame::FrameAllocator, syscall::ProtFlags, ucontext::LockedVMA,
|
||||
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)]
|
||||
pub struct PageTable<Arch> {
|
||||
/// 当前页表表示的虚拟地址空间的起始地址
|
||||
@ -591,6 +676,8 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let phys: PhysAddr = self.frame_allocator.allocate_one()?;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
page_manager_lock_irasave().insert(phys, Page::new(false));
|
||||
return self.map_phys(virt, phys, flags);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ use alloc::{
|
||||
vec::Vec,
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use ida::IdAllocator;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
@ -24,6 +25,7 @@ use crate::{
|
||||
rwlock::{RwLock, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
mm::page::page_manager_lock_irasave,
|
||||
process::ProcessManager,
|
||||
syscall::user_access::{UserBufferReader, UserBufferWriter},
|
||||
};
|
||||
@ -50,6 +52,9 @@ use super::{
|
||||
// protection by setting the value to 0.
|
||||
pub const DEFAULT_MMAP_MIN_ADDR: usize = 65536;
|
||||
|
||||
/// LockedVMA的id分配器
|
||||
static LOCKEDVMA_ID_ALLOCATOR: IdAllocator = IdAllocator::new(0, usize::MAX);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AddressSpace {
|
||||
inner: RwLock<InnerAddressSpace>,
|
||||
@ -464,7 +469,7 @@ impl InnerAddressSpace {
|
||||
let r = r.lock().region;
|
||||
let r = self.mappings.remove_vma(&r).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: 当引入后备页映射后,这里需要增加通知文件的逻辑
|
||||
|
||||
@ -519,7 +524,9 @@ impl InnerAddressSpace {
|
||||
let r = self.mappings.remove_vma(&r).unwrap();
|
||||
|
||||
let intersection = r.lock().region().intersect(®ion).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 {
|
||||
self.mappings.insert_vma(before);
|
||||
@ -663,6 +670,7 @@ impl Drop for UserMapper {
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(self.utable.table().phys()),
|
||||
PageFrameCount::new(1),
|
||||
&mut page_manager_lock_irasave(),
|
||||
)
|
||||
};
|
||||
}
|
||||
@ -870,17 +878,21 @@ impl Default for UserMappings {
|
||||
///
|
||||
/// 备注:进行性能测试,看看SpinLock和RwLock哪个更快。
|
||||
#[derive(Debug)]
|
||||
pub struct LockedVMA(SpinLock<VMA>);
|
||||
pub struct LockedVMA {
|
||||
/// 用于计算哈希值,避免总是获取vma锁来计算哈希值
|
||||
id: usize,
|
||||
vma: SpinLock<VMA>,
|
||||
}
|
||||
|
||||
impl core::hash::Hash for LockedVMA {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.lock().hash(state);
|
||||
self.id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for LockedVMA {
|
||||
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)]
|
||||
impl LockedVMA {
|
||||
pub fn new(vma: VMA) -> Arc<Self> {
|
||||
let r = Arc::new(Self(SpinLock::new(vma)));
|
||||
r.0.lock().self_ref = Arc::downgrade(&r);
|
||||
let r = Arc::new(Self {
|
||||
id: LOCKEDVMA_ID_ALLOCATOR.alloc().unwrap(),
|
||||
vma: SpinLock::new(vma),
|
||||
});
|
||||
r.vma.lock().self_ref = Arc::downgrade(&r);
|
||||
return r;
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> SpinLockGuard<VMA> {
|
||||
return self.0.lock();
|
||||
return self.vma.lock();
|
||||
}
|
||||
|
||||
/// 调整当前VMA的页面的标志位
|
||||
@ -933,19 +948,28 @@ impl LockedVMA {
|
||||
|
||||
let mut guard = self.lock();
|
||||
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() {
|
||||
let (paddr, _, flush) = unsafe { mapper.unmap_phys(page.virt_address(), true) }
|
||||
.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
|
||||
|
||||
// todo: 如果物理页的anon_vma链表长度为0,则释放物理页.
|
||||
|
||||
// 目前由于还没有实现共享页,所以直接释放物理页也没问题。
|
||||
// 但是在实现共享页之后,就不能直接释放物理页了,需要在anon_vma链表长度为0的时候才能释放物理页
|
||||
unsafe { deallocate_page_frames(PhysPageFrame::new(paddr), PageFrameCount::new(1)) };
|
||||
// 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页.
|
||||
if page.can_deallocate() {
|
||||
unsafe {
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(paddr),
|
||||
PageFrameCount::new(1),
|
||||
&mut anon_vma_guard,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
flusher.consume(flush);
|
||||
}
|
||||
@ -953,7 +977,7 @@ impl LockedVMA {
|
||||
}
|
||||
|
||||
pub fn mapped(&self) -> bool {
|
||||
return self.0.lock().mapped;
|
||||
return self.vma.lock().mapped;
|
||||
}
|
||||
|
||||
/// 将当前VMA进行切分,切分成3个VMA,分别是:
|
||||
@ -961,7 +985,7 @@ impl LockedVMA {
|
||||
/// 1. 前面的VMA,如果没有则为None
|
||||
/// 2. 中间的VMA,也就是传入的Region
|
||||
/// 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.end().check_aligned(MMArch::PAGE_SIZE));
|
||||
|
||||
@ -1005,9 +1029,29 @@ impl LockedVMA {
|
||||
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(
|
||||
before,
|
||||
@ -1017,6 +1061,12 @@ impl LockedVMA {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LockedVMA {
|
||||
fn drop(&mut self) {
|
||||
LOCKEDVMA_ID_ALLOCATOR.free(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
/// VMA切分结果
|
||||
pub struct VMASplitResult {
|
||||
pub prev: Option<Arc<LockedVMA>>,
|
||||
@ -1194,27 +1244,22 @@ impl VMA {
|
||||
mapper: &mut PageMapper,
|
||||
mut flusher: impl Flusher<MMArch>,
|
||||
) -> Result<Arc<LockedVMA>, SystemError> {
|
||||
{
|
||||
let mut cur_phy = phys;
|
||||
let mut cur_dest = destination;
|
||||
let mut cur_phy = phys;
|
||||
let mut cur_dest = destination;
|
||||
|
||||
for _ in 0..count.data() {
|
||||
// 将物理页帧映射到虚拟页帧
|
||||
let r = unsafe {
|
||||
mapper.map_phys(cur_dest.virt_address(), cur_phy.phys_address(), flags)
|
||||
}
|
||||
.expect("Failed to map phys, may be OOM error");
|
||||
for _ in 0..count.data() {
|
||||
// 将物理页帧映射到虚拟页帧
|
||||
let r =
|
||||
unsafe { mapper.map_phys(cur_dest.virt_address(), cur_phy.phys_address(), flags) }
|
||||
.expect("Failed to map phys, may be OOM error");
|
||||
|
||||
// todo: 增加OOM处理
|
||||
// todo: 增加OOM处理
|
||||
|
||||
// todo: 将VMA加入到anon_vma中
|
||||
// 刷新TLB
|
||||
flusher.consume(r);
|
||||
|
||||
// 刷新TLB
|
||||
flusher.consume(r);
|
||||
|
||||
cur_phy = cur_phy.next();
|
||||
cur_dest = cur_dest.next();
|
||||
}
|
||||
cur_phy = cur_phy.next();
|
||||
cur_dest = cur_dest.next();
|
||||
}
|
||||
|
||||
let r: Arc<LockedVMA> = LockedVMA::new(VMA {
|
||||
@ -1226,6 +1271,17 @@ impl VMA {
|
||||
self_ref: Weak::default(),
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1258,7 +1314,6 @@ impl VMA {
|
||||
// );
|
||||
let r = unsafe { mapper.map(cur_dest.virt_address(), flags) }
|
||||
.expect("Failed to map zero, may be OOM error");
|
||||
// todo: 将VMA加入到anon_vma中
|
||||
// todo: 增加OOM处理
|
||||
|
||||
// 稍后再刷新TLB,这里取消刷新
|
||||
@ -1280,12 +1335,18 @@ impl VMA {
|
||||
drop(flusher);
|
||||
// kdebug!("VMA::zeroed: flusher dropped");
|
||||
|
||||
// 清空这些内存
|
||||
// 清空这些内存并将VMA加入到anon_vma中
|
||||
let mut anon_vma_guard = page_manager_lock_irasave();
|
||||
let virt_iter: VirtPageFrameIter =
|
||||
VirtPageFrameIter::new(destination, destination.add(page_count));
|
||||
for frame in virt_iter {
|
||||
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 {
|
||||
let vaddr = MMArch::phys_2_virt(paddr).unwrap();
|
||||
MMArch::write_bytes(vaddr, 0, MMArch::PAGE_SIZE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user