物理内存管理 - 常见错误

错误 1:位图初始化错误

症状

所有内存分配失败,或分配到已使用的内存。

原因

位图未正确初始化。

解决方案

初始化策略:先全部标记为已使用(0xFF),然后标记已知可用区域为空闲。

memset(bitmap, 0xFF, BITMAP_SIZE);          // 全部标记已使用
pmm_mark_region_free(0x100000, available);  // 只释放确认可用的区域

错误 2:分配到内核代码所在的内存

症状

分配内存后,内核崩溃或行为异常。

原因

没有保护内核占用的物理内存。

解决方案

确保内核区域在位图中标记为已使用:

extern uint32_t _kernel_end;  // 链接脚本中定义
pmm_mark_region_used(0x1000, (uint32_t)&_kernel_end - 0x1000);

错误 3:位运算错误

症状

释放一个帧影响了相邻帧的状态。

原因

位操作时,frame/8 和 frame%8 混淆,或移位方向错误。

解决方案

// 正确的位操作
static inline void bitmap_set(uint32_t frame) {
    bitmap[frame / 8] |= (1 << (frame % 8));   // 设置
}
static inline void bitmap_clear(uint32_t frame) {
    bitmap[frame / 8] &= ~(1 << (frame % 8));  // 清除
}

错误 4:双重释放

症状

空闲帧计数异常(超过总帧数)。

原因

同一个帧被释放了两次。

解决方案

void pmm_free_frame(uint32_t phys_addr) {
    uint32_t frame = ADDR_TO_FRAME(phys_addr);
    if (!bitmap_test(frame)) {
        // 已经是空闲的,可能是bug
        screen_printf("[PMM] Warning: double free at 0x%x\n", phys_addr);
        return;
    }
    bitmap_clear(frame);
    used_frames--;
}

错误 5:kmalloc返回未对齐地址

症状

页表操作失败,因为地址不是4KB对齐。

原因

使用了普通kmalloc而非页对齐版本。

解决方案

// 页表、页目录等必须使用对齐版本
page_directory_t *dir = kmalloc_aligned(sizeof(page_directory_t));