mm学习笔记_05:虚拟内存核心与系统调用

发布时间:2026/7/22 22:29:52

mm学习笔记_05:虚拟内存核心与系统调用
mm学习笔记_05虚拟内存核心与系统调用基于 ReactOS ARM3 MM 源码ntoskrnl/mm/ARM3/virtual.c1. virtual.c 概述文件位置d:\reactos\ntoskrnl\mm\ARM3\virtual.c职责虚拟内存管理的核心实现以下关键系统调用NtAllocateVirtualMemory— 分配虚拟内存NtFreeVirtualMemory— 释放虚拟内存NtProtectVirtualMemory— 修改内存保护属性MmGetPhysicalAddress— 虚拟地址转物理地址MmCopyVirtualMemory— 跨进程内存拷贝2. NtAllocateVirtualMemory——完整路径文件virtual.c:44572.1 函数签名NTSTATUS NTAPINtAllocateVirtualMemory(IN HANDLE ProcessHandle,IN OUT PVOID*BaseAddress,IN ULONG_PTR ZeroBits,IN OUT PSIZE_T RegionSize,IN ULONG AllocationType,IN ULONG Protect);2.2 步骤一参数验证// 1. ZeroBits 检查不能超过最大值if(ZeroBitsMI_MAX_ZERO_BITS)returnSTATUS_INVALID_PARAMETER_3;// 2. AllocationType 合法性检查必须包含 MEM_COMMIT / MEM_RESERVE / MEM_RESETif(AllocationType~(MEM_COMMIT|MEM_RESERVE|MEM_RESET|...))returnSTATUS_INVALID_PARAMETER_5;if(!(AllocationType(MEM_COMMIT|MEM_RESERVE|MEM_RESET)))returnSTATUS_INVALID_PARAMETER_5;// 3. MEM_RESET 独占检查if((AllocationTypeMEM_RESET)(AllocationType!MEM_RESET))returnSTATUS_INVALID_PARAMETER_5;// 4. MEM_LARGE_PAGES 必须带 MEM_COMMITif((AllocationTypeMEM_LARGE_PAGES)!(AllocationTypeMEM_COMMIT))returnSTATUS_INVALID_PARAMETER_5;// 5. MEM_WRITE_WATCH 必须带 MEM_RESERVEif((AllocationTypeMEM_WRITE_WATCH)!(AllocationTypeMEM_RESERVE))returnSTATUS_INVALID_PARAMETER_5;// 6. MEM_PHYSICAL 必须带 MEM_RESERVE 且 Protect PAGE_READWRITEif((AllocationTypeMEM_PHYSICAL)...)...// 7. 保护属性验证ProtectionMaskMiMakeProtectionMask(Protect);if(ProtectionMaskMM_INVALID_PROTECTION)returnSTATUS_INVALID_PAGE_PROTECTION;// 8. 用户态参数捕获SEH 保护_SEH2_TRY{if(PreviousMode!KernelMode){ProbeForWritePointer(UBaseAddress);ProbeForWriteSize_t(URegionSize);}PBaseAddress*UBaseAddress;PRegionSize*URegionSize;}_SEH2_EXCEPT(...);// 9. 地址范围检查if(PBaseAddressMM_HIGHEST_VAD_ADDRESS)returnSTATUS_INVALID_PARAMETER_2;if(!PRegionSize)returnSTATUS_INVALID_PARAMETER_4;2.3 步骤二进程获取与附加// 如果是当前进程直接使用if(ProcessHandleNtCurrentProcess())ProcessCurrentProcess;else{// 否则以 PROCESS_VM_OPERATION 权限引用目标进程StatusObReferenceObjectByHandle(ProcessHandle,PROCESS_VM_OPERATION,PsProcessType,...);// 如果目标进程不是当前进程附加到目标进程地址空间if(CurrentProcess!Process){KeStackAttachProcess(Process-Pcb,ApcState);AttachedTRUE;}}2.4 步骤三MEM_RESERVE 主路径当未指定基址或指定 MEM_RESERVE 时1. 配额计费 PsChargeProcessNonPagedPoolQuota(sizeof(MMVAD_LONG)) 2. 分配 VADExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD_LONG), SdaV) 3. 初始化 VAD - Vad-u.VadFlags.PrivateMemory 1 - Vad-u.VadFlags.Protection ProtectionMask - if (AllocationType MEM_COMMIT) Vad-u.VadFlags.MemCommit 1 4. 插入 VAD自动查找空闲地址 Status MiInsertVadEx(Vad, StartingAddress, PRegionSize, HighestAddress, MM_VIRTMEM_GRANULARITY, AllocationType) 5. 写回用户参数SEH 保护 *URegionSize PRegionSize; *UBaseAddress (PVOID)StartingAddress;2.5 步骤四MEM_COMMIT 主路径当指定已有地址即对已预留区进行提交1. 锁定地址空间MmLockAddressSpace(AddressSpace) 2. 检查进程是否将终止 3. 查找冲突/匹配 VAD Result MiCheckForConflictingNode(StartVpn, EndVpn, Process-VadRoot, ...) 4. 验证 VAD 类型不能是 VadAwe/VadDevicePhysicalMemory/VadLargePages 5. 验证地址范围在 VAD 内 6. 如果是非私有内存Section 映射 - 获取原型 PTE - 锁定 MmSectionCommitMutex - 遍历 PTE 写入模板 PTE - 更新 NumberOfCommittedPages 7. 如果是私有内存 - 更新 CommitCharge 和 Process-CommitCharge - MiLockProcessWorkingSetUnsafe - 遍历每个 PTE - MiMakePdeExistAndMakeValid确保页表存在 - 写入 DemandZero 格式的 PTE保护属性 软件 PTE 标记 - MiUnlockProcessWorkingSetUnsafe完整流程图NtAllocateVirtualMemory │ ├─ 参数验证 │ ├─ ZeroBits 范围检查 │ ├─ AllocationType 组合检查 │ ├─ Protect 合法性检查 │ ├─ 用户态参数 Probe │ └─ 地址范围检查 │ ├─ 进程获取与附加KeStackAttachProcess │ ├─ [MEM_RESERVE 分支] │ ├─ 配额计费 │ ├─ 分配 VADExAllocatePoolWithTag │ ├─ VAD 初始化 │ └─ MiInsertVadEx自动搜索 Avl 插入 │ ├─ [MEM_COMMIT 分支] │ ├─ MmLockAddressSpace │ ├─ 查找已有 VADMiCheckForConflictingNode │ ├─ 验证 VAD 类型 │ ├─ [Section 内存] → 写原型 PTE → 更新段提交计数 │ ├─ [私有内存] → 更新 CommitCharge │ │ └─ 锁定工作集 │ │ └─ 遍历 PTE确保 PDE 有效写 DemandZero PTE │ └─ 解锁地址空间 │ └─ 返回 BaseAddress STATUS_SUCCESS3. NtFreeVirtualMemory——完整路径3.1 MEM_RELEASE 分支完整 VAD 释放四种释放情况情况1释放整个 VADBaseAddress VAD.StartingVpn, Size VAD 全范围 ─ 直接删除 VAD释放所有物理页 情况2释放 VAD 头部部分BaseAddress VAD.StartingVpn, Size VAD 全范围 ─ 调整 VAD.StartingVpn 原起始地址 Size ─ 释放对应 PTE 情况3释放 VAD 尾部部分BaseAddress VAD.StartingVpn, 释放到结束 ─ 调整 VAD.EndingVpn BaseAddress - 1 ─ 释放对应 PTE 情况4释放 VAD 中间部分释放中间一块两边保留 ─ 需要创建新 VAD 保存剩余后半部分 ─ 原 VAD 缩小到前半部分释放前 ┌──────────────────────────────┐ │ 原始 VAD │ └──────────────────────────────┘ 情况1 情况2 ┌──────────────────┐ ┌─────┐ ┌──────────┐ │ 全部释放 → 删除 │ │释放 │ │ 保留 │ └──────────────────┘ └─────┘ └──────────┘ Base StartingVpn 调整 情况3 情况4 ┌──────────┐ ┌─────┐ ┌─────┐ ┌──────┐ ┌─────┐ │ 保留 │ │释放 │ │释放 │ │ 保留1│ │保留2│ └──────────┘ └─────┘ └─────┘ └──────┘ └─────┘ (需要新建 VAD)3.2 MEM_DECOMMIT 分支取消提交// 1. 锁定地址空间// 2. 查找 VAD确认地址范围有效// 3. 调用 MiDecommitPages 取消提交// - 遍历指定范围的 PTE// - 对每个有效 PTE → 释放物理页、更新 PFN// - 将 PTE 写为 decommit 状态// 4. 更新进程 CommitCharge4. NtProtectVirtualMemory 路径通过MiProtectVirtualMemory实现1. 验证参数保护属性合法性 2. 锁定地址空间 3. 查找覆盖整个范围的 VAD 4. 调用 MiCheckSecuredVad 检查安全 VAD 限制 5. 锁定工作集 6. 遍历范围内的每个 PTE a. 如果 PTE 有效 - 修改硬件 PTE 的保护位 - 刷新 TLBKeFlushCurrentTb b. 如果 PTE 无效 - 修改软件 PTE 的保护位 c. 写时复制COW处理 - 如果新保护为只读但原为可写清除脏位 7. 更新 VAD 的保护属性 8. 解锁5. MiDeletePte——底层 PTE 删除逻辑文件virtual.c:369功能删除单个 PTE释放其引用的物理页。VOID NTAPIMiDeletePte(IN PMMPTE PointerPte,IN PVOID VirtualAddress,IN PEPROCESS CurrentProcess,IN PMMPTE PrototypePte){TempPte*PointerPte;if(TempPte.u.Hard.Valid0){// 无效 PTE可能是 Transition 或 PageFile 状态if(TempPte.u.Soft.Transition){// Transition PTE → 从列表中拆除递减引用MiUnlinkPageFromList(Pfn1);MiDecrementReferenceCount(Pfn1,PageFrameIndex);}// 忽略已换出PageFile的 PTE}else{// 有效 PTEPageFrameIndexPFN_FROM_PTE(TempPte);Pfn1MiGetPfnEntry(PageFrameIndex);if(Pfn1-u3.e1.PrototypePte1){// 原型 PTE → 递减页表共享计数和 PFN 共享计数MiDecrementShareCount(PageTablePfn,...);MiDecrementShareCount(Pfn1,PageFrameIndex);}else{// 普通 PTE → 标记删除递减共享计数MI_SET_PFN_DELETED(Pfn1);MiDecrementShareCount(Pfn1,PageFrameIndex);}// 擦除 PTEMI_ERASE_PTE(PointerPte);}KeFlushCurrentTb();}6. MiDeleteVirtualAddresses——批量 PTE 删除文件virtual.c:530功能批量删除指定虚拟地址范围内的所有 PTE。VOID NTAPIMiDeleteVirtualAddresses(IN ULONG_PTR Va,IN ULONG_PTR EndingAddress,IN OPTIONAL PMMVAD Vad){while(VaEndingAddress){// 逐级检查 PXE → PPE → PDE → PTE 的有效性// 跳过无效的大页表区域AddressGap// 对每个有效 PTE 调用 MiDeletePte// 递减页表引用计数必要时删除 PDEVaPAGE_SIZE;}}关键特点支持多级页表x86 PAE / x86-64的地址间隙跳过对 Section VAD 的间隙处理通过MI_GET_PROTOTYPE_PTE_FOR_VPN跳到下一个原型 PTE批量删除过程中保持 PFN 锁定7. MiDecommitPages——页面取消提交功能将已提交的页面取消提交释放物理内存但保留 VAD 结构。1. 遍历指定地址范围的每个 PTE 2. 对每个 PTE a. 如果 PTE 有效Valid1 - 获取 PFN - 标记 PFN 已删除MI_SET_PFN_DELETED - 递减 ShareCount - 擦除 PTE b. 如果 PTE 是 Transition 状态 - 从列表中拆除 PFN - 递减引用计数 c. 如果 PTE 是 DemandZero 状态 - 直接擦除 PTE 3. 更新进程/系统提交计数 4. 刷新 TLB8. MmGetPhysicalAddress——虚拟地址转物理地址文件virtual.c:5681PHYSICAL_ADDRESS NTAPIMmGetPhysicalAddress(PVOID Address){// 1. 检查 PDE 是否有效对大页 SPI 还检查 PPE/PXEif(MiAddressToPde(Address)-u.Hard.Valid){// 2. 检查是否为大页LargePageTempPde*MiAddressToPde(Address);if(TempPde.u.Hard.LargePage){// 大页偏移 地址低 22 位4MB 大页PhysicalAddress.QuadPart(ULONG64)TempPde.u.Hard.PageFrameNumberPAGE_SHIFT;PhysicalAddress.QuadPart((ULONG_PTR)Address(PAGE_SIZE*PTE_PER_PAGE-1));returnPhysicalAddress;}// 3. 检查 PTE 是否有效TempPte*MiAddressToPte(Address);if(TempPte.u.Hard.Valid){// 物理地址 PFN 12 页内偏移PhysicalAddress.QuadPart(ULONG64)TempPte.u.Hard.PageFrameNumberPAGE_SHIFT;PhysicalAddress.QuadPart((ULONG_PTR)Address(PAGE_SIZE-1));returnPhysicalAddress;}}// 4. 无效地址返回 0PhysicalAddress.QuadPart0;returnPhysicalAddress;}9. MmCopyVirtualMemory——跨进程内存拷贝文件virtual.c:1269两种策略基于数据量选择9.1 大拷贝 512 字节MDL 映射方式MiDoMappedCopyBufferSize MI_POOL_COPY_BYTES (512) → MiDoMappedCopy 流程 1. 循环拷贝每次最大 14 页MI_MAPPED_COPY_PAGES * PAGE_SIZE 56KB 2. 附加到源进程 → ProbeForRead → MmProbeAndLockPages → MmMapLockedPagesSpecifyCache 3. 分离源进程 4. 附加到目标进程 → ProbeForWrite → RtlCopyMemory 5. 分离目标进程 6. MmUnmapLockedPages → MmUnlockPages 7. 继续下一批数据9.2 小拷贝≤ 512 字节池缓冲方式MiDoPoolCopyBufferSize MI_POOL_COPY_BYTES (512) → MiDoPoolCopy 流程 1. 如果 BufferSize 512使用栈上缓冲StackBuffer否则分配 NonPagedPool 2. 附加到源进程 → ProbeForRead → RtlCopyMemory(池, 源) 3. 分离源进程 4. 附加到目标进程 → ProbeForWrite → RtlCopyMemory(目标, 池) 5. 分离目标进程 6. 重复直到所有数据拷贝完毕入口函数NTSTATUS NTAPIMmCopyVirtualMemory(PEPROCESS SourceProcess,PVOID SourceAddress,PEPROCESS TargetProcess,PVOID TargetAddress,SIZE_T BufferSize,KPROCESSOR_MODE PreviousMode,PSIZE_T ReturnSize){if(!BufferSize)returnSTATUS_SUCCESS;// 获取目标进程的 rundown protectionif(!ExAcquireRundownProtection(Process-RundownProtect))returnSTATUS_PROCESS_IS_TERMINATING;if(BufferSizeMI_POOL_COPY_BYTES)StatusMiDoMappedCopy(SourceProcess,SourceAddress,...);elseStatusMiDoPoolCopy(SourceProcess,SourceAddress,...);ExReleaseRundownProtection(Process-RundownProtect);returnStatus;}附录virtual.c 函数一览函数行号功能MiCalculatePageCommitment40计算指定地址范围内的已提交页数MiMakeSystemAddressValid181确保系统页表地址有效触发缺页MiDeleteSystemPageableVm273删除可分页系统内存MiDeletePte367删除单个 PTEMiDeleteVirtualAddresses528批量删除 PTEMiDoMappedCopy793MDL 方式跨进程拷贝MiDoPoolCopy1018池缓冲方式跨进程拷贝MmCopyVirtualMemory1269跨进程内存拷贝入口MiProtectVirtualMemory22 (extern)修改内存保护属性MiGetPageProtection1359获取页面的保护属性NtAllocateVirtualMemory4457虚拟内存分配系统调用MmGetPhysicalAddress5681虚拟地址→物理地址转换

