MM 子系统 API 参考手册

概述

本文档提供 MM 子系统所有公共 API 的快速参考,按模块分类并标注源代码位置。

初始化 API

mm::init()

#![allow(unused)]
fn main() {
pub fn init()
}

功能:初始化整个 MM 子系统

调用顺序

  1. 初始化物理帧分配器
  2. 初始化内核堆分配器
  3. 创建并激活内核地址空间

源代码os/src/mm/mod.rs:33

示例

#![allow(unused)]
fn main() {
fn rust_main() {
    mm::init();  // 第一个调用
    // 此后可以使用所有内存管理功能
}
}

地址抽象层 API (address/)

Paddr / Vaddr

创建

#![allow(unused)]
fn main() {
impl Paddr {
    pub fn new(value: usize) -> Self
    pub fn as_usize(&self) -> usize
}
}

源代码os/src/mm/address/address.rs:20-53

转换

#![allow(unused)]
fn main() {
impl Paddr {
    pub fn to_vaddr(self) -> Vaddr                    // 物理→虚拟
}

impl Vaddr {
    pub fn to_paddr(self) -> Paddr                    // 虚拟→物理(unsafe)
}
}

对齐

#![allow(unused)]
fn main() {
impl AlignOps for Paddr/Vaddr {
    fn is_aligned(&self, align: usize) -> bool
    fn align_up(&self, align: usize) -> Self
    fn align_down(&self, align: usize) -> Self
    fn is_page_aligned(&self) -> bool
    fn align_up_to_page(&self) -> Self
    fn align_down_to_page(&self) -> Self
}
}

源代码os/src/mm/address/operations.rs:44-75

Ppn / Vpn

创建

#![allow(unused)]
fn main() {
impl Ppn/Vpn {
    pub fn new(value: usize) -> Self
    pub fn from_addr_floor(addr: Paddr/Vaddr) -> Self  // 向下取整
    pub fn from_addr_ceil(addr: Paddr/Vaddr) -> Self   // 向上取整
}
}

源代码os/src/mm/address/page_num.rs:7-64

地址转换

#![allow(unused)]
fn main() {
impl PageNum for Ppn/Vpn {
    fn start_addr(self) -> Paddr/Vaddr    // 页起始地址
    fn end_addr(self) -> Paddr/Vaddr      // 页结束地址(下一页起始)
    fn step(self) -> Self                 // 前进一页
    fn step_back(self) -> Self            // 后退一页
    fn offset(self, offset: isize) -> Self // 偏移多页
}
}

AddressRange / PageNumRange

创建

#![allow(unused)]
fn main() {
impl<T> AddressRange<T>/PageNumRange<T> {
    pub fn new(start: T, end: T) -> Self  // [start, end) 左闭右开
    pub fn start(&self) -> T
    pub fn end(&self) -> T
    pub fn len(&self) -> usize
    pub fn is_empty(&self) -> bool
}
}

源代码os/src/mm/address/address.rs:141-233os/src/mm/address/page_num.rs:93-185

区间运算

#![allow(unused)]
fn main() {
pub fn contains(&self, item: &T) -> bool
pub fn intersects(&self, other: &Self) -> bool
pub fn intersection(&self, other: &Self) -> Option<Self>
pub fn union(&self, other: &Self) -> Option<Self>
}

重要:所有 Range 类型均为左闭右开区间 [start, end)


物理帧分配器 API (frame_allocator/)

分配

#![allow(unused)]
fn main() {
pub fn alloc_frame() -> FrameAllocResult<FrameTracker>
pub fn alloc_frames(n: usize) -> FrameAllocResult<Vec<FrameTracker>>
pub fn alloc_contig_frames(n: usize) -> FrameAllocResult<FrameRangeTracker>
pub fn alloc_contig_frames_aligned(n: usize, align: usize) -> FrameAllocResult<FrameRangeTracker>
}

源代码os/src/mm/frame_allocator/frame_allocator.rs:219-236

示例

#![allow(unused)]
fn main() {
// 单帧
let frame = alloc_frame()?;

// 10个非连续帧
let frames = alloc_frames(10)?;

// 256个连续帧(1MB)
let contig = alloc_contig_frames(256)?;

// 512个连续帧,2MB对齐
let aligned = alloc_contig_frames_aligned(512, 512)?;
}

FrameTracker

#![allow(unused)]
fn main() {
impl FrameTracker {
    pub fn ppn(&self) -> Ppn
    pub fn start_paddr(&self) -> Paddr
    pub fn as_slice<T>(&self) -> &[T]
    pub fn as_slice_mut<T>(&mut self) -> &mut [T]
}
}

源代码os/src/mm/frame_allocator/frame_allocator.rs:24-71

