os/mm/
mod.rs

1#![allow(dead_code)]
2//! 内存管理模块
3//!
4//! 本模块为内核提供与体系结构无关的内存管理抽象和实现。
5//!
6//! # 模块组成
7//!
8//! - [`address`]:地址和页号抽象。
9//! - [`frame_allocator`]:物理帧分配。
10//! - [`mod@global_allocator`]:全局堆分配器。
11//! - [`memory_space`]:内存空间管理。
12//! - [`page_table`]:页表抽象和实现(与架构无关)。
13
14pub mod address;
15pub mod frame_allocator;
16pub mod global_allocator;
17pub mod memory_space;
18pub mod page_table;
19
20pub use frame_allocator::init_frame_allocator;
21pub use global_allocator::init_heap;
22
23use crate::arch::mm::vaddr_to_paddr;
24use crate::config::{MEMORY_END, PAGE_SIZE};
25use crate::mm::address::{Ppn, UsizeConvert};
26use crate::println;
27
28unsafe extern "C" {
29    // 链接器脚本中定义的内核结束地址
30    fn ekernel();
31}
32
33/// 初始化内存管理子系统
34///
35/// 此函数执行所有内存管理组件的初始化工作:
36/// 1. 初始化物理帧分配器。
37/// 2. 初始化内核堆分配器。
38/// 3. 创建并激活内核地址空间。
39pub fn init() {
40    // 1. 初始化物理帧分配器
41
42    // ekernel 是一个虚拟地址,需要转换为物理地址,以确定可分配物理内存的起始点。
43    let ekernel_paddr = unsafe { vaddr_to_paddr(ekernel as usize) };
44
45    // 计算页对齐后的物理内存起始地址。
46    // 分配器将管理 [start, end) 范围内的内存。
47    let start = ekernel_paddr.div_ceil(PAGE_SIZE) * PAGE_SIZE; // 页对齐
48
49    let end = MEMORY_END;
50
51    // 初始化物理帧分配器
52    init_frame_allocator(start, end);
53
54    // 2. 初始化堆分配器
55    init_heap();
56
57    // 3. 创建并激活内核地址空间 (内核地址空间通过 lazy_static 自动初始化)
58    #[cfg(target_arch = "riscv64")]
59    {
60        use alloc::sync::Arc;
61
62        use crate::{
63            earlyprintln, kernel::current_cpu, mm::memory_space::MemorySpace, sync::SpinLock,
64        };
65
66        // 记录切换前的 satp 值
67        let old_satp: usize;
68        unsafe {
69            core::arch::asm!("csrr {0}, satp", out(reg) old_satp);
70        }
71        earlyprintln!("[MM] Before space switch - satp: 0x{:x}", old_satp);
72
73        let space = Arc::new(SpinLock::new(MemorySpace::new_kernel()));
74        let root_ppn = space.lock().root_ppn();
75        earlyprintln!(
76            "[MM] New kernel space root PPN: 0x{:x}",
77            root_ppn.as_usize()
78        );
79
80        current_cpu().lock().switch_space(space);
81
82        // 记录切换后的 satp 值
83        let new_satp: usize;
84        unsafe {
85            core::arch::asm!("csrr {0}, satp", out(reg) new_satp);
86        }
87        earlyprintln!("[MM] After space switch - satp: 0x{:x}", new_satp);
88        earlyprintln!(
89            "[MM] Expected satp: 0x{:x}",
90            (root_ppn.as_usize() | (8 << 60))
91        );
92    }
93}
94
95/// 激活指定的地址空间
96///
97/// 通过将根页表(Page Table Root)的物理页号写入特定的寄存器,
98/// 从而切换当前 CPU 使用的地址空间。
99///
100/// # 参数
101///
102/// * `root_ppn` - 新地址空间的根页表的物理页号。
103pub fn activate(root_ppn: Ppn) {
104    use crate::mm::page_table::PageTableInner as PageTableInnerTrait;
105    // 调用特定架构的页表激活函数,例如在 RISC-V 上设置 SATP 寄存器。
106    crate::arch::mm::PageTableInner::activate(root_ppn);
107}