MM 学习笔记 01:miarm.h 核心头文件分析

MM 学习笔记 01:miarm.h 核心头文件分析

概述

miarm.hntoskrnl/mm/ARM3/miarm.h)是整个 MM 子系统的核心头文件。它零外部依赖(无 #include),定义了所有 ARM3 源文件共享的常量、宏、类型和全局变量声明。


1. 基础常量

1.1 容量常量

c 复制代码
#define _1KB (1024u)
#define _1MB (1024 * _1KB)
#define _1GB (1024 * _1MB)
#define _64K (64 * _1KB)
#define PT_SIZE  (PTE_PER_PAGE * sizeof(MMPTE))  // 页表大小
#define PD_SIZE  (PDE_PER_PAGE * sizeof(MMPDE))  // 页目录大小
#define SYSTEM_PD_SIZE (PPE_PER_PAGE * PD_SIZE)  // 进程的完整页目录大小

1.2 内存保护常量(内部保护掩码)

保护值编码为 3 位访问位 + 2 位特殊标志位:

含义
MM_ZERO_ACCESS 0 无访问(请求零页)
MM_READONLY 1 只读
MM_EXECUTE 2 仅执行
MM_EXECUTE_READ 3 执行+读
MM_READWRITE 4 读写
MM_WRITECOPY 5 写时复制
MM_EXECUTE_READWRITE 6 执行+读写
MM_EXECUTE_WRITECOPY 7 执行+写时复制
MM_NOCACHE 0x08 禁止缓存
MM_GUARDPAGE 0x10 警戒页
MM_WRITECOMBINE 0x18 写合并
MM_DECOMMIT 0x10 解除提交
MM_NOACCESS 0x18 无访问
MM_OUTSWAPPED_KSTACK 0x17 内核栈已换出
MM_INVALID_PROTECTION 0xFFFFFFFF 无效保护

1.3 架构相关的 PTE 标志

x86 32位:

c 复制代码
#define PTE_VALID               0x1      // 有效位(存在位)
#define PTE_READWRITE           0x2      // 可写
#define PTE_PROTOTYPE           0x400    // 原型 PTE
#define PTE_ACCESSED            0x20     // 已访问
#define PTE_DIRTY               0x40     // 已修改
#define PTE_DISABLE_CACHE       0x10     // 禁用缓存
#define PTE_PROTECT_MASK        0x612    // 保护掩码

x86-64(注意高位的 NX 位):

c 复制代码
#define PTE_READONLY            0x8000000000000000ULL  // NX 位
#define PTE_READWRITE           0x8000000000000002ULL
#define PTE_EXECUTE_READWRITE   0x0000000000000002ULL

ARM:

c 复制代码
#define PTE_READONLY            0x200
#define PTE_PROTOTYPE           0x400   // 使用共享位

2. 关键结构体(在 miarm.h 中声明,在其他文件中定义)

2.1 POOL_DESCRIPTOR --- 池描述符

定义在 miarm.h 中(非 ARM3 的其他文件也使用此结构):

c 复制代码
typedef struct _POOL_DESCRIPTOR
{
    POOL_TYPE PoolType;          // 池类型(分页/非分页)
    ULONG PoolIndex;             // 池索引
    ULONG RunningAllocs;         // 累计分配计数
    ULONG RunningDeAllocs;       // 累计释放计数
    ULONG TotalPages;            // 总页数
    ULONG TotalBigPages;         // 大页面数
    ULONG Threshold;             // 阈值
    PVOID LockAddress;           // 锁地址
    PVOID PendingFrees;          // 待释放链表
    LONG PendingFreeDepth;       // 待释放深度
    SIZE_T TotalBytes;           // 总字节数
    SIZE_T Spare0;
    LIST_ENTRY ListHeads[POOL_LISTS_PER_PAGE]; // 列表头(256个)
} POOL_DESCRIPTOR, *PPOOL_DESCRIPTOR;

关键理解:

  • ListHeadsPAGE_SIZE / 8 = 512(32位)或 PAGE_SIZE / 16 = 256(64位)个桶
  • 每个桶对应一个固定大小的块范围(8 或 16 字节粒度)
  • Threshold 决定何时切换到大页面分配模式

2.2 POOL_HEADER --- 池头部

每个分配块前有 8 字节头部:

复制代码
32位: PreviousSize:9 | PoolIndex:7 | BlockSize:9 | PoolType:7
64位: PreviousSize:8 | PoolIndex:8 | BlockSize:8 | PoolType:8
  • PreviousSize:前一个块的大小(以 POOL_BLOCK_SIZE 为单位)
  • PoolIndex:所属池的索引
  • BlockSize:当前块的大小(以 POOL_BLOCK_SIZE 为单位)
  • PoolType:池类型

2.3 其余核心结构(在 ntoskrnl/include/internal/mm.hsdk/include/ndk/mmtypes.h 中定义)

结构 文件 关键字段
MMPFN ntoskrnl/include/internal/mm.h:389 PteAddress, ReferenceCount, ShareCount, OriginalPte, u4.PteFrame, e1.PageLocation
MMVAD sdk/include/ndk/mmtypes.h:720 StartingVpn, EndingVpn, VadFlags, ControlArea, FirstPrototypePte
MMPTE sdk/include/ndk/*/mmtypes.h 联合体:Hard(硬件PTE) / Proto(原型) / Soft(软件) / Trans(转换) / Subsect(子段) / List(列表)
CONTROL_AREA sdk/include/ndk/mmtypes.h:519 Segment, FilePointer, NumberOfMappedViews, Flags
SEGMENT sdk/include/ndk/mmtypes.h:407 ControlArea, TotalNumberOfPtes, PrototypePte, ThePtes[1]
SUBSECTION sdk/include/ndk/mmtypes.h:571 ControlArea, SubsectionBase, PtesInSubsection, NextSubsection
MM_AVL_TABLE sdk/include/ndk/mmtypes.h:660 BalancedRoot, DepthOfTree, NumberGenericTableElements
MMPFNLIST ntoskrnl/include/internal/mm.h:460 Total, ListName, Flink, Blink
MMPFNENTRY ntoskrnl/include/internal/mm.h:368 Modified, PrototypePte, PageColor(4), PageLocation(3), CacheAttribute(2)

3. 页面列表枚举(MMLISTS)

c 复制代码
typedef enum _MMLISTS
{
   ZeroedPageList = 0,         // 已清零页面
   FreePageList = 1,           // 空闲页面
   StandbyPageList = 2,        // 备用页面(内容有效但未引用)
   ModifiedPageList = 3,       // 已修改页面(需要写回)
   ModifiedNoWritePageList = 4,// 已修改但不写回
   BadPageList = 5,            // 坏页
   ActiveAndValid = 6,         // 活跃有效
   TransitionPage = 7          // 转换中
} MMLISTS;

物理页状态转换:

复制代码
Free ── 分配 ──→ Active
Active ── 换出 ──→ Standby ── 清零 ──→ Zeroed ── 可用 ──→ Free
Active ── 修改 ──→ Modified ── 写回 ──→ Standby
Active ── 暂时释放 ──→ Transition ── 引用 ──→ Active

4. 关键宏

4.1 地址范围判断

c 复制代码
MI_IS_SESSION_ADDRESS(Addr)      // 是否会话空间地址
MI_IS_PAGE_TABLE_ADDRESS(Addr)   // 是否页表区域地址
MI_IS_SYSTEM_PAGE_TABLE_ADDRESS  // 是否系统页表区域地址

4.2 PTE 操作

c 复制代码
MI_MAKE_SOFTWARE_PTE(p, x)       // 创建软件 PTE
MI_SET_PFN_DELETED(x)            // 标记 PFN 已删除
MI_IS_PFN_DELETED(x)             // 检查 PFN 是否已删除

4.3 颜色分配

c 复制代码
MI_GET_PAGE_COLOR(x)             // 获取页面的缓存颜色
MI_GET_NEXT_COLOR()              // 下一个系统颜色
MI_GET_NEXT_PROCESS_COLOR(x)     // 下一个进程颜色

4.4 会话与系统映射

c 复制代码
#define MI_IS_SESSION_IMAGE_ADDRESS(Address) ...
#define MI_SYSTEM_VIEW_BUCKET_SIZE  _64K   // 系统视图以64K分桶

5. 全局变量声明

5.1 PTE 模板

c 复制代码
extern MMPTE HyperTemplatePte;           // 超空间模板 PTE
extern MMPTE ValidKernelPte;             // 有效内核 PTE 模板
extern MMPTE ValidKernelPteLocal;        // 本地有效内核 PTE
extern MMPTE DemandZeroPte;              // 请求零页 PTE(软件 PTE)
extern MMPTE PrototypePte;               // 原型 PTE 模板
extern MMPTE MmDecommittedPte;           // 解除提交 PTE

5.2 系统 PTE 范围

c 复制代码
extern PMMPTE MmSystemPtesStart[MaximumPtePoolTypes];  // 各种类型 PTE 池的起始
extern PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes];    // 各种类型 PTE 池的结束
extern PMMPTE MmFirstReservedMappingPte, MmLastReservedMappingPte;
extern PMMPTE MiFirstReservedZeroingPte;

5.3 会话空间

c 复制代码
extern PMMPTE MiSessionImagePteStart, MiSessionImagePteEnd;
extern PMMPTE MiSessionBasePte, MiSessionLastPte;

5.4 页面列表

c 复制代码
extern MMPFNLIST MmStandbyPageListByPriority[8];  // 8级优先级的备用列表

5.5 其他

c 复制代码
extern MM_AVL_TABLE MmSectionBasedRoot;    // 基于 Section 的 VAD 树根
extern PMMPTE MiHighestUserPte;             // 最高用户 PTE
extern PMMPTE MmSharedUserDataPte;          // 共享用户数据 PTE

6. 设计要点

  1. 零外部依赖miarm.h 不包含任何其他头文件,仅依赖编译器内置类型和包含它的上下文(ntoskrnl.h + debug.h)。这是一种"大头文件"设计。

  2. 架构隔离 :通过 _M_IX86 / _M_AMD64 / _M_ARM 宏在编译时选择架构相关的 PTE 定义。x86-64 通过 NX 位(第63位)实现只读/可执行分离。

  3. 保护常量 vs 硬件 PTEMM_* 是逻辑保护常量(与架构无关),PTE_* 是硬件 PTE 标志(架构相关)。两者通过 MmProtectToPteMask[32]MmProtectToValue[32] 两张表进行映射。

  4. 颜色分配 :通过 MI_GET_PAGE_COLOR 宏支持 L2 Cache 颜色分配,减少缓存抖动。

  5. 自映射页表 :x86 架构通过 PTE_BASE / PDE_BASE 实现页表自映射,使操作系统可以直接通过虚拟地址访问页表项,而无需物理地址转换。

相关推荐
毛丫讲绘本16 小时前
独立老师开始做绘本课,怎样做少走弯路?
人工智能·学习·微信·微信公众平台·微信开放平台
upper202017 小时前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Wyc7240917 小时前
agent第一周学习
学习
疯狂打码的少年18 小时前
【软件工程】软件测试阶段:单元测试与集成测试(高频对比考点)
笔记·单元测试·集成测试·软件工程
小秋求学记.19 小时前
第三天笔记
笔记
迷途呀20 小时前
CSDN Markdown 编辑器完全指南:从快捷键到高级图表
笔记·其他
栀栀栀栀栀栀20 小时前
刷刷刷 2026/7/16
笔记
小心亦新21 小时前
STM32学习16--定时器输出比较2直流电机
stm32·嵌入式硬件·学习
themingyi21 小时前
Abaqus PythonReaderPro
学习