相关新闻

【Claude Code】使用政策拒绝 Claude Code unable to respond Usage Policy refusal 应对

【Claude Code】使用政策拒绝 Claude Code unable to respond Usage Policy refusal 应对

2026/7/22 22:29:52

文章目录 一、问题描述 1.1 环境信息 1.2 报错现象 二、根因分析 2.1 错误链路追踪 2.2 可能原因列举 三、解决方案 方案一:/rewind 回退到触发轮次之前(推荐) 方案二:/clear 启动全新会话 方案三:非交互模式(-p)的特殊处理 四、验证与回归测试 五、总结与预防 5.1 核心…

07.20.每日总结

07.20.每日总结

2026/7/22 22:29:52

7月20日总结 Linux基础 考试相关 复习前面讲过的所有命令 linux考试:91分 错题与不熟练的题: 存放了linux系统引导和启动时候使用的一些文件和目录的目录是/boot useradd添加用户时哪个选项可以指定描述信息-c 去掉vi编辑器中上一步错误的操作&#xff1…

五大餐饮收银软件排行榜,哪家具有高性价比

五大餐饮收银软件排行榜,哪家具有高性价比

2026/7/22 22:09:37

在餐饮业不断发展的今天,越来越多的餐饮老板选择淘汰传统的餐饮收银方式,转向更智能的餐饮经营,最为明显的改变就是购买餐饮收银软件。现如今的餐饮收银软件已经覆盖了餐饮经营的全流程,从扫码点餐到预定桌台,从会员营…

