Windows Research Kernel (WRK) 内存管理器完整分析
Windows Research Kernel (WRK) 内存管理器完整分析分析范围:WRK-v1.2/base/ntos/mm/参考: Windows Server 2003 内核内存管理目录架构总览核心数据结构虚拟地址布局Section 创建流程View 映射流程缺页处理流程工作集管理进程地址空间初始化系统初始化 (Phase 0/1)会话管理x86 PTE 详解锁体系1. 架构总览1.1 文件组织结构WRK-v1.2/base/ntos/mm/ ├── mi.h # 主头文件: 数据结构、宏、常量、全局变量 ├── miglobal.c # 全局变量定义 │ ├── mmfault.c # MmAccessFault 入口 用户/内核缺页路由 ├── pagfault.c # MiDispatchFault 子处理函数 (demand zero, transition, pagefile, mapped file, proto) │ ├── creasect.c # MmCreateSection 三种 Segment 创建 ├── sectsup.c # Section 辅助函数 ├── extsect.c # Section 扩展 (MmExtendSection) ├── mapview.c # MmMapViewOfSection (用户态映射) ├── umapview.c # MmUnmapViewOfSession ├── querysec.c # 查询 Section 信息 │ ├── procsup.c # 进程地址空间初始化/销毁 ├── session.c # 会话创建/销毁 ├── sessload.c # 会话镜像加载 │ ├── wslist.c # 工作集列表初始化 (进程/会话) ├── wsmanage.c # 工作集管理 (修剪、交换、老化) │ ├── mminit.c # 系统初始化 Phase 0/1 ├── sysptes.c # 系统 PTE 池管理 (分配/释放) ├── pfnlist.c # PFN 数据库列表操作 ├── pfndec.c # PFN 引用计数递减 │ ├── allocpag.c # 物理页分配 (MiRemoveAnyPage, MiRemoveZeroPage) ├── zeropage.c # 零页线程 (MmZeroPageThread) ├── modwrite.c # 修改页写入器 (MiModifiedPageWriter) │ ├── hypermap.c # Hyperspace 临时映射 ├── physical.c # MmAllocatePagesForMdl, MmMapIoSpace │ ├── addrsup.c # 地址空间支持函数 ├── vadtree.c / wstree.c # VAD/工作集 AVL 树操作 ├── deleteva.c # 删除虚拟地址 ├── allocvm.c / freevm.c # 虚拟地址分配/释放 ├── lockvm.c # MmLockPageableSection ├── protect.c # NtProtectVirtualMemory ├── queryvm.c # NtQueryVirtualMemory │ ├── dmpaddr.c # 调试/崩溃转储函数 ├── mmdbg.c # 调试支持 │ ├── i386/ # x86 特定代码 │ ├── mi386.h # x86 PTE 格式, 页表宏 │ ├── init386.c # x86 初始化 │ ├── data386.c # x86 数据 │ ├── procx86.c # x86 进程支持 │ ├── procpae.c # PAE 进程支持 │ ├── setmodfy.c # 脏位设置 │ ├── pae.asm # PAE 汇编 │ └── paesup.c # PAE 支持 │ ├── amd64/ # AMD64 特定代码 │ ├── miamd.h │ ├── initamd.c │ └── dataamd.c │ └── BUILD/ # 构建文件1.2 分层架构用户态 API (ntdll) NtCreateSection, NtMapViewOfSection, NtAllocateVirtualMemory, NtProtectVirtualMemory, NtQueryVirtualMemory │ syscall ▼ MmAccessFault (mmfault.c) 缺页路由: 用户态/内核态/会话空间 │ ┌─────────────────────┼─────────────────────┐ │ │ │ ▼ ▼ ▼ MiDispatchFault MiResolveProtoPteFault MiResolvePageFileFault (pagfault.c) MiResolveDemandZeroFault (pagfault.c) 主调度器 MiResolveTransitionFault MiResolveMappedFileFault ┌─────────────────────┬─────────────────────┐ │ │ │ ▼ ▼ ▼ MmCreateSection MmMapViewOfSection MmInitProcessAddressSpace (creasect.c) (mapview.c) (procsup.c) ┌─────────────────────┬─────────────────────┐ │ │ │ ▼ ▼ ▼ SEGMENT CONTROL_AREA MMVAD 树 MMSUPPORT SUBSECTION 原型PTEs 页表层次 工作集列表1.3 数据流总结MmCreateSection → CONTROL_AREA SEGMENT SUBSECTION 原型PTEs ↓ MmMapViewOfSection → MMVAD (插入 VAD 树) ↓ 缺页 → MmAccessFault → MiDispatchFault → MiResolveProtoPteFault → MiResolveDemandZeroFault → MiResolvePageFileFault → MiResolveTransitionFault → MiResolveMappedFileFault2. 核心数据结构2.1 SECTION → SEGMENT → CONTROL_AREA → SUBSECTION 关系SECTION (对象管理) ┌──────────────────────┐ │ Segment ─────────────┼────┐ │ SizeOfSection │ │ │ InitialPageProtection│ │ │ Flags (Based, Image) │ │ └──────────────────────┘ │ ▼ SEGMENT (分页池分配) ┌──────────────────────────────┐ │ ControlArea ─────────────┼──┐│ │ TotalNumberOfPtes │ ││ │ SizeOfSegment │ ││ │ SegmentPteTemplate │ ││ │ PrototypePte │ ││ │ ThePtes[0..N] │ ││ └──────────────────────────────┘ │ │ │ ▼ ▼ │ CONTROL_AREA 原型PTE数组│ ┌──────────────────┐ ┌──────┐ │ │ Segment ─────────┼──┤ PTE0 │ │ │ FilePointer │ │ PTE1 │ │ │ u.Flags │ │ ... │ │ │ DereferenceList │ └──────┘ │ └──────────────────┘ │ │ │ ▼ │ SUBSECTION (紧接在CA之后) │ ┌────────────────────┐ │ │ ControlArea │ │ │ SubsectionBase ────┼─────────┘ │ PtesInSubsection │ │ NextSubsection │──→更多 SUBSECTION │ StartingSector │ │ NumberOfFullSectors│ │ Protection │ └────────────────────┘2.2 PFN 数据库PFN 数据库 (全局数组 MmPfnDatabase) ┌──────────────────────────────┐ │ u1.Flink/WsIndex/Event │ │ u2.Blink/ShareCount │ │ u3.e1: │ │ Modified, ReadInProgress, │ │ WriteInProgress, │ │ PrototypePte, PageColor, │ │ PageLocation (状态), │ │ RemovalRequested, │ │ ReferenceCount (16位) │ │ PteAddress (反向指针) │ │ OriginalPte (原始PTE) │ │ u4.PteFrame InPageError │ └──────────────────────────────┘2.3 工作集系统MMSUPPORT (每个进程/会话/系统缓存一个) ┌──────────────────────────────┐ │ WorkingSetExpansionLinks │ ← 全局扩展列表 │ LastTrimTime │ │ Flags (SessionSpace, ...) │ │ PageFaultCount │ │ MinimumWorkingSetSize │ │ MaximumWorkingSetSize │ │ VmWorkingSetList ────────────┼──┐ │ WorkingSetSize │ │ │ WorkingSetMutex │ │ └──────────────────────────────┘ │ ▼ MMWSL (工作集列表) ┌──────────────────────────────┐ │ LastEntry, FirstFree, │ │ FirstDynamic, NextSlot │ │ HashTable, HashTableSize │ │ Wsle ────────────────────────┼──┐ └──────────────────────────────┘ │ ▼ MMWSLE 数组 (每个工作集条目) ┌────────────────────┬─────────┬─────────┐ │ WSLE[0] (保留) │ WSLE[1] │ WSLE[2] │ ... │ u1.VirtualAddress │ ... │ ... │ │ u3.e1.LockedInWs │ │ │ │ u3.e1.Direct │ │ │ └────────────────────┴─────────┴─────────┘3. 虚拟地址布局3.1 x86 虚拟地址空间0x00000000 ┌──────────────────────┐ │ 用户地址空间 │ │ (每个进程独立) │ 0x7FFF0000 ├──────────────────────┤ ← 64KB 禁区 0x80000000 ├──────────────────────┤ ← MmSystemRangeStart │ HAL/NTOSKRNL/启动驱动│ 0x83800000 ├──────────────────────┤ │ PFN 数据库 │ 0xB0901000 ├──────────────────────┤ │ 非分页池 │ 0xB2889000 ├──────────────────────┤ │ 系统视图空间 │ 0xBB400000 ├──────────────────────┤ │ 会话池 │ ← MmSessionBase (BD000000) │ 会话视图 │ ← MiSessionViewStart (BE000000) │ 会话镜像 │ ← MiSessionImageStart (BF800000) 0xC0000000 ├──────────────────────┤ │ 页表 (4MB) │ 0xC0400000 ├──────────────────────┤ │ HyperSpace │ 0xC0C00000 ├──────────────────────┤ │ 系统缓存结构 │ 0xC1000000 ├──────────────────────┤ │ 系统缓存 │ 0xE1000000 ├──────────────────────┤ │ 分页系统区 │ ← MmPagedPoolStart │ 分页池 │ 0xFFBE0000 ├──────────────────────┤ │ 非分页池扩展 │ 0xFFC00000 ├──────────────────────┤ │ HAL 保留 (4MB) │ 0xFFDFF000 ├──────────────────────┤ │ PCR (KIP0PCRADDRESS)│ 0xFFFFFFFF └──────────────────────┘3.2 x64 虚拟地址空间0000000000000000 ┌──────────────────────┐ │ 用户地址空间 (8TB) │ 000007FFFFFFFF00 ├──────────────────────┤ 0000080000000000 └──────────────────────┘ 0000800000000000 非规范地址区间 FFFF080000000000 ┌──────────────────────┐ ← MmSystemRangeStart │ 系统地址空间 │ FFFFF68000000000 ├──────────────────────┤ │ 4级页表映射 │ FFFFF70000000000 ├──────────────────────┤ │ HyperSpace │ FFFFF78000000000 ├──────────────────────┤ │ 共享系统页 │ FFFFF80000000000 ├──────────────────────┤ │ 系统缓存工作集 │ FFFFF88000000000 ├──────────────────────┤ │ 系统缓存 (1TB) │ FFFFF98000000000 ├──────────────────────┤ │ 分页池 (512GB) │ FFFFFAC000000000 ├──────────────────────┤ │ 系统PTE池 (512GB) │ FFFFFC0000000000 ├──────────────────────┤ │ 非分页池 (512GB) │ FFFFFE0000000000 ├──────────────────────┤ │ 会话空间 │ FFFFFFFF80000000 ├──────────────────────┤ │ HAL/NTOSKRNL │ FFFFFFFFFF000000 ├──────────────────────┤ │ 共享系统页 │ FFFFFFFFFF002000 ├──────────────────────┤ │ HAL 保留 │ FFFFFFFFFFFFFFFF └──────────────────────┘4. Section 创建流程4.1 总体流程NtCreateSection (creasect.c:131) │ │ 参数校验, PreviousMode 探测 │ MiMakeProtectionMask() ▼ MmCreateSection (creasect.c:403) │ ├── [有文件句柄/对象] ───────────────────────────┐ │ │ │ │ │ 解析 FileObject │ │ │ 检查 SectionObjectPointer │ │ │ 分配 NewControlArea (带 SUBSECTION) │ │ │ │ │ ├── [SEC_IMAGE] │ │ │ │ │ │ │ │ 分配 LARGE_CONTROL_AREA SUBSECTION │ │ │ │ MiCreateImageFileMap(File, Segment) │ │ │ │ → 读取 PE 头 │ │ │ │ → 分配 SEGMENT ThePtes[] │ │ │ │ → 为每个 PE Section 创建 SUBSECTION │ │ │ │ → 填充原型PTEs (subsection-format) │ │ │ ▼ │ │ │ 返回 Segment │ │ │ │ │ └── [!SEC_IMAGE - 数据文件] │ │ │ │ │ │ MiCreateDataFileMap(File, Segment) │ │ │ → 分配 MAPPED_FILE_SEGMENT │ │ │ → 创建 MSUBSECTION 链 │ │ │ → 原型PTEs 惰性分配 (首次缺页) │ │ ▼ │ │ 返回 Segment │ │ │ └── [无文件句柄 - pagefile-backed] ──────────┘ │ │ MiCreatePagingFileMap(Segment, ...) │ → 分配 SEGMENT ThePtes[] │ → 分配 CONTROL_AREA SUBSECTION │ → 填充原型PTEs (demand-zero/pagefile-format) ▼ 返回 Segment │ │ 公共后处理 │ SECTION.SizeOfSection Segment.SizeOfSegment │ ObCreateObject → SECTION 对象 │ [SEC_BASED] → MiInsertBasedSection ▼ 返回 SECTION 对象4.2 三种 Segment 对比特性镜像 (Image)数据文件 (Data File)分页文件 (Pagefile)Segment 类型SEGMENTMAPPED_FILE_SEGMENTSEGMENT分配位置分页池分页池分页池原型PTE分配时机创建时惰性 (首次缺页)创建时原型PTE位置ThePtes[] (内联)SubsectionBase (独立)ThePtes[] (内联)原型PTE格式Subsection-format (Prototype1)Subsection-formatDemand-zero/PagefileSUBSECTION 类型SUBSECTIONMSUBSECTIONSUBSECTION段模板 (SegmentPteTemplate)编码第一SUBSECTION地址编码第一MSUBSECTION地址仅有Protection位4.3 CONTROL_AREA SUBSECTION 内存布局非分页池分配: ┌─────────────────────┐ ← ExAllocatePoolWithTag(NonPagedPool, │ CONTROL_AREA │ sizeof(CONTROL_AREA) sizeof(SUBSECTION)) │ .Segment → SEGMENT │ │ .FilePointer │ │ .u.Flags │ ├─────────────────────┤ ← (CONTROL_AREA 1) │ SUBSECTION (第一个) │ │ .ControlArea │ │ .SubsectionBase │ │ .NextSubsection ───┼──→ 独立分配的更多 SUBSECTION └─────────────────────┘4.4 原型PTE的三种格式Section Pagefile-backed 原型PTE: ┌─┬────────┬────────┬─┬─┬──────────────────┐ │0│PageFile│Protect │0│0│ PageFileHigh │ │ │Low(4) │ion (5) │ │ │ (20) │ └─┴────────┴────────┴─┴─┴──────────────────┘ Section Image/Data 原型PTE (Subsection-format): ┌─┬────┬────────┬─┬────────────────────────┐ │0│Sub-│Protect │1│ SubsectionAddress (24) │ │ │闁(4)│ion (5) │ │ │ └─┴────┴────────┴─┴────────────────────────┘ Demand Zero 原型PTE: ┌─┬────────┬────────┬─┬─┬──────────────────┐ │0│0 │Protect │0│0│ 0 │ │ │ │ion (5) │ │ │ │ └─┴────────┴────────┴─┴─┴──────────────────┘5. View 映射流程MmMapViewOfSection (mapview.c) │ │ 参数校验 │ PreviousMode 探测 (用户/内核) │ ▼ ├── [SEC_IMAGE] │ │ │ │ 获取 SectionObject │ │ 从 SEGMENT 读取 BasedAddress (首选加载地址) │ │ MiFindEmptyAddressRange (查找可用地址空间) │ │ MmMapViewOfImageSection (mapview.c) │ │ → 分配 MMVAD_LONG (VadImageMap 类型) │ │ → 插入 VAD 树 │ │ → 设置 FirstPrototypePte │ │ → 设置 ControlArea │ │ → 返回映射地址 │ ├── [!SEC_IMAGE - 页文件] │ │ │ │ MmMapViewOfSection (继续) │ │ → 分配 MMVAD_LONG (VadNone 类型) │ │ → 插入 VAD 树 │ │ → 设置 FirstPrototypePte SEGMENT.ThePtes[0] │ │ → 设置 ControlArea │ │ → 返回映射地址 │ └── [KCACHE - 缓存管理器] │ │ MiMapSystemCacheView (mapcache.c) │ → 分配系统视图 │ → 映射到系统缓存地址范围 ▼ 返回6. 缺页处理流程6.1 MmAccessFault 决策树MmAccessFault (mmfault.c) │ ├── OldIrql APC_LEVEL? │ → 快速路径: PTE有效则置位脏/访问位, 无效则 BugCheck │ ├── 内核地址 ( MmSystemRangeStart)? │ │ │ ├── 验证 PXE/PPE/PDE/PTE 层次 │ ├── 会话地址? │ │ ├── MiCheckPdeForSessionSpace │ │ ├── 使用会话工作集 (HYDRA_PROCESS) │ │ └── 镜像加载特殊处理 (CoW) │ │ │ └── 非会话? │ ├── 使用系统缓存工作集 │ └── 检查已释放的非分页池 │ └── 用户地址? │ ├── 分页文件压力检查 ├── 加锁进程工作集 ├── 缺页 PTE/PPE/PDE 层次 (递归) ├── 读 PTE │ ├── PTE 有效? → 置位脏/访问位, CoW 处理 ├── PTE MM_DEMAND_ZERO_WRITE_PTE? │ → MiResolveDemandZeroFault (直接) ├── PTE MM_ZERO_PTE / MM_ZERO_KERNEL_PTE? │ ├── MiCheckVirtualAddress → 找 VAD │ ├── 无 VAD → ACCESS_VIOLATION │ ├── 保护区 → 栈溢出处理 │ ├── 无原型PTE (私有页) → 内联 Demand Zero │ └── 有原型PTE → 安装原型PTE引用 │ └── PTE 非零且无效? → MiDispatchFault6.2 MiDispatchFault 决策树MiDispatchFault (pagfault.c) │ ├── PointerProtoPte ! NULL? (原型PTE路径) │ │ │ ├── 原型PTE页面未驻留? │ │ → 递归 MmAccessFault (原型PTE地址) │ │ → 会话: 切换工作集 → 缺页 → 切回 │ │ │ ├── 原型PTE有效/转换 (内联路径) │ │ → 共享计数 │ │ → MiCompleteProtoPteFault │ │ │ └── MiResolveProtoPteFault │ │ │ ├── 原型PTE有效? │ │ → MiCompleteProtoPteFault │ ├── 原型PTE Demand Zero CoW? │ │ → 私有化, 分配零页 │ ├── 原型PTE.Prototype1? │ │ → MiResolveMappedFileFault → I/O │ ├── 原型PTE.Transition1? │ │ → MiResolveTransitionFault │ ├── 原型PTE.PageFileHigh0? │ │ → MiResolveDemandZeroFault │ └── 否则 │ → MiResolvePageFileFault → I/O │ → MiCompleteProtoPteFault (收尾) │ └── 非原型PTE路径 (NonProtoFault) │ ├── Transition1? │ → MiResolveTransitionFault (软故障, 无I/O) ├── PageFileHigh0? │ → MiResolveDemandZeroFault (分配零页) └── 否则 → MiResolvePageFileFault (页文件I/O)6.3 子故障处理器处理器输入条件动作I/OMiResolveDemandZeroFaultPageFileHigh0, Transition0分配物理页, 清零, 映射无MiResolveTransitionFaultTransition1从Standby/Modified列表取回页面无MiResolvePageFileFaultPageFileHigh!0从页文件读取页面IoPageReadMiResolveMappedFileFaultPrototype1 (Subsection-format)从文件读取页面IoPageReadMiResolveProtoPteFaultPrototype PTE存在根据原型PTE类型派分子处理器取决于子处理器MiCompleteProtoPteFault(由子处理器调用)填充用户PTE, 更新共享计数, 添加到工作集无6.4 Process 参数编码MiDispatchFault 的 Process 参数有三种取值:值含义工作集NULL系统空间故障MmSystemCacheWsHYDRA_PROCESS (sentinel)会话空间故障MmSessionSpace-GlobalVirtualAddress-Vm有效 EPROCESS 指针用户模式故障Process-Vm7. 工作集管理7.1 工作集类型类型MMSUPPORT 位置Flags.SessionSpace锁字段进程EPROCESS.Vm0OwnsProcessWorkingSetExclusive/Shared会话MM_SESSION_SPACE.Vm1OwnsSessionWorkingSetExclusive/Shared系统缓存MmSystemCacheWs0OwnsSystemWorkingSetExclusive/Shared7.2 工作集锁定宏// LOCK_WORKING_SET(THREAD, WSINFO)KeEnterGuardedRegionThread(THREAD-Tcb);ASSERT(!MI_IS_SESSION_ADDRESS(WSINFO));// WSINFO必须是全局地址!ASSERT(!MM_ANY_WS_LOCK_HELD(THREAD));ExAcquirePushLockExclusive((WSINFO)-WorkingSetMutex);// 根据 WSINFO 设置对应线程标志// UNLOCK_WORKING_SET(THREAD, WSINFO)MM_WS_LOCK_ASSERT(WSINFO);// 清除对应线程标志ExReleasePushLockExclusive((WSINFO)-WorkingSetMutex);KeLeaveGuardedRegionThread(THREAD-Tcb);关键约束:LOCK_WORKING_SET/UNLOCK_WORKING_SET 都断言MI_IS_SESSION_ADDRESS(WSINFO) FALSE。对于会话工作集, 必须使用全局地址:MmSessionSpace-GlobalVirtualAddress-Vm。7.3 工作集初始化进程工作集 (MiInitializeWorkingSetList, wslist.c:1393)1. 使用全局 WSLE 阵列初始化 2. 设置 LastEntry Process-Vm.MinimumWorkingSetSize 3. 填充保留槽: 顶层页目录、Hyperspace PDE/PTE、VAD位图、WSL本身 4. 构建空闲WSLE链表会话工作集 (MiSessionInitializeWorkingSetList, wslist.c:1591)1. 使用会话空间内预留地址 (MiSessionSpaceWs) 2. ExInitializePushLock(SessionGlobal-Vm.WorkingSetMutex) ← 全局地址! 3. 分配页表页 数据页 4. 填充保留槽: MmSessionSpace、WSL、页表、PagedPoolStart 5. Flags.SessionSpace 1 6. 插入 MiSessionWsList 和 MmWorkingSetExpansionHead7.4 工作集修剪工作集修剪由平衡集管理器 (KeBalanceSetManager) 触发, 流程:KeBalanceSetManager → MmWorkingSetManager (wsmanage.c) → MiTrimWorkingSet (对每个工作集) → 遍历 WSLE → MiEliminateWorkingSetEntry (移除页面) → 如果可丢弃/可分页: → MiDecrementReferenceCount → PTE → Transition 状态 → PFN → StandbyPageList 或 ModifiedPageList8. 进程地址空间初始化8.1 MmInitializeProcessAddressSpace (procsup.c:603)MmInitializeProcessAddressSpace(Process, ...) │ │ 1. 初始化同步原语 │ KeInitializeGuardedMutex(Process-AddressCreationLock) │ ExInitializePushLock(Process-Vm.WorkingSetMutex) ← 关键! │ │ 2. 初始化 VAD 树 │ Process-VadRoot.BalancedRoot.u1.Parent Process-VadRoot.BalancedRoot │ │ 3. 初始化工作集元数据 │ KeQuerySystemTime(Process-Vm.LastTrimTime) │ Process-Vm.VmWorkingSetList MmWorkingSetList │ │ 4. 初始化页表层次 (架构相关) │ (分配页面目录, 复制系统PDE, 设置进程页目录) │ │ 5. MiInitializeWorkingSetList(Process) │ (填充工作集列表, 保留固定槽位) │ │ 6. 分配 PEB │ MmCreatePeb(Process, Peb) │ │ 7. 添加进程到会话 (如果需要) │ MiSessionAddProcess(Process) │ ▼ 返回 STATUS_SUCCESS8.2 MmCreateProcessAddressSpace (procsup.c)由 PspCreateProcess 在创建进程时调用。比 MmInitializeProcessAddressSpace 少一些步骤, 用于初始系统进程。8.3 工作集互斥体初始化WRK 在procsup.c:752显式初始化:ExInitializePushLock(ProcessToInitialize-Vm.WorkingSetMutex);ReactOS ARM3 的procsup.c省略了此调用 (依赖EPROCESS零初始化)。8.4 进程地址空间销毁MmCleanProcessAddressSpace (procsup.c) → 遍历 VAD 树 → 删除所有映射 → 释放页表页面 → MiSessionRemoveProcess → 释放 PDE 页面9. 系统初始化 (Phase 0/1)9.1 Phase 0MmInitSystem(0, LoaderBlock) │ │ 1. 计算地址空间布局 │ MmSystemRangeStart 0x80000000 │ MmHighestUserAddress 0x7FFF0000 │ 计算 MmSessionBase, MiSessionSpaceEnd (基于注册表调整) │ │ 2. 初始化全局锁和列表 │ MmWorkingSetExpansionHead │ MmSectionCommitMutex │ MmPagedPoolMutex │ MmSystemLoadLock │ │ 3. 计算物理页数 │ │ 4. MiInitMachineDependent(LoaderBlock) ← 架构相关 │ ├── 分配系统 PTE 池 (MiInitializeSystemPtes) │ ├── 初始化 PFN 数据库 │ ├── 初始化非分页池 │ └── 初始化分页池 │ │ 5. MiInitializeSystemCache (构建系统缓存) │ 6. MiBuildPagedPool (构建分页池) │ 7. MiInitializeLoadedModuleList │ 8. 设置提交限制和最大工作集大小 │ ▼ 返回 TRUE9.2 Phase 1MmInitSystem(1, LoaderBlock) │ │ 1. MiInitMachineDependent(LoaderBlock) (再次) │ 2. MiMapBBTMemory(LoaderBlock) │ 3. MiSectionInitialization() (Section对象支持) │ 4. 分配 MmSharedUserDataPte │ 5. MiSessionWideInitializeAddresses() │ 6. MiInitializeSessionWsSupport() (MiSessionWsList 列表头) │ 7. MiInitializeSessionIds() (会话ID位图) │ 8. 启动修改页面写入器线程 │ 9. 初始化内存事件 (低/高可用页面阈值) │ 10. 启动平衡集管理器 │ 11. 启动零页工作线程 │ 12. MiFullyInitialized 1 │ ▼ 返回 TRUE9.3 系统 PTE 池初始化MiInitializeSystemPtes (sysptes.c:2248) │ │ 1. 设置 MmSystemPteBase, MmSystemPtesStart[type], MmSystemPtesEnd[type] │ 2. PTE 池清零 │ 3. 初始化空闲集群链表 │ 4. 设置 MmTotalFreeSystemPtes[type] │ │ 对于 SystemPteSpace 类型: │ ├── 为按大小分类的NB队列分配SLIST块 │ │ 大小区间: 1,2,4,8,16 (x86) / 1,2,4,7,8,16,19 (x64) │ ├── ExInitializeNBQueueHead 初始化NB队列 │ ├── 可选: 位图跟踪 │ └── 预填充分类列表 │ ▼ 返回9.4 系统 PTE 运行时分配MiReserveSystemPtes(NumberOfPtes, PoolType) │ ├── 大小 ≤ MM_PTE_TABLE_LIMIT? │ → 检查NB队列 (按大小分类) │ → 命中? 返回PTE, 补充NB队列 │ → 未命中? 回退到 MiReserveAlignedSystemPtes │ └── 大分配 → MiLockSystemSpace → 遍历空闲集群链表 → 分割/精确匹配 → MiUnlockSystemSpace → 返回PTE10. 会话管理10.1 会话创建MmSessionCreate (session.c:1440) │ │ 1. 检查进程是否已在会话中 │ 2. 原子性设置会话领导者 │ 3. │ MiSessionCreateInternal(SessionId) │ ├── 分配会话ID位图条目 │ ├── MiChargeCommitment(MiSessionCreatePages) │ ├── MiReserveSystemPtes(MiSessionDataPages, SystemPteSpace) │ ├── 分配物理页 │ │ ├── 数据页 (sizeof(MM_SESSION_SPACE)) │ │ ├── 页目录页 (x64) │ │ ├── 页表页 │ │ └── 标签页 (池标签跟踪) │ ├── 映射并初始化 PFN │ ├── 填充 MM_SESSION_SPACE 字段 │ ├── MiInitializeSessionPool() ← 会话分页池 │ └── MiInitializeSystemSpaceMap() │ │ 4. MiSessionInitializeWorkingSetList() │ ├── 预留WSL VA │ ├── ExInitializePushLock(SessionGlobal-Vm.WorkingSetMutex) │ ├── 分配页表页 数据页 │ ├── 填充保留WSLE │ ├── Flags.SessionSpace 1 │ └── 插入全局工作集列表 │ │ 5. 初始化后备列表 (第一个会话池分配) │ 6. MmSessionSpace-u.Flags.Initialized 1 │ 7. 设置进程 PS_PROCESS_FLAGS_IN_SESSION │ ▼ 返回 STATUS_SUCCESS10.2 会话空间结构typedefstruct_MM_SESSION_SPACE{// 生命周期管理struct_MM_SESSION_SPACE*GlobalVirtualAddress;ULONG ReferenceCount;ULONG ResidentProcessCount;ULONG ProcessReferenceToSession;union{ULONG LongFlags;MMSESSION_FLAGS Flags;}u;// 标识ULONG SessionId;LIST_ENTRY ProcessList;LIST_ENTRY ImageList;ULONG SessionPageDirectoryIndex;// 记账SIZE_T NonPageablePages;SIZE_T CommittedPages;PVOID PagedPoolStart;PVOID PagedPoolEnd;// 工作集LIST_ENTRY WsListEntry;MMSUPPORT Vm;// MMSUPPORT 包含 WorkingSetMutexPMMWSLE Wsle;// 池LOOKASIDE_LIST Lookaside[14];MMPOOL Descriptor[2];PMM_SESSION_POOL_SPECIFIC PagedPool;// 页表ULONG PageDirectory[768];MMPTE PageTables[];}MM_SESSION_SPACE;10.3 会话工作集关键差异方面进程工作集会话工作集MMSUPPORT 位置EPROCESS.VmMmSessionSpace-Vm锁地址Process-Vm.WorkingSetMutexSessionGlobal-Vm.WorkingSetMutex (全局)Flags.SessionSpace01线程锁字段OwnsProcessWorkingSet*OwnsSessionWorkingSet*全局列表MmWorkingSetExpansionHeadMiSessionWsList11. x86 PTE 详解11.1 x86 PTE 格式 (无PAE)硬件 PTE (Valid1): ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──┬─┬───────────────────┐ │0│1│2│3│4│5│6│7│8│9│10│11│12-31 │ ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼──┼─┼───────────────────┤ │V│W│O│WT│CD│A│D│L│G│CW│Pr│W│ PageFrameNumber│ │ │ │ │ │ │ │ │ │ │ │ot│r│ (20位) │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴──┴─┴───────────────────┘ 0 1 2 3 4 5 6 7 8 9 10 11 VValid, WWrite, OOwner, WTWriteThrough, CDCacheDisable AAccessed, DDirty, LLargePage, GGlobal CWCopyOnWrite, ProtPrototype, WWr (保留/软件) 软件 PTE (Valid0): ┌─┬────────┬────────┬─┬─┬──────────────────────┐ │0│PageFile│Protect │0│0│ PageFileHigh (20位) │ │ │Low (4) │ion (5) │ │ │ │ └─┴────────┴────────┴─┴─┴──────────────────────┘ 转换 PTE (Transition1): ┌─┬─┬─┬─┬─┬────────┬─┬─┬──────────────────────┐ │0│W│O│WT│CD│Protect│0│1│ PageFrameNumber(20) │ │ │ │ │ │ │ion (5)│ │ │ │ └─┴─┴─┴─┴─┴────────┴─┴─┴──────────────────────┘ 原型 PTE (Prototype1, Valid0): ┌─┬────────┬──┬─┬─┬───────────────────────────┐ │0│ProtoLow│RO│P│1│ SubsectionAddress (21位) │ │ │ (7位) │O │W│ │ │ └─┴────────┴──┴─┴─┴───────────────────────────┘ Subsection-format PTE (Prototype1): ┌─┬────┬────────┬─┬───────────────────────────┐ │0│闁(4)│Protect │1│ SubsectionAddress (22位) │ │ │ │ion (5) │ │ │ └─┴────┴────────┴─┴───────────────────────────┘11.2 保护常量#defineMM_ZERO_ACCESS0#defineMM_READONLY1#defineMM_EXECUTE2#defineMM_EXECUTE_READ3#defineMM_READWRITE4#defineMM_WRITECOPY5#defineMM_EXECUTE_READWRITE6#defineMM_EXECUTE_WRITECOPY7#defineMM_NOCACHE811.3 特殊 PTE 值// 用户地址零PTE#defineMM_ZERO_PTE0x00000000// 内核地址零PTE#defineMM_ZERO_KERNEL_PTE0x00000000// Demand-Write PTE (ProtectionREADWRITE, all else 0)#defineMM_DEMAND_ZERO_WRITE_PTE(MM_READWRITE5)// 0x80// 已释放PTE#defineMmDecommittedPte{0}// 查找需要 (原型PTE延迟定位)#defineMI_PTE_LOOKUP_NEEDED0xFFF12. 锁体系12.1 锁层次IRQL DISPATCH_LEVEL: ├── PFN 锁 (MiAcquirePfnLock / MiReleasePfnLock) │ 保护: PFN 数据库, 页表修改, 物理页分配 │ ├── 扩展锁 (MiAcquireExpansionLock / MiReleaseExpansionLock) │ 保护: 工作集扩展头链表 │ └── 系统空间锁 (MiLockSystemSpace / MiUnlockSystemSpace) 保护: 系统 PTE 池空闲链表 IRQL APC_LEVEL: ├── 工作集锁 (ExAcquirePushLockExclusive/Shared) │ 保护: 工作集列表, 页面映射状态 │ 类型: 进程/会话/系统缓存 (线程跟踪避免递归) │ ├── Section 提交互斥体 (MmSectionCommitMutex) │ 保护: Section 提交计数 │ └── 分页池互斥体 (MmPagedPoolMutex) 保护: 分页池分配12.2 锁获取顺序工作集锁 → PFN锁 → 扩展锁 ↓ 系统空间锁 (于系统PTE分配时独立获取)不允许: 持有 PFN 锁时获取工作集锁!12.3 线程工作集锁所有权跟踪每个 ETHREAD 包含以下标志位:ULONG OwnsProcessWorkingSetExclusive:1;ULONG OwnsProcessWorkingSetShared:1;ULONG OwnsSystemWorkingSetExclusive:1;ULONG OwnsSystemWorkingSetShared:1;ULONG OwnsSessionWorkingSetExclusive:1;ULONG OwnsSessionWorkingSetShared:1;三种工作集类型互不干扰, 但同一类型不能递归加锁。与 ReactOS ARM3 的关键差异特性WRK (Windows Server 2003)ReactOS ARM3WorkingSetMutex 显式初始化procsup.c:752缺失 (依赖零初始化)LastTrimTime 初始化KeQuerySystemTime缺失会话工作集WSINFO必须使用全局地址使用 session.c 中全局地址MM_DBG_PRINT 调试有 (控制台 串口)有 (DPRINT1)MmDebug 全局变量有有 (在 section.c)数据结构位置mi.h ps.hmiarm.h pstypes.h工作集修剪MiTrimWorkingSetMiTrimWorkingSet (wrk_wsmanage.c)