重要结构

  • mm_struct:描述一个进程的“整个用户虚拟地址空间”的内核抽象(全局视角)。
  • vm_area_struct:描述该地址空间里的“一段连续的映射区域(VMA)”(局部视角)。
  • mm_context_tmm_context):与体系结构相关的、供硬件/MMU 使用的“地址空间硬件上下文”(架构视角),嵌在 mm_struct 里。

详情

mm_struct(进程地址空间描述符)

  • 表示一个进程(或一组共享 mm 的线程)的整个用户虚拟地址空间。
  • 关键内容:
    • VMA 集合(老内核用红黑树,近年主线用 maple tree 保存/检索)。
    • 顶级页表根(如 pgd/mm->pgd)。
    • 统计信息(RSS、swap 计数等)、mmap_lock 等地址空间级锁。
    • 引用计数(mm_users/mm_count)、属主线程、内存上限等。
    • 架构相关上下文 mm_struct::context(类型为 mm_context_t)。
  • 进程与线程关系:
    • 普通线程共享同一个 mm_struct
    • 内核线程通常 tsk->mm == NULL,借用 active_mm
  • 你可以把它理解为“这个进程的用户态内存长什么样、有哪些映射、页表在哪、怎么加锁管理”。

vm_area_struct(单个映射区域 VMA)

  • 描述虚拟地址空间中一段“连续、同属性”的内存区域,如可执行段、堆、栈、匿名映射、文件映射的一段等。
  • 关键字段(常见):
    • vm_start/vm_end:虚拟地址范围。
    • vm_flags:权限与属性(如读/写/执行、私有/共享、是否可扩展等)。
    • vm_file + vm_pgoff:若为文件映射,指向底层文件与偏移;匿名映射则没有文件。
    • vm_ops:按需缺页处理等回调。
  • 所有 VMA 共同组成 mm_struct 的完整地址空间布局。缺页异常时,内核会在 mm 的 VMA 索引结构里查找对应的 vma 来决定权限与缺页处理。

mm_context_t / mm_context(架构相关的硬件上下文)

  • 每个 mm_struct 都有一个 context 字段,类型为 mm_context_t(在各架构的 arch/*/include/asm/mmu.h 定义)。
  • 存放“硬件/MMU 需要的、与地址空间绑定的状态”,高度依赖架构:
    • 例:x86 可能包含 LDT、进程地址空间的 PCID/ASID、pkeys/PKRU 状态(见 arch/x86/include/asm/pkeys.h),以及 TLB 相关信息。
    • 例:arm64 通常包含 ASID、TTBR0 等。
  • 作用是在任务切换或 switch_mm() 时,把“这个 mm 的硬件态”正确装载到 CPU(如切换 CR3/TTBR、ASID、PKRU 等),并配合 TLB 管理。

三者关系与区别

  • 层次关系
    • mm_struct:一整个地址空间的“软件描述”。
    • vm_area_struct:该地址空间中的“一个片段”的软件描述。
    • mm_context_t:这个地址空间对应的“硬件/MMU 状态”,是 mm_struct 的一部分,但由各架构定义与使用。
  • 职责边界
    • mm_struct 负责组织/管理 VMA 集合、页表根、统计与锁。
    • vm_area_struct 负责描述具体映射区的范围、权限、来源(匿名/文件)与缺页处理方式。
    • mm_context_t 负责硬件视角的上下文(ASID/PCID/PKRU/LDT…),保证在 CPU 上正确访问该地址空间并高效管理 TLB。

生命周期与并发要点

  • 共享与引用
    • 多线程共享同一个 mm_struct 和其下所有 vm_area_struct
    • mm_context_t 随 mm_struct 的创建/销毁而初始化/清理。
    • 访问/修改 VMA 集合需使用 mm->mmap_lock(读锁查找、写锁修改)。
    • 页表修改还会用到更细粒度的页表锁。
  • 典型路径
    • 缺页异常:找到 current->mm → find_vma() 定位 vma → 检查 vm_flags → 走 vm_ops->fault 或通用缺页处理 → 建立页表项。

MPK

  • 在 x86 上,mm_context_t 会包含与内存保护键(pkeys/PKRU)相关的状态,定义见 arch/x86/include/asm/pkeys.h,管理逻辑在 arch/x86/mm/pkeys.c
  • mm_struct 的定义在 include/linux/mm_types.h,其中的 context 字段就是 mm_context_t

mm_context_t​中有两个字段:

/*
 * One bit per protection key says whether userspace can
 * use it or not.  protected by mmap_lock.
 */
u16 pkey_allocation_map; //每个pkey是否被使用,用于alloc/free
s16 execute_only_pkey; //所有xom共用一个pkey

内存保护相关系统调用

​mmap​、mprotect​会尝试分配pk来实现xom(当prot​只有PROT_EXEC​)时。如果pk已经被耗尽了,则对应内存仍可读取,且不会产生任何错误信息。

手动pk分配

使用pkey_alloc​来分配并设置一个pk的值,pkey_free​来释放。
​pkey_mprotect​来为某段内存指定pkey​编号。

内核中的相关接口实现在mm/mprotect.c​

static int do_mprotect_pkey(unsigned long start, size_t len, unsigned long prot, int pkey);
 
SYSCALL_DEFINE4(pkey_mprotect, unsigned long, start, size_t, len, unsigned long, prot, int, pkey);
 
SYSCALL_DEFINE2(pkey_alloc, unsigned long, flags, unsigned long, init_val);
 
SYSCALL_DEFINE1(pkey_free, int, pkey);