|
@@ -1,15 +1,20 @@
|
|
|
//! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
|
|
|
//!
|
|
|
-//! 这里假设在内核引导文件中,已经填写了前100M的页表,其中,前50M是真实映射到内存的,后面的仅仅创建了页表,表项全部为0。
|
|
|
-//! 因此这里映射内存不需要任何动态分配。
|
|
|
-//!
|
|
|
//! 映射关系为:
|
|
|
//!
|
|
|
//! 虚拟地址 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 crate::mm::{MMArch, MemoryManagementArch, PhysAddr};
|
|
|
use core::marker::PhantomData;
|
|
|
|
|
|
use super::{
|
|
@@ -18,6 +23,74 @@ use super::{
|
|
|
PageTableKind, VirtAddr,
|
|
|
};
|
|
|
|
|
|
+/// 用于存储重映射页表的位图和页面
|
|
|
+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)]
|
|
|
+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_eq!(self.bmp.get(index).unwrap(), true);
|
|
|
+ self.bmp.set(index, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// 伪分配器
|
|
|
struct PseudoAllocator<MMA> {
|
|
|
phantom: PhantomData<MMA>,
|
|
@@ -33,17 +106,26 @@ impl<MMA: MemoryManagementArch> PseudoAllocator<MMA> {
|
|
|
|
|
|
/// 为NoInitAllocator实现FrameAllocator
|
|
|
impl<MMA: MemoryManagementArch> FrameAllocator for PseudoAllocator<MMA> {
|
|
|
- unsafe fn allocate(&mut self, _count: PageFrameCount) -> Option<(PhysAddr, PageFrameCount)> {
|
|
|
- panic!("NoInitAllocator can't allocate page frame");
|
|
|
+ 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) {
|
|
|
- panic!("NoInitAllocator can't free page frame");
|
|
|
+ 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");
|
|
|
}
|
|
|
}
|