DragonOS/kernel/src/mm/no_init.rs
MemoryShore cf7f801e1d
feat(mm): 简单实现fat文件系统的文件映射 (#840)
- 添加文件映射相关接口,目前已简单实现fat文件系统的私有映射和共享映射
- 添加msync系统调用(由于当前未实现脏页自动回写,需要手动调用msync进行同步)
- 简单实现PageCache(暂时使用HashMap进行文件页号与页的映射)
- 添加新的PageFlags标志结构,原PageFlags改名为EntryFlags
- 参考linux使用protection_map映射表进行页面标志的获取
- 添加页面回收机制
- 添加页面回收内核线程
- 缺页中断使用的锁修改为irq_save; 添加脏页回写机制
- 修复do_cow_page死锁问题
- 访问非法地址时发送信号终止进程
- 修复重复插入反向vma表的错误
- 添加test_filemap文件映射测试程序
2024-09-05 00:35:27 +08:00

213 lines
6.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
//!
//! 映射关系为:
//!
//! 虚拟地址 0-100M与虚拟地址 0x8000_0000_0000 - 0x8000_0640_0000 之间具有重映射关系。
//! 也就是说他们的第二级页表在最顶级页表中占用了第0和第256个页表项。
//!
//! 对于x86:
//! 这里假设在内核引导文件中已经填写了前100M的页表其中前50M是真实映射到内存的后面的仅仅创建了页表表项全部为0。
use bitmap::{traits::BitMapOps, StaticBitmap};
use crate::{
libs::spinlock::SpinLock,
mm::{MMArch, MemoryManagementArch, PhysAddr},
};
use core::marker::PhantomData;
use super::{
allocator::page_frame::{FrameAllocator, PageFrameCount, PageFrameUsage},
page::EntryFlags,
PageTableKind, VirtAddr,
};
/// 用于存储重映射页表的位图和页面
pub static EARLY_IOREMAP_PAGES: SpinLock<EarlyIoRemapPages> =
SpinLock::new(EarlyIoRemapPages::new());
/// 早期重映射使用的页表
#[repr(C)]
#[repr(align(4096))]
#[derive(Clone, Copy)]
struct EarlyRemapPage {
data: [u64; MMArch::PAGE_SIZE],
}
impl EarlyRemapPage {
/// 清空数据
fn zero(&mut self) {
self.data.fill(0);
}
}
#[repr(C)]
pub struct EarlyIoRemapPages {
pages: [EarlyRemapPage; Self::EARLY_REMAP_PAGES_NUM],
bmp: StaticBitmap<{ Self::EARLY_REMAP_PAGES_NUM }>,
}
impl EarlyIoRemapPages {
/// 预留的用于在内存管理初始化之前,映射内存所使用的页表数量
pub const EARLY_REMAP_PAGES_NUM: usize = 256;
pub const fn new() -> Self {
Self {
pages: [EarlyRemapPage {
data: [0; MMArch::PAGE_SIZE],
}; Self::EARLY_REMAP_PAGES_NUM],
bmp: StaticBitmap::new(),
}
}
/// 分配一个页面
///
/// 如果成功,返回虚拟地址
///
/// 如果失败返回None
pub fn allocate_page(&mut self) -> Option<VirtAddr> {
if let Some(index) = self.bmp.first_false_index() {
self.bmp.set(index, true);
// 清空数据
self.pages[index].zero();
let p = &self.pages[index] as *const EarlyRemapPage as usize;
let vaddr = VirtAddr::new(p);
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
return Some(vaddr);
} else {
return None;
}
}
pub fn free_page(&mut self, addr: VirtAddr) {
// 判断地址是否合法
let start_vaddr = &self.pages[0] as *const EarlyRemapPage as usize;
let offset = addr.data() - start_vaddr;
let index = offset / MMArch::PAGE_SIZE;
if index < Self::EARLY_REMAP_PAGES_NUM {
assert!(self.bmp.get(index).unwrap());
self.bmp.set(index, false);
}
}
}
/// 伪分配器
struct PseudoAllocator<MMA> {
phantom: PhantomData<MMA>,
}
impl<MMA: MemoryManagementArch> PseudoAllocator<MMA> {
pub const fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/// 为NoInitAllocator实现FrameAllocator
impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
unsafe fn allocate(&mut self, count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
assert!(count.data() == 1);
let vaddr = EARLY_IOREMAP_PAGES.lock_irqsave().allocate_page()?;
let paddr = MMA::virt_2_phys(vaddr)?;
return Some((paddr, count));
}
unsafe fn free(&mut self, address: PhysAddr, count: PageFrameCount) {
assert_eq!(count.data(), 1);
assert!(address.check_aligned(MMA::PAGE_SIZE));
let vaddr = MMA::phys_2_virt(address);
if let Some(vaddr) = vaddr {
EARLY_IOREMAP_PAGES.lock_irqsave().free_page(vaddr);
}
}
/// @brief: 获取内存区域页帧的使用情况
/// @param self
/// @return 页帧的使用情况
unsafe fn usage(&self) -> PageFrameUsage {
// 暂时不支持
panic!("NoInitAllocator can't get page frame usage");
}
}
/// Use pseudo mapper to map physical memory to virtual memory.
///
/// ## Safety
///
/// 调用该函数时,必须保证内存管理器尚未初始化。否则将导致未定义的行为
///
/// 并且内核引导文件必须以4K页为粒度填写了前100M的内存映射关系。具体以本文件开头的注释为准
#[inline(never)]
pub unsafe fn pseudo_map_phys(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
let flags: EntryFlags<MMArch> = EntryFlags::new().set_write(true);
pseudo_map_phys_with_flags(vaddr, paddr, count, flags);
}
/// Use pseudo mapper to map physical memory to virtual memory
/// with READ_ONLY and EXECUTE flags.
#[inline(never)]
pub unsafe fn pseudo_map_phys_ro(vaddr: VirtAddr, paddr: PhysAddr, count: PageFrameCount) {
let flags: EntryFlags<MMArch> = EntryFlags::new().set_write(false).set_execute(true);
pseudo_map_phys_with_flags(vaddr, paddr, count, flags);
}
#[inline(never)]
pub unsafe fn pseudo_map_phys_with_flags(
vaddr: VirtAddr,
paddr: PhysAddr,
count: PageFrameCount,
flags: EntryFlags<MMArch>,
) {
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
assert!(paddr.check_aligned(MMArch::PAGE_SIZE));
let mut pseudo_allocator = PseudoAllocator::<MMArch>::new();
let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new(
PageTableKind::Kernel,
MMArch::table(PageTableKind::Kernel),
&mut pseudo_allocator,
);
for i in 0..count.data() {
let vaddr = vaddr + i * MMArch::PAGE_SIZE;
let paddr = paddr + i * MMArch::PAGE_SIZE;
let flusher: crate::mm::page::PageFlush<MMArch> =
mapper.map_phys(vaddr, paddr, flags).unwrap();
flusher.ignore();
}
mapper.make_current();
}
/// Unmap physical memory from virtual memory.
///
/// ## 说明
///
/// 该函数在系统启动早期,内存管理尚未初始化的时候使用
#[inline(never)]
pub unsafe fn pseudo_unmap_phys(vaddr: VirtAddr, count: PageFrameCount) {
assert!(vaddr.check_aligned(MMArch::PAGE_SIZE));
let mut pseudo_allocator = PseudoAllocator::<MMArch>::new();
let mut mapper = crate::mm::page::PageMapper::<MMArch, _>::new(
PageTableKind::Kernel,
MMArch::table(PageTableKind::Kernel),
&mut pseudo_allocator,
);
for i in 0..count.data() {
let vaddr = vaddr + i * MMArch::PAGE_SIZE;
if let Some((_, _, flusher)) = mapper.unmap_phys(vaddr, true) {
flusher.ignore();
};
}
mapper.make_current();
}