MM 学习笔记 10:页面文件与系统加载器

MM 学习笔记 10:页面文件与系统加载器

文件:ntoskrnl/mm/pagefile.c + ntoskrnl/mm/rmap.c + ntoskrnl/mm/ARM3/sysldr.c + ntoskrnl/mm/ARM3/mdlsup.c + ntoskrnl/mm/ARM3/iosup.c

日期:2026-07-19


1. 概述

这组文件涵盖内存管理的"外围"支持功能:

文件 行数 职责
pagefile.c ~900 行 页面文件管理:交换槽位分配、磁盘 I/O
rmap.c ~470 行 反向映射:从物理页找到对应的虚拟地址
sysldr.c ~3600 行 系统镜像加载器:PE 文件加载、导入表解析
mdlsup.c ~2000 行 MDL 管理:内存描述符列表、页面锁定
iosup.c ~500 行 I/O 空间映射:MmMapIoSpace / MmUnmapIoSpace

2. pagefile.c --- 页面文件管理

位置: ntoskrnl/mm/pagefile.c

2.1 SWAPENTRY 结构

SWAPENTRY 编码了页面文件索引和页面偏移:

c 复制代码
/*
 * 编码/解码宏
 */
#define FILE_FROM_ENTRY(i)    ((i) & 0x0f)            // 低4位:页面文件索引(最多16个文件)
#define OFFSET_FROM_ENTRY(i)  ((i) >> 11)             // 高比特位:页面偏移
#define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)  // 编码

SWAPENTRY 编码布局:

复制代码
31            11|10      4|3        0
┌────────────────┬──────────┬────────┐
│    页面偏移      │ 保留/标志 │ 文件索引 │
│   (21 bits)     │ (7 bits) │ (4 bits)│
└────────────────┴──────────┴────────┘
  • 最大支持 16 个页面文件(MAX_PAGING_FILES = 16)
  • 每个文件支持约 2M 个页面(21 位偏移)
  • 0x400 标志位表示该条目有效

2.2 核心全局变量

c 复制代码
PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];  // 页面文件数组
ULONG MmNumberOfPagingFiles;                    // 页面文件数量
PFN_COUNT MiFreeSwapPages;                      // 空闲交换页面数
PFN_COUNT MiUsedSwapPages;                      // 已使用交换页面数
PFN_COUNT MiReservedSwapPages;                  // 已保留交换页面数
KGUARDED_MUTEX MmPageFileCreationLock;          // 页面文件创建锁
BOOLEAN MmZeroPageFile;                          // 是否清零页面文件

// 页面文件最小/最大尺寸
#define MINIMUM_PAGEFILE_SIZE   (256ULL * PAGE_SIZE)  // 256页 = 1MB
#if defined(_M_IX86) && !defined(_X86PAE_)
#define MAXIMUM_PAGEFILE_SIZE   ((1ULL * 1024 * 1024 - 1) * PAGE_SIZE)  // ~4GB
#else
#define MAXIMUM_PAGEFILE_SIZE   ((4ULL * 1024 * 1024 * 1024 - 1) * PAGE_SIZE)  // ~16TB
#endif

// 提交比率控制
#define MM_PAGEFILE_COMMIT_RATIO      (1)     // 1:1 比率
#define MM_PAGEFILE_COMMIT_GRACE      (256)   // 256页的宽限

2.3 MmAllocSwapPage / MmFreeSwapPage 槽位管理

c 复制代码
SWAPENTRY
NTAPI
MmAllocSwapPage(VOID)

位置: pagefile.c:320

复制代码
MmAllocSwapPage
    │
    ├─ 加锁 MmPageFileCreationLock
    │
    ├─ 检查 MiFreeSwapPages > 0
    │
    ├─ 遍历所有页面文件
    │   └─ 查找有 FreeSpace 的文件
    │       └─ RtlFindClearBitsAndSet(PageFile->Bitmap, 1, 0)
    │
    ├─ 计算 SWAPENTRY
    │   └─ entry = ENTRY_FROM_FILE_OFFSET(i, off)
    │
    ├─ 更新统计
    │   ├─ PageFile->FreeSpace--
    │   ├─ PageFile->CurrentUsage++
    │   ├─ MiFreeSwapPages--
    │   └─ MiUsedSwapPages++
    │
    └─ 返回 SWAPENTRY
