拓冰建站拓冰建站
首页 / 资讯中心 / 正文

三层内存管理深度拆解:cavOS如何用PMM、VMM与4级页表管理内存

三层内存管理深度拆解cavOS如何用PMM、VMM与4级页表管理内存【免费下载链接】cavOS Amd64 operating system in C. Trying to make a full OS, with a simple and readable codebase!项目地址: https://gitcode.com/gh_mirrors/ca/cavOScavOS 是一个用 C 语言编写的 x86_64 操作系统它的内存子系统由三层清晰的模块构成PMM 物理内存管理器、VMM 虚拟内存管理器和4 级页表分页子系统。对新手来说理解这三层如何分工是读懂任何现代 OS 内存管理的最佳入口。这篇文章带你快速拆解它的设计思路与实现细节 cavOS 内存管理全景一个三层流水线cavOS 的内存管理遵循教科书式但实现极简的架构各层职责如下层级核心职责源码位置PMM物理页框分配与回收位图src/kernel/memory/pmm.cVMM内核虚拟地址空间HHDM 恒等映射src/kernel/memory/vmm.cPaging4 级页表翻译、进程地址空间src/kernel/memory/paging.cBitmap三者的公共数据结构src/kernel/utilities/data_structures/bitmap.c 一句话总结依赖关系PMM 管物理页归谁VMM 让内核免翻译地访问内存页表则把每个用户进程隔离进独立地址空间。PMM 物理内存管理器用 1 个 bit 管一个 4KB 页框cavOS 的 PMM 基于位图bitmap实现规则极简内存中每 4KB一个页框用 1 个 bit 表示占用/空闲定义在src/kernel/include/bitmap.h中BLOCK_SIZE 4096。这意味着内存开销非常小8GB 内存只需 262144 个 bit即约32KB 位图。物理内存位图的初始化内核启动时initiatePMM() 做了三件事从 Limine 引导器的内存映射表memmap中找一块足够大的可用区域放置位图把标记为LIMINE_MEMMAP_USABLE的区间全部置为空闲把不可用区间以及位图自身置为占用防止误分配。分配与释放自旋锁保护的页框分配PhysicalAllocate(pages)在自旋锁LOCK_PMM保护下扫描位图找到连续空闲区若内存耗尽会直接panic()——内核不向物理内存妥协。一个贴心的优化是lastDeepFragmented指针它记录碎片区边界让高频的单页分配跳过已碎片化的区域避免重复扫描见bitmap.c中的FindFreeRegion()。VMM 虚拟内存管理器HHDM 恒等映射这条捷径传统教程里内核往往要为自己也建一套完整的页表。cavOS 走了捷径——HHDMHigher Half Direct Mapping上半直映射Limine 引导器在启动时就把整段物理内存恒等映射到一个高虚拟地址区间偏移量即bootloader.hhdmOffset于是VirtualAllocate(pages)的逻辑只有两行从 PMM 拿物理页加上 hhdmOffset 就是可用的虚拟地址无需触碰任何页表源码中VMM_POS_ENSURE 0x40000000常量则提醒一个坑HHDM 可能以整 GB 大页映射分配起点必须对齐到 1GB 边界之上防止跨界踩坑 这正是内核能在分页系统就绪之前就开始工作的原因——启动代码里initiatePMM()和initiateVMM()都位于initiatePaging()之前src/kernel/entry/kernel.c注释明确写着None of the two depend on paging。4 级页表设计48 位虚拟地址是如何拆解的x86_64 的 4 级页表把 48 位虚拟地址切成 999912 五段每查一级缩小 512 倍最终落到 4KB 页位段层级表名每级覆盖47–39L1PML4512 项512 × 512GB38–30L2PDPT512 × 1GB29–21L3PD512 × 2MB20–12L4PT512 × 4KB11–0—页内偏移4096B各层的移位宏PML4E/PDPTE/PDE/PTE定义在src/kernel/include/paging.h中与 Intel 手册的位布局完全一致。页表查找VirtualMapL 的四步走VirtualMapL() 是建立虚拟地址 → 物理页映射的核心它沿 PML4→PDPT→PD→PT 逐级检查PF_PRESENT标志哪一层缺表页就用PagingPhysAllocate()从 PMM 现取一个物理页填上——按需懒分配所以一个进程不用为 256TB 地址空间预建全部页表叶子层若覆盖已有映射旧物理页会被回收画布帧缓冲区域除外最后执行invlpg指令刷新 TLB保证下一次访问走新映射。写入操作统一在读写计数自旋锁WLOCK_PAGING下完成兼顾中断上下文与调度器并发。虚拟转物理HHDM 快路径VirtualToPhysicalL()做反向翻译时有一个性能捷径若地址落在 HHDM 区间直接减去 hhdmOffset 就得到物理地址跳过整条页表查找链。源码中 2MB/1GB 大页的翻译分支目前是注释保留状态当前以 4KB 页为主属于清晰的 TODO 演进路线。进程地址空间页表克隆与 fork 时的页面拷贝多进程隔离靠每个任务一张独立 PML4实现建表PageDirectoryAllocate()为新任务分配一个页目录并完整拷贝内核任务 PML4 的 512 个顶层条目——内核映射所有进程共享用户区各自独立切换调度器通过ChangePageDirectory()修改 CR3 寄存器完成进程页表切换同时记录pagedirOverride供任务信息使用fork 拷贝PageDirectoryUserDuplicate()遍历源页目录中所有带PF_USER标志的页面逐页分配新物理页并memcpy4KB 后映射到目标目录PF_SHARED标记的页则直接共享物理页——目前是全量拷贝README 中也提到 COW写时复制在后续路线图中回收PageDirectoryFree()只释放PF_USER页对应的物理页确保内核映射永不被误回收。用户空间布局也定义在paging.h中方便理解各内存区的位置区域虚拟地址起点堆heap0x600000000000mmap 区0x700000000000栈底向下增长2048 页 ≈ 8MB0x800000000000启动初始化顺序三层的依赖关系打开src/kernel/entry/kernel.c的_start()初始化顺序就是依赖关系图串口、引导器解析、VGA/控制台——纯输出不碰内存管理initiatePMM → initiateVMM基于 HHDM 直接工作GDT、ACPI、ISR内存管理的地基异常与中断保护initiatePaging此时才接管 CR3开始维护全局页目录globalPagedir任务系统initiateTasks()此后每个新进程都会获得自己的页表。⚡ 记住这条链引导器 memmap → PMM 位图 → HHDM 虚拟分配 → 页表页分配 → 进程地址空间每一层都只站在上一层的肩上。总结从 cavOS 内存管理带走这 4 点位图 PMM用 1 bit 管 4KB 页框32KB 位图即可统管 8GB 内存配lastDeepFragmented抗碎片扫描VMM 的精髓是 HHDM 恒等映射——内核虚拟地址 物理地址 偏移把最复杂的页表操作从内核路径上彻底剔除4 级页表按需懒建表invlpg刷 TLB 收尾CR3 切换实现进程隔离fork 目前采用整页 memcpy 的全量拷贝代码风格高度可读每层几百行、注释坦率连todo都写在行内是学习 OS 内存管理难得的范例。顺着src/kernel/memory/目录通读 pmm.c、vmm.c、paging.c 三个文件配合本文的三层视角你完全可以亲手跑一遍这条内存管理流水线 【免费下载链接】cavOS Amd64 operating system in C. Trying to make a full OS, with a simple and readable codebase!项目地址: https://gitcode.com/gh_mirrors/ca/cavOS创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门