虚拟内存 - 练习题

练习 1:高半内核映射

修改vmm_init,将内核映射到虚拟地址0xC0000000(3GB处):

// 物理地址 0x0-0x400000 映射到虚拟地址 0xC0000000-0xC0400000
for (uint32_t i = 0; i < 1024; i++) {
    vmm_map_page(dir, 0xC0000000 + i * PAGE_SIZE, i * PAGE_SIZE, PAGE_WRITABLE);
}

注意:这需要同时保持恒等映射,直到跳转到高地址代码。

练习 2:页表遍历

实现一个函数打印当前的虚拟内存映射:

void vmm_dump_mappings(page_directory_t *dir) {
    // 遍历所有页目录条目和页表条目
    // 打印所有有效的映射: virtual -> physical [flags]
}

练习 3:需求分页

实现延迟分配(lazy allocation):

  1. vmm_map_page时只在页表中标记”待分配”(不分配物理帧)
  2. 第一次访问时触发缺页异常
  3. 在缺页处理器中分配物理帧并建立真正的映射

练习 4:写时复制(COW)

实现简单的Copy-on-Write:

  1. 两个页目录共享同一个物理页(标记为只读)
  2. 写入时触发缺页异常
  3. 在异常处理器中复制物理页并重新映射为可写

思考题

  1. 每个进程的页表结构需要占用多少内存?有什么优化方法?
  2. 为什么x86使用二级页表而非一级扁平页表?
  3. TLB的大小通常是多少?TLB miss的代价是什么?
  4. 如果CR3指向的物理地址本身被换出到磁盘,会发生什么?