c 复制代码
VOID
NTAPI
MmFreeSwapPage(SWAPENTRY Entry)
复制代码
MmFreeSwapPage
    │
    ├─ i = FILE_FROM_ENTRY(Entry)
    ├─ off = OFFSET_FROM_ENTRY(Entry) - 1
    │
    ├─ RtlClearBit(PagingFile->Bitmap, off >> 5)
    │
    └─ 更新统计
        ├─ PagingFile->FreeSpace++
        ├─ PagingFile->CurrentUsage--
        ├─ MiFreeSwapPages++
        └─ MiUsedSwapPages--

2.4 MmWriteToSwapPage / MmReadFromSwapPage 磁盘 I/O

c 复制代码
NTSTATUS
NTAPI
MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)

位置: pagefile.c:147

复制代码
MmWriteToSwapPage
    │
    ├─ 解码 SWAPENTRY
    │   ├─ i = FILE_FROM_ENTRY(SwapEntry)
    │   └─ offset = OFFSET_FROM_ENTRY(SwapEntry) - 1
    │
    ├─ 构建 MDL(指向要写出的物理页)
    │   ├─ MmInitializeMdl(Mdl, NULL, PAGE_SIZE)
    │   └─ MmBuildMdlFromPages(Mdl, &Page)
    │
    ├─ 计算文件偏移
    │   └─ file_offset.QuadPart = offset * PAGE_SIZE
    │
    └─ 发起同步写操作
        └─ IoSynchronousPageWrite(FileObject, Mdl, &file_offset, &Event, &Iosb)
            └─ 如果 STATUS_PENDING → 等待
c 复制代码
NTSTATUS
NTAPI
MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)

位置: pagefile.c:204

复制代码
MmReadFromSwapPage
    │
    └─ 调用 MiReadPageFile(Page, FileIndex, PageFileOffset)
        │
        ├─ 构建 MDL
        ├─ 计算文件偏移
        └─ 发起同步读操作
           └─ IoPageRead(FileObject, Mdl, &file_offset, &Event, &Iosb)

2.5 页面文件 I/O 流程图

复制代码
         缺页异常 (Page Fault)
                │
                ▼
     MiResolvePageFileFault
                │
                ├─ 解析 SWAPENTRY 从 PTE
                │
                ├─ 分配物理页
                │
                └─ MmReadFromSwapPage(swapentry, page)
                        │
                        ▼
              MiReadPageFile
                        │
                        ├─ 构建 MDL
                        ├─ 计算偏移
                        └─ IoPageRead (同步)
                            └─ → 页面内容加载完成

         工作集修剪 (Trim)
                │
                ▼
           页面换出 (Page Out)
                │
                ├─ MmAllocSwapPage → 分配槽位
                │
                └─ MmWriteToSwapPage(swapentry, page)
                        │
                        ├─ 构建 MDL
                        └─ IoSynchronousPageWrite (同步)
                            └─ → 页面内容写入交换文件

2.6 NtCreatePagingFile 创建页面文件

c 复制代码
NTSTATUS
NTAPI
NtCreatePagingFile(
    IN PUNICODE_STRING PageFileName,
    IN PLARGE_INTEGER MinimumSize,
    IN PLARGE_INTEGER MaximumSize,
    IN ULONG Priority)

创建一个新的页面文件:

  1. 验证文件名和大小参数
  2. 检查是否超过 MAX_PAGING_FILES 限制
  3. 打开或创建文件
  4. 分配 MMPAGING_FILE 结构
  5. 初始化位图管理空闲槽位
  6. 添加到 MmPagingFile[] 数组

3. rmap.c --- 反向映射

位置: ntoskrnl/mm/rmap.c

3.1 概念

反向映射允许系统从一个物理页帧号(PFN)找到所有映射到它的虚拟地址。这对页面换出至关重要------当需要换出一个物理页面时,必须知道哪些进程映射了它,以便更新它们的 PTE。

数据结构:

复制代码
物理页 (PFN)
    │
    └─ 反向映射链表 (MM_RMAP_ENTRY)
        ├─ [0] → (进程A, 虚拟地址VA1)
        ├─ [1] → (进程B, 虚拟地址VA2)
        ├─ [2] → (段映射, 段指针)   ← RMAP_IS_SEGMENT 标记
        └─ ....

3.2 初始化