RAII:自动释放(Drop

FrameRangeTracker

#![allow(unused)]
fn main() {
impl FrameRangeTracker {
    pub fn start_ppn(&self) -> Ppn
    pub fn end_ppn(&self) -> Ppn
    pub fn start_paddr(&self) -> Paddr
    pub fn end_paddr(&self) -> Paddr
    pub fn iter(&self) -> impl Iterator<Item = Ppn>
}
}

源代码os/src/mm/frame_allocator/frame_allocator.rs:74-132

错误类型

#![allow(unused)]
fn main() {
pub enum FrameAllocError {
    OutOfMemory,
    InvalidAddress,
    AlignmentError,
}
}

内核堆分配器 API (global_allocator/)

初始化

#![allow(unused)]
fn main() {
pub fn init_heap()
}

功能:初始化全局堆分配器(16 MB)

源代码os/src/mm/global_allocator/global_allocator.rs:35

使用

初始化后自动支持 alloc crate:

#![allow(unused)]
fn main() {
use alloc::vec::Vec;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::collections::BTreeMap;

let v = Vec::new();
let b = Box::new(42);
let s = String::from("hello");
let m = BTreeMap::new();
}

页表抽象层 API (page_table/)

PageTableInner trait

#![allow(unused)]
fn main() {
pub trait PageTableInner<T: PageTableEntry> {
    // 常量
    const LEVELS: usize;
    const MAX_VA_BITS: usize;
    const MAX_PA_BITS: usize;

    // 生命周期
    fn new() -> Self;
    fn from_ppn(ppn: Ppn) -> Self;
    fn activate(ppn: Ppn);
    fn root_ppn(&self) -> Ppn;

    // TLB管理
    fn tlb_flush(vpn: Vpn);
    fn tlb_flush_all();

    // 映射操作
    fn map(&mut self, vpn: Vpn, ppn: Ppn, page_size: PageSize,
           flags: UniversalPTEFlag) -> PagingResult<()>;
    fn unmap(&mut self, vpn: Vpn) -> PagingResult<()>;
    fn remap(&mut self, vpn: Vpn, new_ppn: Ppn, page_size: PageSize,
             flags: UniversalPTEFlag) -> PagingResult<()>;

    // 查询
    fn translate(&self, vaddr: Vaddr) -> Option<Paddr>;
    fn walk(&self, vpn: Vpn) -> PagingResult<(Ppn, PageSize, UniversalPTEFlag)>;
}
}

源代码os/src/mm/page_table/page_table.rs:5-52

UniversalPTEFlag

#![allow(unused)]
fn main() {
impl UniversalPTEFlag {
    // 基础标志
    pub const V: Self;  // Valid
    pub const R: Self;  // Readable
    pub const W: Self;  // Writable
    pub const X: Self;  // Executable
    pub const U: Self;  // User
    pub const G: Self;  // Global
    pub const A: Self;  // Accessed
    pub const D: Self;  // Dirty

    // 预定义组合
    pub fn user_read() -> Self;      // U | R | V
    pub fn user_rw() -> Self;        // U | R | W | V
    pub fn user_rx() -> Self;        // U | R | X | V
    pub fn kernel_r() -> Self;       // R | V
    pub fn kernel_rw() -> Self;      // R | W | V
}
}

源代码os/src/mm/page_table/page_table_entry.rs:4-58

PageSize

#![allow(unused)]
fn main() {
pub enum PageSize {
    Size4K = 0x1000,
    Size2M = 0x20_0000,    // 暂时禁用
    Size1G = 0x4000_0000,  // 暂时禁用
}
}

PagingError

#![allow(unused)]
fn main() {
pub enum PagingError {
    NotMapped,
    AlreadyMapped,
    InvalidAddress,
    InvalidPageSize,
    PermissionDenied,
    PageTableFull,
    FrameAllocationFailed,
    // ... 更多
}
}

源代码os/src/mm/page_table/mod.rs:23-44


地址空间管理 API (memory_space/)

MemorySpace

创建

#![allow(unused)]
fn main() {
impl MemorySpace {
    pub fn new_kernel() -> Self              // 创建内核地址空间
    pub fn from_elf(elf_data: &[u8]) -> Self // 从ELF创建用户地址空间
}
}

源代码os/src/mm/memory_space/memory_space.rs:203-458

系统调用支持

#![allow(unused)]
fn main() {
pub fn brk(&mut self, new_end: Vaddr) -> SyscallResult<Vaddr>
pub fn mmap(&mut self, start: Vaddr, len: usize, prot: usize) -> SyscallResult<Vaddr>
pub fn munmap(&mut self, start: Vaddr, len: usize) -> SyscallResult<()>
}

进程管理

#![allow(unused)]
fn main() {
pub fn clone_for_fork(&self) -> Self           // fork时深拷贝
pub fn activate(&self)                          // 激活地址空间
pub fn root_ppn(&self) -> Ppn                   // 获取根页表页号
}

MappingArea

创建

#![allow(unused)]
fn main() {
impl MappingArea {
    pub fn new(
        vaddr_range: VaddrRange,
        map_type: MapType,
        permission: UniversalPTEFlag,
        area_type: AreaType,
    ) -> Self
}
}

源代码os/src/mm/memory_space/mapping_area.rs:62-100

映射类型

#![allow(unused)]
fn main() {
pub enum MapType {
    Direct,   // 直接映射(内核)
    Framed,   // 帧映射(用户)
}

pub enum AreaType {
    KernelText,
    KernelData,
    UserText,
    UserData,
    UserStack,
    UserHeap,
    // ...
}
}

操作

#![allow(unused)]
fn main() {
pub fn map(&mut self, page_table: &mut ActivePageTableInner) -> PagingResult<()>
pub fn unmap(&mut self, page_table: &mut ActivePageTableInner) -> PagingResult<()>
pub fn copy_data(&self, page_table: &ActivePageTableInner, data: &[u8])
pub fn extend(&mut self, page_table: &mut ActivePageTableInner,
              new_end_vpn: Vpn) -> PagingResult<()>
pub fn shrink(&mut self, page_table: &mut ActivePageTableInner,
              new_end_vpn: Vpn) -> PagingResult<()>
}

源代码os/src/mm/memory_space/mapping_area.rs:113-626


架构特定 API (arch/*/mm/)

RISC-V (arch/riscv/mm/)

地址转换

#![allow(unused)]
fn main() {
pub const unsafe fn vaddr_to_paddr(vaddr: usize) -> usize
pub const fn paddr_to_vaddr(paddr: usize) -> usize
}

源代码os/src/arch/riscv/mm/mod.rs:8-15

常量

#![allow(unused)]
fn main() {
pub const VADDR_START: usize = 0xffff_ffc0_0000_0000;
pub const PADDR_MASK: usize = 0x0000_003f_ffff_ffff;
}

SV39 PageTableInner

#![allow(unused)]
fn main() {
impl PageTableInner<PageTableEntry> for PageTableInner {
    const LEVELS: usize = 3;
    const MAX_VA_BITS: usize = 39;
    const MAX_PA_BITS: usize = 56;
    // ... trait实现
}
}

源代码os/src/arch/riscv/mm/page_table.rs:21-286


配置常量 (config.rs)

#![allow(unused)]
fn main() {
// 基础配置
pub const PAGE_SIZE: usize = 4096;
pub const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024;  // 16 MB
pub const USER_STACK_SIZE: usize = 4 * 1024 * 1024;    // 4 MB
pub const MAX_USER_HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MB

// 内存布局
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
pub const TRAP_CONTEXT: usize = TRAMPOLINE - 2 * PAGE_SIZE;
pub const USER_STACK_TOP: usize = TRAP_CONTEXT - PAGE_SIZE;

// 平台相关
pub const MEMORY_END: usize = 0x88000000;  // 128 MB
}

源代码os/src/config.rs


常用模式

模式 1:分配并映射页面

#![allow(unused)]
fn main() {
use crate::mm::frame_allocator::alloc_frame;
use crate::mm::page_table::PageSize;

let frame = alloc_frame()?;
let ppn = frame.ppn();
page_table.map(vpn, ppn, PageSize::Size4K, UniversalPTEFlag::user_rw())?;
frames.insert(vpn, TrackedFrames::Single(frame));
}

模式 2:创建用户地址空间

#![allow(unused)]
fn main() {
use crate::mm::memory_space::MemorySpace;

let elf_data = load_elf_from_disk(path)?;
let mut space = MemorySpace::from_elf(&elf_data);
space.activate();
}

模式 3:扩展堆区域

#![allow(unused)]
fn main() {
let new_end = current_end + size;
let new_end_vaddr = Vaddr::new(new_end);
space.brk(new_end_vaddr)?;
}

模式 4:地址转换

#![allow(unused)]
fn main() {
// 虚拟地址 → 物理地址
let vaddr = Vaddr::new(0xffff_ffc0_8000_1000);
let paddr = page_table.translate(vaddr).unwrap();

// 页号 → 地址
let vpn = Vpn::new(0x100);
let vaddr = vpn.start_addr();
}

快速索引

功能API源文件
初始化MMmm::init()mm/mod.rs:33
分配单帧alloc_frame()frame_allocator/frame_allocator.rs:219
分配连续帧alloc_contig_frames(n)frame_allocator/frame_allocator.rs:223
地址对齐addr.align_up_to_page()address/operations.rs:69
页号转换Ppn::from_addr_floor(paddr)address/page_num.rs:34
创建页表PageTableInner::new()arch/riscv/mm/page_table.rs:56
映射页面page_table.map(vpn, ppn, ...)page_table/page_table.rs:35
创建用户空间MemorySpace::from_elf(data)memory_space/memory_space.rs:353
扩展堆space.brk(new_end)memory_space/memory_space.rs:461
地址转换vaddr.to_paddr()address/address.rs:50

版本信息

  • 文档版本:1.0
  • Rust工具链:nightly-2025-01-13
  • 支持架构:RISC-V (SV39), LoongArch (TODO)
  • 页面大小:4KB(大页支持已暂时禁用)

相关文档

在线文档

完整的 rustdoc 文档:

cd os && cargo doc --open

生成的文档位于:target/doc/os/mm/index.html