Windows Research Kernel (WRK) 内存管理器完整分析
分析范围:
WRK-v1.2/base/ntos/mm/参考: Windows Server 2003 内核内存管理
目录
- 架构总览
- 核心数据结构
- 虚拟地址布局
- [Section 创建流程](#Section 创建流程)
- [View 映射流程](#View 映射流程)
- 缺页处理流程
- 工作集管理
- 进程地址空间初始化
- 系统初始化 (Phase 0/1)
- 会话管理
- [x86 PTE 详解](#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
→ MiResolveMappedFileFault
2. 核心数据结构
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 虚拟地址空间
00000000`00000000 ┌──────────────────────┐
│ 用户地址空间 (8TB) │
000007FF`FFFFFF00 ├──────────────────────┤
00000800`00000000 └──────────────────────┘
00008000`00000000 非规范地址区间
FFFF0800`00000000 ┌──────────────────────┐ ← MmSystemRangeStart
│ 系统地址空间 │
FFFFF680`00000000 ├──────────────────────┤
│ 4级页表映射 │
FFFFF700`00000000 ├──────────────────────┤
│ HyperSpace │
FFFFF780`00000000 ├──────────────────────┤
│ 共享系统页 │
FFFFF800`00000000 ├──────────────────────┤
│ 系统缓存工作集 │
FFFFF880`00000000 ├──────────────────────┤
│ 系统缓存 (1TB) │
FFFFF980`00000000 ├──────────────────────┤
│ 分页池 (512GB) │
FFFFFAC0`00000000 ├──────────────────────┤
│ 系统PTE池 (512GB) │
FFFFFC00`00000000 ├──────────────────────┤
│ 非分页池 (512GB) │
FFFFFE00`00000000 ├──────────────────────┤
│ 会话空间 │
FFFFFFFF`80000000 ├──────────────────────┤
│ HAL/NTOSKRNL │
FFFFFFFF`FF000000 ├──────────────────────┤
│ 共享系统页 │
FFFFFFFF`FF002000 ├──────────────────────┤
│ HAL 保留 │
FFFFFFFF`FFFFFFFF └──────────────────────┘
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 类型 | SEGMENT | MAPPED_FILE_SEGMENT | SEGMENT |
| 分配位置 | 分页池 | 分页池 | 分页池 |
| 原型PTE分配时机 | 创建时 | 惰性 (首次缺页) | 创建时 |
| 原型PTE位置 | ThePtes\[\] (内联) | SubsectionBase (独立) | ThePtes\[\] (内联) |
| 原型PTE格式 | Subsection-format (Prototype=1) | Subsection-format | Demand-zero/Pagefile |
| SUBSECTION 类型 | SUBSECTION | MSUBSECTION | SUBSECTION |
| 段模板 (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 非零且无效?
→ MiDispatchFault
6.2 MiDispatchFault 决策树
MiDispatchFault (pagfault.c)
│
├── PointerProtoPte != NULL? (原型PTE路径)
│ │
│ ├── 原型PTE页面未驻留?
│ │ → 递归 MmAccessFault (原型PTE地址)
│ │ → 会话: 切换工作集 → 缺页 → 切回
│ │
│ ├── 原型PTE有效/转换 (内联路径)
│ │ → 共享计数++
│ │ → MiCompleteProtoPteFault
│ │
│ └── MiResolveProtoPteFault
│ │
│ ├── 原型PTE有效?
│ │ → MiCompleteProtoPteFault
│ ├── 原型PTE == Demand Zero + CoW?
│ │ → 私有化, 分配零页
│ ├── 原型PTE.Prototype==1?
│ │ → MiResolveMappedFileFault → I/O
│ ├── 原型PTE.Transition==1?
│ │ → MiResolveTransitionFault
│ ├── 原型PTE.PageFileHigh==0?
│ │ → MiResolveDemandZeroFault
│ └── 否则
│ → MiResolvePageFileFault → I/O
│ → MiCompleteProtoPteFault (收尾)
│
└── 非原型PTE路径 (NonProtoFault)
│
├── Transition==1?
│ → MiResolveTransitionFault (软故障, 无I/O)
├── PageFileHigh==0?
│ → MiResolveDemandZeroFault (分配零页)
└── 否则
→ MiResolvePageFileFault (页文件I/O)
6.3 子故障处理器
| 处理器 | 输入条件 | 动作 | I/O |
|---|---|---|---|
| MiResolveDemandZeroFault | PageFileHigh0, Transition0 | 分配物理页, 清零, 映射 | 无 |
| MiResolveTransitionFault | Transition==1 | 从Standby/Modified列表取回页面 | 无 |
| MiResolvePageFileFault | PageFileHigh!=0 | 从页文件读取页面 | IoPageRead |
| MiResolveMappedFileFault | Prototype==1 (Subsection-format) | 从文件读取页面 | IoPageRead |
| MiResolveProtoPteFault | Prototype PTE存在 | 根据原型PTE类型派分子处理器 | 取决于子处理器 |
| MiCompleteProtoPteFault | (由子处理器调用) | 填充用户PTE, 更新共享计数, 添加到工作集 | 无 |
6.4 Process 参数编码
MiDispatchFault 的 Process 参数有三种取值:
| 值 | 含义 | 工作集 |
|---|---|---|
| NULL | 系统空间故障 | MmSystemCacheWs |
| HYDRA_PROCESS (sentinel) | 会话空间故障 | MmSessionSpace->GlobalVirtualAddress->Vm |
| 有效 EPROCESS 指针 | 用户模式故障 | Process->Vm |
7. 工作集管理
7.1 工作集类型
| 类型 | MMSUPPORT 位置 | Flags.SessionSpace | 锁字段 |
|---|---|---|---|
| 进程 | EPROCESS.Vm | 0 | OwnsProcessWorkingSetExclusive/Shared |
| 会话 | MM_SESSION_SPACE.Vm | 1 | OwnsSessionWorkingSetExclusive/Shared |
| 系统缓存 | MmSystemCacheWs | 0 | OwnsSystemWorkingSetExclusive/Shared |
7.2 工作集锁定宏
c
// 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 和 MmWorkingSetExpansionHead
7.4 工作集修剪
工作集修剪由平衡集管理器 (KeBalanceSetManager) 触发, 流程:
KeBalanceSetManager
→ MmWorkingSetManager (wsmanage.c)
→ MiTrimWorkingSet (对每个工作集)
→ 遍历 WSLE
→ MiEliminateWorkingSetEntry (移除页面)
→ 如果可丢弃/可分页:
→ MiDecrementReferenceCount
→ PTE → Transition 状态
→ PFN → StandbyPageList 或 ModifiedPageList
8. 进程地址空间初始化
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_SUCCESS
8.2 MmCreateProcessAddressSpace (procsup.c)
由 PspCreateProcess 在创建进程时调用。比 MmInitializeProcessAddressSpace 少一些步骤, 用于初始系统进程。
8.3 工作集互斥体初始化
WRK 在 procsup.c:752 显式初始化:
c
ExInitializePushLock(&ProcessToInitialize->Vm.WorkingSetMutex);
ReactOS ARM3 的 procsup.c 省略了此调用 (依赖EPROCESS零初始化)。
8.4 进程地址空间销毁
MmCleanProcessAddressSpace (procsup.c)
→ 遍历 VAD 树 → 删除所有映射
→ 释放页表页面
→ MiSessionRemoveProcess
→ 释放 PDE 页面
9. 系统初始化 (Phase 0/1)
9.1 Phase 0
MmInitSystem(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. 设置提交限制和最大工作集大小
│
▼
返回 TRUE
9.2 Phase 1
MmInitSystem(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
│
▼
返回 TRUE
9.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
→ 返回PTE
10. 会话管理
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_SUCCESS
10.2 会话空间结构
c
typedef struct _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 包含 WorkingSetMutex
PMMWSLE 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.Vm | MmSessionSpace->Vm |
| 锁地址 | Process->Vm.WorkingSetMutex | SessionGlobal->Vm.WorkingSetMutex (全局) |
| Flags.SessionSpace | 0 | 1 |
| 线程锁字段 | OwnsProcessWorkingSet* | OwnsSessionWorkingSet* |
| 全局列表 | MmWorkingSetExpansionHead | MiSessionWsList |
11. x86 PTE 详解
11.1 x86 PTE 格式 (无PAE)
硬件 PTE (Valid=1):
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──┬─┬───────────────────┐
│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
V=Valid, W=Write, O=Owner, WT=WriteThrough, CD=CacheDisable
A=Accessed, D=Dirty, L=LargePage, G=Global
CW=CopyOnWrite, Prot=Prototype, W=Wr (保留/软件)
软件 PTE (Valid=0):
┌─┬────────┬────────┬─┬─┬──────────────────────┐
│0│PageFile│Protect │0│0│ PageFileHigh (20位) │
│ │Low (4) │ion (5) │ │ │ │
└─┴────────┴────────┴─┴─┴──────────────────────┘
转换 PTE (Transition=1):
┌─┬─┬─┬─┬─┬────────┬─┬─┬──────────────────────┐
│0│W│O│WT│CD│Protect│0│1│ PageFrameNumber(20) │
│ │ │ │ │ │ion (5)│ │ │ │
└─┴─┴─┴─┴─┴────────┴─┴─┴──────────────────────┘
原型 PTE (Prototype=1, Valid=0):
┌─┬────────┬──┬─┬─┬───────────────────────────┐
│0│ProtoLow│RO│P│1│ SubsectionAddress (21位) │
│ │ (7位) │O │W│ │ │
└─┴────────┴──┴─┴─┴───────────────────────────┘
Subsection-format PTE (Prototype=1):
┌─┬────┬────────┬─┬───────────────────────────┐
│0│闁(4)│Protect │1│ SubsectionAddress (22位) │
│ │ │ion (5) │ │ │
└─┴────┴────────┴─┴───────────────────────────┘
11.2 保护常量
c
#define MM_ZERO_ACCESS 0
#define MM_READONLY 1
#define MM_EXECUTE 2
#define MM_EXECUTE_READ 3
#define MM_READWRITE 4
#define MM_WRITECOPY 5
#define MM_EXECUTE_READWRITE 6
#define MM_EXECUTE_WRITECOPY 7
#define MM_NOCACHE 8
11.3 特殊 PTE 值
c
// 用户地址零PTE
#define MM_ZERO_PTE 0x00000000
// 内核地址零PTE
#define MM_ZERO_KERNEL_PTE 0x00000000
// Demand-Write PTE (Protection=READWRITE, all else 0)
#define MM_DEMAND_ZERO_WRITE_PTE (MM_READWRITE << 5) // = 0x80
// 已释放PTE
#define MmDecommittedPte {0}
// 查找需要 (原型PTE延迟定位)
#define MI_PTE_LOOKUP_NEEDED 0xFFF
12. 锁体系
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 包含以下标志位:
c
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 ARM3 |
|---|---|---|
| WorkingSetMutex 显式初始化 | procsup.c:752 | 缺失 (依赖零初始化) |
| LastTrimTime 初始化 | KeQuerySystemTime | 缺失 |
| 会话工作集WSINFO | 必须使用全局地址 | 使用 session.c 中全局地址 |
| MM_DBG_PRINT 调试 | 有 (控制台 + 串口) | 有 (DPRINT1) |
| MmDebug 全局变量 | 有 | 有 (在 section.c) |
| 数据结构位置 | mi.h + ps.h | miarm.h + pstypes.h |
| 工作集修剪 | MiTrimWorkingSet | MiTrimWorkingSet (wrk_wsmanage.c) |