c 复制代码
CODE_SEG("INIT")
VOID
NTAPI
MmInitializeRmapList(VOID)
{
    ExInitializeNPagedLookasideList(&RmapLookasideList,
                                    NULL,
                                    RmapListFree,
                                    0,
                                    sizeof(MM_RMAP_ENTRY),
                                    TAG_RMAP,
                                    50);
}

使用 Lookaside 列表缓存 RMAP 条目,避免频繁分配/释放。

3.3 MmInsertRmap / MmDeleteRmap 映射管理

c 复制代码
NTSTATUS
NTAPI
MmInsertRmap(PEPROCESS Process, PVOID Address, PFN_NUMBER Page)

插入反向映射条目:

复制代码
MmInsertRmap(Process, Address, Page)
    └─ 从 Lookaside 列表分配 MM_RMAP_ENTRY
    └─ entry->Process = Process
    └─ entry->Address = Address
    └─ 插入到 Page 的反向映射链表头部
c 复制代码
NTSTATUS
NTAPI
MmDeleteRmap(PEPROCESS Process, PVOID Address, PFN_NUMBER Page)

删除反向映射条目:

复制代码
MmDeleteRmap(Process, Address, Page)
    └─ 遍历 Page 的反向映射链表
    └─ 找到匹配 (Process, Address) 的条目
    └─ 从链表移除
    └─ 释放回 Lookaside 列表

3.4 MmPageOutPhysicalAddress 页面换出

c 复制代码
NTSTATUS
NTAPI
MmPageOutPhysicalAddress(PFN_NUMBER Page)

位置: rmap.c:51

复制代码
MmPageOutPhysicalAddress(Page)
    │
    ├─ 获取反向映射条目的头
    │   └─ entry = MmGetRmapListHeadPage(Page)
    │
    ├─ 跳过段映射条目 (RMAP_IS_SEGMENT)
    │
    ├─ 获取进程和虚拟地址
    │   ├─ Process = entry->Process
    │   └─ Address = entry->Address
    │
    ├─ 获得进程的消亡保护
    │   └─ ExAcquireRundownProtection(&Process->RundownProtect)
    │
    ├─ 锁定地址空间
    ├─ 附加到进程(如果需要)
    │
    ├─ 为页面分配交换槽位
    │   └─ MmAllocSwapPage → swapentry
    │
    ├─ 写入交换文件
    │   └─ MmWriteToSwapPage(swapentry, Page)
    │
    ├─ 更新 PTE 为页文件 PTE
    │   └─ PTE 编码:Valid=0, PageFile=1, SwapEntry
    │
    ├─ 释放物理页
    │   └─ MmReleasePageMemoryConsumer(MC_USER, Page)
    │
    └─ 返回

4. sysldr.c --- 系统镜像加载器

位置: ntoskrnl/mm/ARM3/sysldr.c

4.1 概述

系统加载器负责将 PE 格式的内核模块(驱动、DLL)加载到系统空间。

c 复制代码
// 核心全局变量
LIST_ENTRY PsLoadedModuleList;           // 已加载模块链表
LIST_ENTRY MmLoadedUserImageList;        // 已加载用户映像链表
KSPIN_LOCK PsLoadedModuleSpinLock;       // 模块链表自旋锁
ERESOURCE PsLoadedModuleResource;        // 模块资源锁
ULONG_PTR PsNtosImageBase;               // NT 内核映像基址
KMUTANT MmSystemLoadLock;                // 系统加载互斥体

4.2 MmLoadSystemImage PE 文件加载

c 复制代码
NTSTATUS
NTAPI
MmLoadSystemImage(IN PUNICODE_STRING FileName,
                  IN PUNICODE_STRING NamePrefix OPTIONAL,
                  IN BOOLEAN SessionLoad,
                  IN BOOLEAN LoadSymbols,
                  OUT PVOID *ImageBase,
                  OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)

主要调用链:

复制代码
MmLoadSystemImage
    │
    ├─ 打开文件
    │   └─ IoCreateFile / ObReferenceObjectByHandle
    │
    ├─ 创建 Section
    │   └─ MmCreateSection → MmCreateArm3Section
    │
    └─ 加载镜像 Section
        └─ MiLoadImageSection

4.3 MiLoadImageSection 核心加载逻辑

位置: sysldr.c:78

这是驱动加载的核心函数:

