正常
设计图:一位一页的位图
先看位图这个数据结构怎么把物理内存"拍扁"成一张表:
text
物理内存(每页 4KB)
页0 页1 页2 页3 ... 页(4GB/4KB-1)= 1M 页
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
bit0 bit1 bit2 bit3 ... bit(1M-1)
└──────────── 一位一页,装进 128KB 的 s_bitmap ────────────┘
1=占用 0=空闲MAX_MEMORY = 4_GB、PAGE_SIZE = 4_KB,所以最多 MAX_PAGES = 1M 页,位图 BITMAP_SIZE = 1M/8 = 128KB(每字节 8 页)。这个 128KB 的数组是 PMM 的全部状态,放在内核的 .bss 里。
再看初始化的思路。这里有个反直觉但很稳的设计:先把所有页都标成"占用",再把能用的"挖"出来。这比"先全空、再标占用"安全——默认拒绝,只对确认可用的开绿灯,漏标顶多是少分到内存,绝不会把保留区误分出去:
text
init(boot_info):
① 位图全置 1(全占用) ← 默认拒绝
② 遍历 E820:
type==1(可用)的区域 →
滤掉低 1MB、页对齐 → 标 free(挖出来)
③ 内核自身区域 → 标 used(保护)
④ bootloader 区 0x0–0x10000 → 标 used(保护)alloc/free 则是在这张表上做最简单的位操作:
text
alloc_page(): 扫描位图找第一个 0 → 置 1 → 返回 该页物理地址(page_idx × 4KB)
扫不到 → 返 0(OOM)
free_page(p): p/4KB 得 page_idx → 该 bit 清 0