![如何获取页表的物理地址?](https://linux22.com/image/228265/%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E9%A1%B5%E8%A1%A8%E7%9A%84%E7%89%A9%E7%90%86%E5%9C%B0%E5%9D%80%EF%BC%9F.png)
我试图获取物理地址页表本身,但一直失败。
我要尝试的最后一个选项是修改内核代码,并在创建或扩展分层页表时简单地打印出物理地址。
但是,是否有不同的方法来检查页表的物理地址?类似于简单地读取 /proc/PID/pagemap 来查找虚拟到物理映射的方法。
答案1
多重误解。
- 在现代处理器上,尤其是 aarch64、x86_64,不存在页表;而是存在页表。它是一个多级结构,可以在内存空间中任意分布。没有一个地址可以找到它!您需要具体说明您指的是哪个架构、哪个级别。
- 不一定每个体系结构实际上在物理地址空间中都有一个版本的页表。特别是嵌入式处理器类型确实为此内置了存储器,但它根本不在 RAM 中。同样,需要具体说明您所指的架构。
- 您问的是好像所有操作系统都是一样的 - 但 Linux 构建页表和与 mmu 交互的方式不一定与其他 unixoid 操作系统相同。你需要具体说明你的意思!
我要尝试的最后一个选项是修改内核代码,并在创建或扩展分层页表时简单地打印出物理地址。
有趣的是,这是你的最后的选项!用户空间,即对自己的虚拟内存空间进行分段、受保护访问的进程,通常不应看到 Danny 物理地址。事实上,对于我听说过的任何操作系统驱动程序框架来说,这都是一个相当固定的规则。如果任何东西将物理内存地址暴露给虚拟内存空间中的进程,那么该东西就会损坏并且必须修复。不错的规则 - 它避免了危险的错误,即允许用户空间将受操纵的物理地址返回给内核,从而访问进程不应访问的内存。
我强烈建议您在扩展页表时执行除打印之外的其他操作;这是一个坏主意,因为无论这意味着什么,它可能最终会出现在一个必须增长的缓冲区中,这会分配更多的内存,从而可能导致无限循环。您可以在各种 BSD 内核和 Linux 上使用探针来挂钩此类位置。
总而言之,在经典的 32 位 x86 中,当处于环 0 时,寄存器cr3
保存当前活动页目录的地址,该页目录保存页表的地址。请注意,受这些页表约束的进程应该无法访问该寄存器。
现在实际应用内存中的哪个视图取决于cr4,即进程上下文标识符是否被设置。
因此,要访问页表地址,您需要在“内核模式”下运行(如果您愿意的话),但需要将您感兴趣的进程的页目录基地址加载到 CR3 中。您也可以通过调试器直接从内核内存中获取数据 - 最后,切换到不同的任务需要将基地址保存在某些(特定于操作系统的)结构中,以供当前任务需要时使用待续。
请注意,通过虚拟化,“物理地址”实际上可能只是嵌套页表结构中的上一层。半虚拟化操作系统的内核也永远不会看到“真实”物理地址,但考虑到 iommu/smmu 概念,我什至不确定这里的“真实”一词有多大意义。