复制代码
MiLoadImageSection(SectionPtr, ImageBase, FileName, SessionLoad, LdrEntry)
    │
    ├─ 附加到系统进程 (KeStackAttachProcess)
    │
    ├─ 映射 Section 视图
    │   └─ MmMapViewOfSection(Section, SystemProcess, ...)
    │
    ├─ 保留系统 PTE(用于驱动驻留)
    │   └─ MiReserveSystemPtes(PteCount, SystemPteSpace)
    │
    ├─ 分配物理页(循环)
    │   └─ for each PTE:
    │       ├─ PageFrameIndex = MiRemoveAnyPage(color)
    │       ├─ MiInitializePfn(PageFrameIndex, PointerPte, TRUE)
    │       └─ MI_WRITE_VALID_PTE(PointerPte, TempPte)
    │
    ├─ 复制镜像内容
    │   └─ RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT)
    │
    └─ 取消映射临时视图
        └─ MmUnmapViewOfSection(Process, Base)

关键代码片段:

c 复制代码
// 为驱动分配物理页
TempPte = ValidKernelPte;
while (PointerPte < LastPte)
{
    ASSERT(PointerPte->u.Hard.Valid == 0);
    MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);  // 标记为驱动页面
    
    PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
    MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
    
    TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    MI_WRITE_VALID_PTE(PointerPte, TempPte);
    PointerPte++;
}

// 复制映像内容
RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);

4.4 MiResolveImageReferences 导入表解析

解析 PE 文件的导入表,将导入符号解析为实际地址:

复制代码
MiResolveImageReferences(LdrEntry)
    │
    ├─ 遍历导入描述符 (IMAGE_IMPORT_DESCRIPTOR)
    │
    ├─ 对每个导入的 DLL:
    │   ├─ 查找已加载的 DLL(在 PsLoadedModuleList 中搜索)
    │   ├─ 如果未加载 → 先递归加载
    │   └─ 解析每个导入函数
    │
    └─ 对每个导入函数:
        ├─ NameToOrdinal → 查找导出名称表
        └─ MiSnapThunk → 修正 Thunk

4.5 MiSnapThunk Thunk 修正

修正导入地址表(IAT)中的每个条目:

复制代码
MiSnapThunk(ImageBase, Thunk, ImportTable, Reason)
    │
    ├─ 读取 Thunk 中的函数名或序号
    ├─ 通过 NameToOrdinal 或直接使用序号
    ├─ 在目标 DLL 的导出表中查找地址
    └─ 将解析后的地址写回 Thunk

辅助函数 NameToOrdinal

c 复制代码
USHORT
NTAPI
NameToOrdinal(PCSTR ExportName, PVOID ImageBase,
              ULONG NumberOfNames, PULONG NameTable, PUSHORT OrdinalTable)
{
    // 在名称表上执行二分查找
    Low = Mid = 0;
    High = NumberOfNames - 1;
    while (High >= Low)
    {
        Mid = (Low + High) >> 1;
        Ret = strcmp(ExportName, (PCHAR)RVA(ImageBase, NameTable[Mid]));
        if (Ret < 0)      High = Mid - 1;
        else if (Ret > 0) Low = Mid + 1;
        else              return OrdinalTable[Mid];
    }
    return -1;  // 未找到
}

4.6 MiFreeInitializationCode 初始化代码释放

系统启动后,MiFreeInitializationCode 释放标记为 INIT 的代码段(.init 节),回收物理页面:

复制代码
MiFreeInitializationCode
    │
    ├─ 遍历已加载模块链表
    │
    ├─ 对每个模块:
    │   ├─ 查找 INIT 节
    │   ├─ 释放物理页面(标记为空闲)
    │   ├─ 释放系统 PTE
    │   └─ 刷新 TLB
    │
    └─ 更新统计

5. mdlsup.c --- MDL 管理

位置: ntoskrnl/mm/ARM3/mdlsup.c

MDL(Memory Descriptor List)描述一段物理内存缓冲区,用于 I/O 操作。

5.1 MDL 结构

c 复制代码
typedef struct _MDL {
    struct _MDL *Next;         // 链表
    CSHORT Size;               // MDL 总大小
    CSHORT MdlFlags;           // 标志
    struct _EPROCESS *Process; // 所属进程
    PVOID MappedSystemVa;      // 系统空间映射地址
    PVOID StartVa;             // 起始虚拟地址
    ULONG ByteOffset;          // 页内偏移
    ULONG ByteCount;           // 字节数
    // 后面紧跟 PFN 数组
} MDL, *PMDL;

