Windows Research Kernel (WRK) 内存管理器完整分析

Windows Research Kernel (WRK) 内存管理器完整分析

分析范围: WRK-v1.2/base/ntos/mm/

参考: Windows Server 2003 内核内存管理


目录

  1. 架构总览
  2. 核心数据结构
  3. 虚拟地址布局
  4. [Section 创建流程](#Section 创建流程)
  5. [View 映射流程](#View 映射流程)
  6. 缺页处理流程
  7. 工作集管理
  8. 进程地址空间初始化
  9. 系统初始化 (Phase 0/1)
  10. 会话管理
  11. [x86 PTE 详解](#x86 PTE 详解)
  12. 锁体系

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)
相关推荐
vortex52 小时前
PowerShell Provider 机制详解:从文件系统到注册表的统一抽象
windows·powershell
小狮子&4 小时前
ubuntu2604终端右键新建窗口
windows
shx_wei6 小时前
从函数调用到进程替换:使用 execl、CMake 与 PowerShell 构建一个多可执行程序
linux·c语言·windows·c
奶油话梅糖6 小时前
锐捷常用命令速查表
java·网络·windows
love530love6 小时前
CodexPro + MCP + Cloudflare 配置详解:HTTP2、QUIC 与连接排障
ide·人工智能·windows·ai agent
kyle~6 小时前
Schema---数据结构的形式化规则描述
数据结构·windows·microsoft
艾德金的溪7 小时前
【windows安装使用openclaw】
运维·windows·ai
love530love7 小时前
GPT + Codex CLI + CodexPro 三位一体:AI 编程协作工作流
人工智能·windows·gpt·chatgpt·devops·mcp
W是笔名7 小时前
python___容器类型的数据___列表
开发语言·windows·python