解析 write_cr3()
和 read_cr3()
这两个函数是 内联汇编(inline assembly),用于在 x86 体系结构 中 读写 CR3 寄存器。
📌 CR3(控制寄存器 3)
- CR3 寄存器 在 x86 32 位分页机制(Paging)中,存储 页目录的物理地址。
- 修改 CR3 会 改变页表的基地址,相当于 切换页表(如切换进程的虚拟内存映射)。
- 读取 CR3 可以 获得当前进程的页目录地址。
1. write_cr3(uint32_t v)
作用:将 v
写入 CR3
,用于 设置新的页目录地址。
📌 代码
static inline void write_cr3(uint32_t v) {
__asm__ __volatile__("mov %[v], %%cr3"::[v]"r"(v));
}
📌 解析
-
__asm__ __volatile__
:asm
关键字:表示内联汇编。volatile
:防止编译器优化(因为CR3
读写影响 CPU 页表)。
-
mov %[v], %%cr3
- 把
v
这个变量的值 移动到CR3
,即:mov v, %cr3 // 把 v 赋值给 CR3
- 把
-
[v] "r"(v)
[v]
是 汇编变量占位符。"r"(v)
表示v
存放在通用寄存器(如eax
)。
📌 例子
uint32_t new_page_directory = 0x00100000; // 假设页目录在 1MB 处
write_cr3(new_page_directory); // 切换页表
✅ 将页目录基地址 0x00100000
加载到 CR3
,完成页表切换。
2. read_cr3()
作用:读取当前 CR3
寄存器的值,获取当前 页目录表的物理地址。
📌 代码
static inline uint32_t read_cr3() {
uint32_t cr3;
__asm__ __volatile__("mov %%cr3, %[v]":[v]"=r"(cr3));
return cr3;
}
📌 解析
-
mov %%cr3, %[v]
- 从
CR3
读取值 到cr3
变量,即:mov %cr3, cr3 // 把 CR3 值存到 cr3 变量
- 从
-
[v] "=r"(cr3)
[v]
是 占位符。"=r"(cr3)
表示:=
:表示这个变量是 输出变量。r
:存放在通用寄存器(如eax
)。
📌 例子
uint32_t current_cr3 = read_cr3();
printf("当前 CR3: 0x%X\n", current_cr3);
✅ 获取当前 CR3
值,输出当前页表的地址。
3. 作用总结
函数 | 作用 |
---|---|
write_cr3(uint32_t v) | 切换页表(修改 CR3) |
read_cr3() | 读取当前 CR3 值 |
write_cr3()
:用于 切换进程页表,如fork()
或execve()
。read_cr3()
:用于 调试,查看当前页表基地址。
4. CR3 的作用
在 分页机制(Paging)中,CR3
主要存储:
- 页目录基地址(Page Directory Base Address, PDBA)
- PCD(Page Cache Disable,页缓存禁止)
- PWT(Page Write-Through,写入策略)
格式(32 位模式)
| 31 12 | 11 | 10 | 9 - 0 |
| 页目录物理基地址(PDBA) | PCD | PWT | 保留 |
- 高 20 位:页目录的物理地址(必须是 4KB 对齐)。
- 低 12 位:标志位(如缓存策略)。
5. 什么时候用 write_cr3()
?
-
进程切换时(Context Switch)
- 每个进程有自己的页表(Page Table)。
write_cr3()
切换到新的页表。
write_cr3(new_process->page_directory);
-
初始化分页时
- 启动分页(Paging)时,设置
CR3
指向 内核页目录。
write_cr3(kernel_page_directory);
- 启动分页(Paging)时,设置
6. 结论
✅ read_cr3()
读取当前 CR3
(获取页目录基地址)。
✅ write_cr3()
写入 CR3
(切换页表,影响虚拟内存)。
✅ CR3
负责页表切换,是进程虚拟内存管理的核心。
🚀 x86 分页系统依赖 CR3
切换页表,write_cr3()
和 read_cr3()
是关键工具! 🎯