BirdNET-Go核心功能解析:本地AI模型如何实现高精度鸟类与蝙蝠识别

BirdNET-Go核心功能解析:本地AI模型如何实现高精度鸟类与蝙蝠识别

2026/7/22 23:29:54

BirdNET-Go核心功能解析:本地AI模型如何实现高精度鸟类与蝙蝠识别 【免费下载链接】birdnet-go Self-hosted realtime soundscape analyser for birds, bats and other wildlife. Multi-model local AI inference, runs 24/7 on a Raspberry Pi. 项目地址: https:…

Lenovo Legion Toolkit:拯救者笔记本的5大核心功能与3分钟部署指南

Lenovo Legion Toolkit:拯救者笔记本的5大核心功能与3分钟部署指南

2026/7/22 23:29:54

Lenovo Legion Toolkit:拯救者笔记本的5大核心功能与3分钟部署指南 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit …

inject.dart高级特性:泛型支持与复杂依赖关系处理

inject.dart高级特性:泛型支持与复杂依赖关系处理

2026/7/22 23:29:54

inject.dart高级特性:泛型支持与复杂依赖关系处理 【免费下载链接】inject.dart Compile-time dependency injection for Dart and Flutter 项目地址: https://gitcode.com/gh_mirrors/in/inject.dart 在Dart和Flutter开发中,依赖注入是实现代码解…

