我试图更好地理解,例如,x86,内核如何映射到每个进程地址空间,以便更改内核地址映射到的内容能够在所有进程和所有内核中进行更改。举一个具体的例子,假设在进程 A 中发生系统调用期间,内核地址 0xC0000004 被映射到页框 1000。
我的问题是:如何为可能在多个核心上同时运行的进程 B 和 C 以及当前未运行的进程更新这些映射?
我假设必须有某种方法让所有进程“指向”/仅引用一组中央内核页表,因此对该中央位置的更新意味着所有进程的更改。但是,如果每个核心都有自己的 MMU,那么多核心系统将如何处理这个问题呢?带有示例的演练可能非常有帮助。谢谢。
答案1
页表层次结构就是答案。 Linux 页表分为多个级别,这意味着当我们深入页表寻找有效的pte
.这通常被认为是一种空间优化(仅存储有效内存位置的页表,而不是整个进程地址空间)。但对于内核来说,这也是一种性能优化,因为这意味着可以在进程之间重用现有的内核页表映射。
内核映射更新并不像您最初想象的那么重要,因为通常情况下,您的内核地址空间更改示例将发生在低于页面全局目录 (PGD)(最高页表级别)的级别对于每个过程。正如内核页表隔离的解释所暗示的那样(KPTI),如果您可以从进程的页面全局目录中删除内核映射,则该进程应该无法访问任何内核代码。这意味着所有进程 PGD 都指向相同的较低级别内核页表。假设只有一个核心,这些较低页表上的任何内核内存更新都将对所有进程可见,只需内存中的一次更新。当然,此更新需要传播到所有 CPU,但这只是正常的缓存一致性更新。与手动更新计算机中运行的每个进程的映射相比,强度要低得多。