MM 学习笔记 01:miarm.h 核心头文件分析
MM 学习笔记 01miarm.h 核心头文件分析概述miarm.hntoskrnl/mm/ARM3/miarm.h是整个 MM 子系统的核心头文件。它零外部依赖无#include定义了所有 ARM3 源文件共享的常量、宏、类型和全局变量声明。1. 基础常量1.1 容量常量#define_1KB(1024u)#define_1MB(1024*_1KB)#define_1GB(1024*_1MB)#define_64K(64*_1KB)#definePT_SIZE(PTE_PER_PAGE*sizeof(MMPTE))// 页表大小#definePD_SIZE(PDE_PER_PAGE*sizeof(MMPDE))// 页目录大小#defineSYSTEM_PD_SIZE(PPE_PER_PAGE*PD_SIZE)// 进程的完整页目录大小1.2 内存保护常量内部保护掩码保护值编码为 3 位访问位 2 位特殊标志位宏值含义MM_ZERO_ACCESS0无访问请求零页MM_READONLY1只读MM_EXECUTE2仅执行MM_EXECUTE_READ3执行读MM_READWRITE4读写MM_WRITECOPY5写时复制MM_EXECUTE_READWRITE6执行读写MM_EXECUTE_WRITECOPY7执行写时复制MM_NOCACHE0x08禁止缓存MM_GUARDPAGE0x10警戒页MM_WRITECOMBINE0x18写合并MM_DECOMMIT0x10解除提交MM_NOACCESS0x18无访问MM_OUTSWAPPED_KSTACK0x17内核栈已换出MM_INVALID_PROTECTION0xFFFFFFFF无效保护1.3 架构相关的 PTE 标志x86 32位#definePTE_VALID0x1// 有效位存在位#definePTE_READWRITE0x2// 可写#definePTE_PROTOTYPE0x400// 原型 PTE#definePTE_ACCESSED0x20// 已访问#definePTE_DIRTY0x40// 已修改#definePTE_DISABLE_CACHE0x10// 禁用缓存#definePTE_PROTECT_MASK0x612// 保护掩码x86-64注意高位的 NX 位#definePTE_READONLY0x8000000000000000ULL// NX 位#definePTE_READWRITE0x8000000000000002ULL#definePTE_EXECUTE_READWRITE0x0000000000000002ULLARM#definePTE_READONLY0x200#definePTE_PROTOTYPE0x400// 使用共享位2. 关键结构体在 miarm.h 中声明在其他文件中定义2.1 POOL_DESCRIPTOR — 池描述符定义在miarm.h中非 ARM3 的其他文件也使用此结构typedefstruct_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;关键理解ListHeads有PAGE_SIZE / 8 51232位或PAGE_SIZE / 16 25664位个桶每个桶对应一个固定大小的块范围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:8PreviousSize前一个块的大小以 POOL_BLOCK_SIZE 为单位PoolIndex所属池的索引BlockSize当前块的大小以 POOL_BLOCK_SIZE 为单位PoolType池类型2.3 其余核心结构在ntoskrnl/include/internal/mm.h和sdk/include/ndk/mmtypes.h中定义结构文件关键字段MMPFNntoskrnl/include/internal/mm.h:389PteAddress,ReferenceCount,ShareCount,OriginalPte,u4.PteFrame,e1.PageLocationMMVADsdk/include/ndk/mmtypes.h:720StartingVpn,EndingVpn,VadFlags,ControlArea,FirstPrototypePteMMPTEsdk/include/ndk/*/mmtypes.h联合体Hard(硬件PTE) /Proto(原型) /Soft(软件) /Trans(转换) /Subsect(子段) /List(列表)CONTROL_AREAsdk/include/ndk/mmtypes.h:519Segment,FilePointer,NumberOfMappedViews,FlagsSEGMENTsdk/include/ndk/mmtypes.h:407ControlArea,TotalNumberOfPtes,PrototypePte,ThePtes[1]SUBSECTIONsdk/include/ndk/mmtypes.h:571ControlArea,SubsectionBase,PtesInSubsection,NextSubsectionMM_AVL_TABLEsdk/include/ndk/mmtypes.h:660BalancedRoot,DepthOfTree,NumberGenericTableElementsMMPFNLISTntoskrnl/include/internal/mm.h:460Total,ListName,Flink,BlinkMMPFNENTRYntoskrnl/include/internal/mm.h:368Modified,PrototypePte,PageColor(4),PageLocation(3),CacheAttribute(2)3. 页面列表枚举MMLISTStypedefenum_MMLISTS{ZeroedPageList0,// 已清零页面FreePageList1,// 空闲页面StandbyPageList2,// 备用页面内容有效但未引用ModifiedPageList3,// 已修改页面需要写回ModifiedNoWritePageList4,// 已修改但不写回BadPageList5,// 坏页ActiveAndValid6,// 活跃有效TransitionPage7// 转换中}MMLISTS;物理页状态转换Free ── 分配 ──→ Active Active ── 换出 ──→ Standby ── 清零 ──→ Zeroed ── 可用 ──→ Free Active ── 修改 ──→ Modified ── 写回 ──→ Standby Active ── 暂时释放 ──→ Transition ── 引用 ──→ Active4. 关键宏4.1 地址范围判断MI_IS_SESSION_ADDRESS(Addr)// 是否会话空间地址MI_IS_PAGE_TABLE_ADDRESS(Addr)// 是否页表区域地址MI_IS_SYSTEM_PAGE_TABLE_ADDRESS// 是否系统页表区域地址4.2 PTE 操作MI_MAKE_SOFTWARE_PTE(p,x)// 创建软件 PTEMI_SET_PFN_DELETED(x)// 标记 PFN 已删除MI_IS_PFN_DELETED(x)// 检查 PFN 是否已删除4.3 颜色分配MI_GET_PAGE_COLOR(x)// 获取页面的缓存颜色MI_GET_NEXT_COLOR()// 下一个系统颜色MI_GET_NEXT_PROCESS_COLOR(x)// 下一个进程颜色4.4 会话与系统映射#defineMI_IS_SESSION_IMAGE_ADDRESS(Address)...#defineMI_SYSTEM_VIEW_BUCKET_SIZE_64K// 系统视图以64K分桶5. 全局变量声明5.1 PTE 模板externMMPTE HyperTemplatePte;// 超空间模板 PTEexternMMPTE ValidKernelPte;// 有效内核 PTE 模板externMMPTE ValidKernelPteLocal;// 本地有效内核 PTEexternMMPTE DemandZeroPte;// 请求零页 PTE软件 PTEexternMMPTE PrototypePte;// 原型 PTE 模板externMMPTE MmDecommittedPte;// 解除提交 PTE5.2 系统 PTE 范围externPMMPTE MmSystemPtesStart[MaximumPtePoolTypes];// 各种类型 PTE 池的起始externPMMPTE MmSystemPtesEnd[MaximumPtePoolTypes];// 各种类型 PTE 池的结束externPMMPTE MmFirstReservedMappingPte,MmLastReservedMappingPte;externPMMPTE MiFirstReservedZeroingPte;5.3 会话空间externPMMPTE MiSessionImagePteStart,MiSessionImagePteEnd;externPMMPTE MiSessionBasePte,MiSessionLastPte;5.4 页面列表externMMPFNLIST MmStandbyPageListByPriority[8];// 8级优先级的备用列表5.5 其他externMM_AVL_TABLE MmSectionBasedRoot;// 基于 Section 的 VAD 树根externPMMPTE MiHighestUserPte;// 最高用户 PTEexternPMMPTE MmSharedUserDataPte;// 共享用户数据 PTE6. 设计要点零外部依赖miarm.h不包含任何其他头文件仅依赖编译器内置类型和包含它的上下文ntoskrnl.hdebug.h。这是一种大头文件设计。架构隔离通过_M_IX86/_M_AMD64/_M_ARM宏在编译时选择架构相关的 PTE 定义。x86-64 通过 NX 位第63位实现只读/可执行分离。保护常量 vs 硬件 PTEMM_*是逻辑保护常量与架构无关PTE_*是硬件 PTE 标志架构相关。两者通过MmProtectToPteMask[32]和MmProtectToValue[32]两张表进行映射。颜色分配通过MI_GET_PAGE_COLOR宏支持 L2 Cache 颜色分配减少缓存抖动。自映射页表x86 架构通过PTE_BASE/PDE_BASE实现页表自映射使操作系统可以直接通过虚拟地址访问页表项而无需物理地址转换。