为什么选择BirdNET-Go?自建野生动物声音监测系统的5大优势

为什么选择BirdNET-Go?自建野生动物声音监测系统的5大优势

2026/7/22 23:29:54

为什么选择BirdNET-Go?自建野生动物声音监测系统的5大优势 【免费下载链接】birdnet-go Self-hosted realtime soundscape analyser for birds, bats and other wildlife. Multi-model local AI inference, runs 24/7 on a Raspberry Pi. 项目地址: https://gitco…

BitWHIP架构探秘:Rust实现的WebRTC客户端与服务器设计

BitWHIP架构探秘:Rust实现的WebRTC客户端与服务器设计

2026/7/22 23:29:54

BitWHIP架构探秘:Rust实现的WebRTC客户端与服务器设计 【免费下载链接】bitwhip CLI Native WebRTC Agent in Rust 项目地址: https://gitcode.com/gh_mirrors/bi/bitwhip BitWHIP是一款用Rust编写的CLI WebRTC代理,旨在提供低延迟的实时音视频传…

私有部署AI编码平台要花多少钱?从服务器到模型费用一笔笔算清楚

私有部署AI编码平台要花多少钱?从服务器到模型费用一笔笔算清楚

2026/7/22 23:19:54

很多团队在评估 AI 编码工具时,都会问一个问题:"私有部署到底要花多少钱?"厂商通常给你一个"联系我们获取报价",你心里就没底了。这篇文章不绕弯子,直接拿 MonkeyCode(开源&#xff0c…

微服务进阶:服务网格与Istio

微服务进阶:服务网格与Istio

2026/7/21 5:45:57

541|微服务进阶:服务网格与Istio 上篇文章我们聊了微服务的基本概念和拆分方法。 但微服务多了,问题也多了: 服务之间怎么通信? 怎么监控每个服务的调用链路? 熔断、限流、重试怎么做? 安全认证怎么统一? 以前这些都靠SDK库(比如Hystrix、Feign),每个服务都要集成…

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

零售超级终端全域协同:ShareKit 碰一碰商品流转业务落地案例

2026/7/21 9:56:14

一、零售门店全域协同业务背景与行业痛点 1.1 门店超级终端设备矩阵(连锁便利店/商超标准配置) 自助收银Kiosk一体机:顾客结算、自助核销优惠券、商品素材预览;运营折叠平板:店长后台商品上新、图片录入、活动配置、…

噗叽短视频界面分析

噗叽短视频界面分析

2026/7/21 3:09:32

1 和小红书类似,可以采用类似判断方法------------其实他比小红书好判断,因为他没有图片,控件位置几乎是固定的,都不用判断------------2 因为他没有点赞按钮------------而且几乎所有控件位置都是完全一样的,所以我就…

设计EDA 首席专家 12 维度 JD(HR 仅高管 / HRD 使用)

设计EDA 首席专家 12 维度 JD(HR 仅高管 / HRD 使用)

2026/7/22 0:08:09

定位:公司 EDA 技术最高负责人、技术天花板、战略级专家、流片总兜底人 属于P9/Fellow/ 首席科学家级,不做日常执行,管方向、管架构、管风险、管突破。1. 对标层级内部职级:P9 / 首席专家 / Fellow 外部对标:华为 20–…

费用率无法实时监控怎么办?费用率联动预算管理怎么实现?

费用率无法实时监控怎么办?费用率联动预算管理怎么实现?

2026/7/22 0:08:09

很多企业费用管控存在严重滞后性:日常差旅、招待、营销、人力费用持续发生,但费用率只能等到月末结账、营收数据出来后才能计算核对,月度中途费用超标、营收不达标导致的费用率失衡完全无法感知。等到月末发现整体费用率远超预算目标时&#…

设计EDA 研发总监 12 维度 JD(HR 内部仅高管层使用)

设计EDA 研发总监 12 维度 JD(HR 内部仅高管层使用)

2026/7/22 0:08:09

定位:公司 EDA / 设计平台最高管理岗,技术 管理 经营三重决策,对整体流片、效率、质量、成本、团队负最终责任1. 对标层级内部职级:M3 / P8 / 总监级 外部对标:华为 20 级、互联网 M2 / 总监、头部芯片 / EDA 公司研…