OS虚拟内存管理
虚拟内存管理是操作系统设计的核心点之一,涉及到 分页机制、安全性、内核态/用户态隔离、页表设计 等关键知识点。
4kb*1024 = 4M
下面这个是一级页表
实现一级页表要改下CR4 PSE的位
❓Q1:你是如何通过虚拟内存来实现内核与用户空间的隔离的?
✅ 推荐回答:
我使用的是 x86 的二级分页机制,每个任务有独立的页目录。在页表设计中,我将内核代码、数据等内容映射到高地址(如 0xC0000000 ~ 0xFFFFFFFF),并在页表中设置为 U/S=0,也就是用户进程不能访问的页。
用户空间(0x00000000 ~ 0xBFFFFFFF)由各进程的私有页表定义。内核页表部分在所有进程中是共享的,而用户部分各自独立,从而实现了虚拟内存上的隔离保护。
❓Q2:你怎么防止用户进程访问内核内存?
✅ 推荐回答:
在分页机制中,每个页表项都有一个 U/S(User/Supervisor)位。如果该位是 0,说明只有特权级为 0 的代码(内核)可以访问该页。
所以我在内核映射区域的页表项上都设置了 U/S=0,用户进程在 Ring3 尝试访问这些地址时,会触发 Page Fault 异常。我的异常处理器会记录这种越权行为并终止对应进程。
❓Q3:你每个用户进程的页表是怎么构建的?
✅ 推荐回答:
fork 时,我会复制当前进程的页目录表,用户空间部分为每个页分配新的物理页并复制内容(也可以拓展为写时复制 COW);而高地址的内核部分则直接指向内核的共享页表项。
execve 时,我会销毁原用户地址空间的页表,重新加载 ELF 文件的 .text/.data 段,并构建用户栈。最终把新的页目录地址写入 CR3,切换虚拟地址空间。
❓Q4:为什么内核空间要映射到高地址?
✅ 推荐回答:
把内核映射到高地址(例如从 0xC0000000 开始),可以清晰划分用户态和内核态的地址空间。
用户程序看到的虚拟地址是从 0x00000000 开始,而内核的地址从高地址开始,确保用户进程无法伪造指针访问内核。这个策略还允许内核在中断/系统调用时能继续使用自己熟悉的地址,不需要来回切换页表或复制内核数据。
❓Q5:CR3 是什么?它在进程切换中起什么作用?
✅ 推荐回答:
CR3 是 x86 架构中的页目录基地址寄存器,它指向当前激活的页目录物理地址。每次任务切换时,我会将新进程的页目录地址写入 CR3,这样虚拟地址的映射也就随之切换,实现了内存空间隔离。
✅ 二、答题要点总结(可以作为开场白)
你可以这样回答概括性的问题:
在我的操作系统中,我使用分页机制将虚拟地址映射到物理地址。通过将内核空间映射到高地址,并设置 U/S 位限制用户访问,实现了内核与用户空间的隔离。每个进程都有独立的页目录,切换进程时通过 CR3 切换页表,从而实现了每个进程拥有独立的地址空间,互不干扰。这既提高了安全性,也为多任务调度和用户态支持打下了基础。