5.2 MmProbeAndLockPages

c 复制代码
VOID
NTAPI
MmProbeAndLockPages(IN PMDL Mdl,
                    IN KPROCESSOR_MODE AccessMode,
                    IN LOCK_OPERATION Operation)

核心流程:

复制代码
MmProbeAndLockPages(Mdl, AccessMode, Operation)
    │
    ├─ 锁定地址空间
    │   └─ MmLockAddressSpace
    │
    ├─ 遍历 MDL 覆盖的页面
    │   │
    │   ├─ ProbeAndReadAddress(用户模式地址探测)
    │   │
    │   ├─ MiAddressToPte → 获取 PTE
    │   │
    │   ├─ 解析 PTE:
    │   │   ├─ 如果无效 → 触发缺页异常(MmAccessFault)
    │   │   ├─ 如果转换中 → MiResolveTransitionFault
    │   │   └─ 有效 → 使用页面
    │   │
    │   ├─ 增加 PFN 引用计数
    │   │   └─ Pfn->ReferenceCount++
    │   │
    │   └─ 将 PFN 写入 MDL 的 PFN 数组
    │       └─ MdlPages[i] = PageFrameIndex
    │
    └─ 设置 MDL 标志
        └─ Mdl->MdlFlags |= MDL_PAGES_LOCKED

5.3 MmMapLockedPagesSpecifyCache

c 复制代码
PVOID
NTAPI
MmMapLockedPagesSpecifyCache(IN PMDL Mdl,
                             IN KPROCESSOR_MODE AccessMode,
                             IN MEMORY_CACHING_TYPE CacheType,
                             IN PVOID BaseAddress OPTIONAL,
                             IN BOOLEAN BugCheckOnFailure,
                             IN ULONG Priority)

将已锁定的页面映射到系统空间:

复制代码
MmMapLockedPagesSpecifyCache(Mdl, ...)
    │
    ├─ 如果是内核模式访问 → 直接计算地址
    │   └─ 返回 Mdl->StartVa + Mdl->ByteOffset
    │
    ├─ 用户模式访问 → 需要 VAD
    │   └─ MiMapLockedPagesInUserSpace(Mdl, ...)
    │       ├─ 分配 VAD(MMVAD_LONG)
    │       ├─ 查找空闲地址范围
    │       ├─ 设置页表项(使用 PFN 数组)
    │       └─ 设置缓存属性
    │
    └─ 设置 MDL_MAPPED_TO_SYSTEM_VA 标志

5.4 MmAllocatePagesForMdl / MmFreePagesFromMdl

c 复制代码
PMDL
NTAPI
MmAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
                      IN PHYSICAL_ADDRESS HighAddress,
                      IN PHYSICAL_ADDRESS SkipBytes,
                      IN SIZE_T TotalBytes)

分配物理页并创建 MDL:

复制代码
MmAllocatePagesForMdl
    ├─ 计算需要的页面数
    ├─ 分配 MDL 结构
    ├─ 分配物理页(从指定地址范围)
    ├─ 写入 PFN 数组
    └─ 返回 MDL
c 复制代码
VOID
NTAPI
MmFreePagesFromMdl(IN PMDL Mdl)

释放 MDL 中的物理页面:

复制代码
MmFreePagesFromMdl
    ├─ 遍历 MDL 的 PFN 数组
    ├─ 对每个页面:
    │   └─ MmReleasePageMemoryConsumer → 释放页面
    └─ 清除标志

6. iosup.c --- I/O 空间映射

位置: ntoskrnl/mm/ARM3/iosup.c

6.1 MmMapIoSpace

c 复制代码
PVOID
NTAPI
MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress,
             IN SIZE_T NumberOfBytes,
             IN MEMORY_CACHING_TYPE CacheType)

位置: iosup.c:46

将物理地址空间映射到内核虚拟地址空间,用于访问设备内存(MMIO):

