【问题标题】:Why does CR3 register contents vary, when read each time from a kernel module?为什么每次从内核模块读取时,CR3 寄存器的内容会有所不同?
【发布时间】:2012-10-16 21:35:47
【问题描述】:

我正在编写一个内核驱动程序,旨在剖析 Linux 内核页表。 我发现,每当我从驱动程序内部读取 CR3 寄存器时,CR3 的内容每次读取时都会发生变化

为什么会这样?既然驱动在内核态执行,CR3需要指向内核页目录(对吧?),那为什么CR3每次都在变化呢?

如果 CR3 不断变化,驱动程序如何按预期正确访问内存?

【问题讨论】:

  • 根据我的阅读,CR3 的内容将是最后一个“运行”进程的 CR3(Linux 使用每个进程的分页结构)。所以我想分析变化没有多大意义。

标签: linux linux-kernel x86 linux-device-driver x86-64


【解决方案1】:

CR3 是页目录指针。至少每次地址空间改变时它都会改变。没有单一的“内核”内存空间。在大多数(全部?)内存模型中,您看到的 CR3 值将特定于您所在的地址空间上下文(例如,您正在处理来自哪个进程的系统调用等...)。

【讨论】:

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

正如其他人所提到的,您看到的是当前进程的“分页表”。对于 x86,输入低于 3 的权限级别不会更改页表。这就是大多数操作系统为内核保留部分虚拟地址空间的原因。该空间中的内存被映射到每个进程中。通过将页框中的 u/s 标志设置为“0”,可以对用户模式代码隐藏内核地址空间中的内存。这将其标记为“系统”内存而不是用户内存。

更改页表通常在转换内核模式后完成,这就是内核内存需要成为进程地址空间的一部分的原因。否则它不知道在哪里可以找到它的数据结构。一个例外是“系统管理模式”,它透明地切换地址空间。然而,这只能在响应“系统管理中断”时发生,需要主板的特殊硬件支持,并且设计上不能被操作系统抑制或响应。

否则,在保护模式下,页表的操作总是由操作系统完成,转换到内核模式之后。这就是“模式切换”比完整上下文切换更快的部分原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    相关资源
    最近更新 更多