正常
029_gui_canvas 排查笔记
问题 1:Canvas 测试后内核 hang(test_fifo_ordering)
现象
GUI ON 时,Canvas 测试全部通过后,test_fifo_ordering 在创建 fifo_owner 后 hang。GUI OFF 时基线 356 测试全过。
根因
Heap expand 无上限检查。KMEM_HEAP_SIZE = 1MB(仅初始大小),Heap 可无限 expand。Canvas 每次 init() 分配 ~3MB back_buf(1024x768x4),Heap 扩展到 ~3MB 后越界进入 MMIO/Stack 虚拟地址区域,导致 VMM 页表映射冲突,后续 TaskBuilder 分配栈时 g_vmm.map() 行为异常。
修复
heap.hpp:新增max_size_字段heap.cpp:init()中设置max_size_ = KMEM_HEAP_SIZE;expand()中检查size_ + expand_size > max_size_则返回 falsememory_layout.hpp:KMEM_HEAP_SIZE从 1MB 提到 128MB(GUI OS 合理值,物理页按需分配不浪费)
问题 2:test_create_user_space hang
现象
Heap 修复后,GUI ON 时 test_create_user_space hang。AddressSpace 构造中 phys_to_virt(pml4_phys_) = phys + 0xFFFFFFFF80000000,当 PMM 分配的物理页超过 loader 映射范围时 page fault。
根因
Loader 的 identity_map_up_to() 只映射到 ELF 段末尾(~20MB)。PMM 管理 9GB 物理内存,alloc_page() 可返回任意地址。当返回 >20MB 的物理页时,phys_to_virt() 返回的虚拟地址未被映射,访问即 page fault。
Canvas 测试消耗了大量低地址物理页(Heap expand),使后续分配更容易落到高地址区域。
修复
big_kernel_loader.cpp:phase2 中扫描 BootInfo 的 E820 memory map,找最高可用 RAM 地址,映射全部物理内存(Linux-style full direct map)- 用 2MB 大页映射 0-1GB,1GB 大页映射 >=1GB,开销极小(8GB 仅需 ~5 页页表)
附带修复
test_vmm.cpp:test_demand_page原来依赖地址未映射来触发 page fault,全量 direct map 后该假设不成立。改为验证高地址可通过 direct map 正常读写。
虚拟内存布局(修复后)
0xFFFF8000_00000000 KMEM_HEAP_BASE (128 MB reserved)
0xFFFF8000_08000000 KMEM_MMIO_BASE (256 KB)
0xFFFF8000_08040000 KMEM_STACK_BASE (1 MB, 向上增长)
0xFFFF8000_08140000 KMEM_DMA_BASE (1 MB)
0xFFFF8000_08240000 KMEM_EXT2_DMA_BASE (1 MB)
...
0xFFFF_FFFF_80000000 KERNEL_VMA (direct physical map, 全量)教训
- Heap expand 必须有上限:不能假设"虚拟地址空间无限就随便扩展",必须检查预留区域边界
- phys_to_virt 依赖 direct map 覆盖:loader 只映射 ELF 段是不够的,PMM 可能返回任意物理地址,必须全量映射或实现 kmap
- 测试要覆盖资源消耗场景:大块分配(Canvas 3MB)在单元测试中不可见,只有内核集成测试才会暴露内存布局冲突