为什么从内核模块中每次读取CR3寄存器的内容都会有所不同?

5
我正在编写一个内核驱动程序,旨在分析Linux内核页表。 我发现无论何时我从驱动程序中读取CR3寄存器,每次读取都会产生不同的CR3内容! 为什么会这样呢?因为驱动程序在内核模式下执行,所以CR3需要指向内核页目录(对吧?),那么为什么CR3每次都在变化呢? 如果CR3不断变化,驱动程序如何正确地访问内存,达到预期的效果呢?

据我所读,CR3的内容将是最后一个“运行”进程的CR3(Linux使用每个进程的分页结构)。因此,分析这种变化可能没有太多意义。 - appusajeev
2个回答

5
正如其他人所提到的,您正在看到当前进程的“页表”。在x86架构中,进入低于3的特权级不会改变页面表。这就是为什么大多数操作系统为内核预留了虚拟地址空间的部分。该空间中的内存映射到每个进程。内核地址空间中的内存可以通过将页面帧中的u/s标志设置为“0”来隐藏用户模式代码。这将其标记为“系统”内存而不是用户内存。
通常在转换到内核模式后才更改页面表,这就是为什么内核内存需要成为进程地址空间的一部分的原因。否则,它将无法找到它的数据结构。一个例外是“系统管理模式”,它会透明地切换地址空间。但是,这只能在响应“系统管理中断”时发生,并且需要主板的特殊硬件支持,而且设计上不能被操作系统压制或响应。
否则,在受保护模式下,页面表的操作始终由操作系统在进入内核模式后进行。这是一个“模式切换”比全文切换更快的原因之一。

3

CR3是指页面目录指针,它会在地址空间发生变化时进行更改。没有单一的“内核”内存空间。在大多数(或所有?)内存模型中,您所看到的CR3值将特定于您所处的地址空间上下文(例如,您正在处理系统调用的进程等等)。


假设我已经为我的内核模块声明了一个全局字符数组。现在,如果CR3指向的不是内核空间目录,而是指向其他位置,那么对该数组的访问将如何成功?实际上,这些访问确实会成功! - appusajeev
1
为什么访问不成功?使用不同的顶级页面目录并不意味着它不能指向您变量的相同物理地址。 - Andy Ross
你确定这就是发生的事情吗?因为这意味着每个进程的分页结构都必须包含所有这些内核数据的映射!这似乎不是一个好主意。这也会限制进程可以使用的地址范围。 - appusajeev
我几乎可以确定这就是正在发生的事情(请注意,较低级别的页面表可以共享)。你已经准备好了设备,请跟踪并自行找出答案。这不就是我们的目的吗? - Andy Ross
访问成功是因为内核模式地址空间对于每个进程都映射相同的方式。用户模式地址空间必须针对每个进程进行更改,这意味着CR3将根据正在运行的进程而改变。 - Robin Caron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接