tianole/docs/agents/tasks/03-memory.md

6.6 KiB
Raw Blame History

03 内存管理

目标

从 boot memory map 建立 kernel 自己的内存模型,提供物理页、虚拟地址和内核堆能力。

前置条件

  • 异常处理可用,尤其是 page fault 路径。
  • early log 和 panic 可用。

建议边界

  • mm/:架构无关内存管理。
  • arch/x86/mm/page_table.c页表格式、地址空间切换、TLB 操作和 map/unmap/query 主路径。
  • arch/x86/mm/fault.cpage fault 诊断。
  • arch/x86/mm/page_table.hx86 页表子目录私有接口。
  • kernel/selftest/page_table.c:页表 map/unmap/query 启动自测。
  • include/tianole/:通用内存接口。

实现内容

  • 解析 boot memory map。
  • 归一化可用/保留/固件/内核占用区域。
  • 建立物理页分配器。
  • 建立内核虚拟地址布局。
  • 建立页表 map/unmap 接口。
  • 建立最小内核堆。
  • 为后续匿名页、缺页加载、COW、mmap、page cache、换页预留接口。

1. Memory map 与长期区域模型

  • boot memory map 只作为启动输入,不能直接成为长期内核内存类型。
  • 建立内核自己的 memory region 类型usable、reserved、kernel image、boot data、MMIO、ACPI reclaim 等。
  • 记录物理地址范围、页对齐、可分配性和后续热插拔/NUMA 预留信息。
  • 不写死物理内存大小、页数量或固件返回顺序。

2. Physical page allocator

  • 当前可以先用 free list但接口要允许替换为 buddy allocator。
  • 每个物理页后续要有 page metadata记录引用计数、状态、所属用途和链表节点。
  • allocator 需要能区分单页、小批量页和连续页需求。
  • 后续 DMA、page cache、匿名页、COW、swap 都要能复用同一 page model。

3. Virtual memory 与 page table

  • arch 页表代码负责页表格式、flag 编码、TLB 操作和地址空间切换。
  • 通用 MM 层负责虚拟地址区域、映射策略和对象生命周期。
  • 内核地址空间布局必须文档化,用户地址空间和内核地址空间要有硬边界。
  • page fault handler 要区分诊断、按需分配、权限错误和用户态进程终止。

4. Kernel heap 与小对象分配

  • 当前 kmalloc() 可以简单,但不能让调用方依赖永不失败或永不释放。
  • 小对象分配后续应演进到 slab/slub 或等价缓存分配器。
  • heap 元数据不能和 x86 页表实现强耦合。
  • 释放路径要能检测基础错误,例如 double free 或明显越界的后续调试接口。

5. Future VM capabilities

  • 为匿名页、文件页、page cache、COW、mmap、换页和内存回收预留结构边界。
  • VFS/page cache 不能绕过 MM 直接私有管理所有缓存页。
  • 用户态出现前可以先只做 kernel mapping但接口不能排斥多地址空间。
  • 后续进程退出必须能回收地址空间、页表页、匿名页和文件映射引用。

Linux 参考原则

  • 参考 Linux buddy + slab/slub 分层:页级分配和小对象分配分开演进。
  • 参考 Linux struct page 思路:物理页要有长期 metadata而不是只有 free list 节点。
  • 参考 Linux VMA/page fault 思路:缺页不是单纯 panic未来要能按区域策略处理。
  • 参考 Linux page cache 思路:文件缓存属于 MM/VFS 共同边界,不能被具体文件系统或块驱动私有化。

非玩具化约束

  • 不写死物理内存大小。
  • 不把 UEFI memory type 作为长期内核内存类型。
  • allocator 接口要允许后续替换为 buddy/slab。
  • 小对象分配要允许后续演进到 slab/slub 或等价缓存分配器。
  • 地址空间布局要文档化。
  • 用户地址空间和内核地址空间的边界不能依赖调用方自觉遵守。
  • 不能把 page cache 和匿名页排除在长期模型之外。
  • 页表实现不能混入启动 selftest 或具体业务逻辑。
  • 通用 MM 接口不能暴露 x86 页表 flag 编码。
  • page fault 诊断和 page fault 策略要分离。
  • 内核堆失败路径必须被调用方看见,不能默认分配永远成功。

验收方式

  • 能分配和释放多个物理页。
  • 能建立和删除虚拟映射。
  • page fault 能输出有效诊断。
  • 内核堆能分配小对象。
  • 后续能在此基础上加入 COW、mmap、换页和内存回收。
  • 页表 selftest 不和页表主实现混在同一文件职责内。
  • kmalloc()/kfree() 有基础复用验证。
  • page fault 测试能区分 not-present、权限和访问类型。
  • 后续添加用户地址空间时不需要重写物理页 allocator。

当前状态

基础完成:

  • 已从 boot memory map 扫描 conventional memory。
  • 已排除 kernel image、boot_info 和 boot memory map 占用页。
  • 已建立最小物理页 free-list allocator。
  • 已提供 alloc_page()free_page()
  • 已加入物理页分配/释放 selftest。
  • 已切换到内核自有 PML4不再直接修改固件页表。
  • 已提供最小 map_page()unmap_page()virt_to_phys() 接口。
  • 已加入页表 map/unmap/query selftest。
  • 已把 x86 页表 selftest 从 page_table.c 移到 kernel/selftest/page_table.c,避免页表主路径和启动验证逻辑混在同一目录边界。
  • 已拆出 x86 page fault 诊断路径,能输出 fault address、错误码、访问类型和权限来源。
  • 已建立最小内核堆,提供 kmalloc()kfree(),底层通过页表按需映射物理页。
  • 已加入内核堆分配、写入、释放、复用 selftest。
  • scripts/check.sh 已验证 physical pages free=、物理页 selftest、页表根切换、页表 selftest、内核堆 selftest 和 page fault 日志。

后续扩展:

  • 长期内存区域模型,不直接依赖 UEFI memory type。
  • page metadata。
  • buddy allocator。
  • slab/slub 或等价小对象缓存。
  • VMA 或等价虚拟区域管理。
  • 用户地址空间创建、复制和销毁。
  • COW、匿名页和文件页。
  • page cache、writeback 和内存回收。
  • swap 或等价换页机制。
  • DMA 可用内存和 MMIO 映射边界。

验收依据:

  • 正常启动日志包含 physical pages free=
  • 正常启动日志包含 physical page allocator selftest ok
  • 正常启动日志包含 kernel page table root active
  • 正常启动日志包含 page table selftest ok
  • 正常启动日志包含 kernel heap initialized
  • 正常启动日志包含 kernel heap selftest ok
  • page fault 测试日志包含 page fault: address=access=write mode=kernel reason=not-present

下一阶段:

  • 03-memory.md 的最小基础已经闭环。
  • 下一阶段可以进入 timer/scheduler如果继续打磨内存则应补 page metadata、buddy allocator 和 slab/slub。