复制代码
MmMapIoSpace(PhysicalAddress, NumberOfBytes, CacheType)
    │
    ├─ 1. 参数验证
    │      ├─ NumberOfBytes 必须大于 0
    │      └─ CacheType 必须在有效范围内
    │
    ├─ 2. 计算页面数
    │      └─ PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(...)
    │
    ├─ 3. 计算 PFN
    │      └─ Pfn = PhysicalAddress.QuadPart >> PAGE_SHIFT
    │
    ├─ 4. 获取缓存属性
    │      └─ CacheAttribute = MiPlatformCacheAttributes[isIoMapping][CacheType]
    │
    ├─ 5. 保留系统 PTE
    │      └─ PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace)
    │
    ├─ 6. 设置页表(循环)
    │      └─ for each page:
    │          ├─ TempPte = IoPteTemplate (写入合并/非缓存等)
    │          └─ MI_WRITE_VALID_PTE(PointerPte, TempPte)
    │
    └─ 7. 返回虚拟地址
           └─ BaseAddress = MiPteToAddress(PointerPte)

6.2 MmUnmapIoSpace

c 复制代码
VOID
NTAPI
MmUnmapIoSpace(IN PVOID BaseAddress, IN SIZE_T NumberOfBytes)

取消 I/O 空间映射:

  1. 计算页面数和起始 PTE
  2. 清零 PTE
  3. 释放系统 PTE
  4. 刷新 TLB

6.3 平台缓存属性表

c 复制代码
// 每种架构有自己的缓存属性
MI_PFN_CACHE_ATTRIBUTE MiPlatformCacheAttributes[2][MmMaximumCacheType] =
{
    // RAM 映射
    {MiNonCached, MiCached, MiWriteCombined, MiCached, MiNonCached, MiWriteCombined},

    // 设备内存映射
    {MiNonCached, MiCached, MiWriteCombined, MiCached, MiNonCached, MiWriteCombined},
};

7. 整体数据流

复制代码
                          ┌─────────────────┐
                          │   系统加载器      │
                          │   sysldr.c       │
                          │  MmLoadSystemImage│
                          └────────┬────────┘
                                   │ 加载驱动/内核模块
                                   ▼
                          ┌─────────────────┐
                          │   Section 创建   │
                          │   section.c      │
                          └────────┬────────┘
                                   │ 创建映射
                                   ▼
┌─────────────────┐      ┌─────────────────┐
│   页面文件管理    │◄─────│   缺页异常处理    │
│   pagefile.c    │      │   pagfault.c    │
│  MmWriteToSwap  │──────│  MiResolve*Fault│
│  MmReadFromSwap │      └─────────────────┘
└────────┬────────┘              │
         │                       │
         ▼                       ▼
┌─────────────────┐      ┌─────────────────┐
│   反向映射       │◄─────│   工作集修剪     │
│   rmap.c        │      │   balance.c     │
│  MmPageOut      │──────│  MmTrimUserMemory│
│  PhysicalAddress│      └─────────────────┘
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   MDL 管理      │
│   mdlsup.c      │
│ MmProbeAndLock  │
│ MmMapLockedPages│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   I/O 空间映射   │
│   iosup.c       │
│ MmMapIoSpace    │
│ MmUnmapIoSpace  │
└─────────────────┘

参考链接

  • pagefile.c --- 页面文件管理(file:///d:/reactos/ntoskrnl/mm/pagefile.c)
  • rmap.c --- 反向映射(file:///d:/reactos/ntoskrnl/mm/rmap.c)
  • sysldr.c --- 系统镜像加载器(file:///d:/reactos/ntoskrnl/mm/ARM3/sysldr.c)
  • mdlsup.c --- MDL 管理(file:///d:/reactos/ntoskrnl/mm/ARM3/mdlsup.c)
  • iosup.c --- I/O 空间映射(file:///d:/reactos/ntoskrnl/mm/ARM3/iosup.c)
  • Windows Internals 7th Part 1, Chapter 10 "Memory Management"

相关推荐
一只小菜鸡..1 小时前
南京大学 操作系统 (JYY) 学习笔记:Hello, OS World! (程序的机器视角)
java·笔记·学习
lazy H2 小时前
从入门到日常开发,一篇文章掌握 Git 核心操作
git·后端·学习·github
克里斯蒂亚诺更新11 小时前
ruoyi角色权限的对应关系
笔记
a11177613 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao14 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
破碎的南瓜15 小时前
sqli--sql注入过关笔记(1,2,3,4,5,9)
数据库·笔记·sql
你想知道什么?15 小时前
线性回归-学习笔记
笔记·学习·线性回归
鱼毓屿御15 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
谙弆悕博士15 小时前
系统集成项目管理工程师教程(第3版)笔记——第17章:法律法规和标准规范
笔记·职场和发展·学习方法·业界资讯·软考·法律·法规