在 ARMv8 中,如果一个全局页 table 条目在不同进程之间发生冲突怎么办?

In ARMv8, what happens if a global page table entry conflict across different processes?

我知道每个进程都可以有单独的页面 table,并且可以在上下文切换期间通过更新 TTBR0/1_EL1 指向它们。在每个进程的页面 table 内,一些条目将是进程特定的 (nG=1),而其他条目将指向公共资源 (nG=0)。

  1. 如果页面 table 条目 (PTE) 在一个进程的页面-table 中被标记为全局,这是否意味着 PTE 必须完全相同/指向完全相同的物理块在所有其他页面中-tables?
  2. 如果是,如果不一致会怎样?我的意思是,如果一个进程的 nG = 0 而另一个进程的 nG = 1 用于相同的虚拟-> 物理映射,那么这是一个错误的页面-table 从 OS 创建吗?
  3. 如果我的第二个问题是相关的,OS如何确保每个全局 PTE 在不同进程中是一致的,以便所有进程的页面都能看到全局 PTE 的更新-tables?

我在 stack-overflow 和其他网站上进行了搜索,但没有得到关于全局页面维护的令人满意的解释。

提前致谢!

  1. If a page table entry (PTE) is marked as global in one process's page-table, does it mean that the PTE has to be exactly same / pointing to exact same physical block in all other page-tables?

如果 PTE 在某些页面-table(在内存中)有 nG=0(设置为全局),则没有任何意义。但是当这个 PTE 被加载到 TLB 缓存中时,这个位改变了 TLB 将这个虚拟地址与这个缓存的 PTE 匹配的方式(在支持 ASID 的模式下;“为了解决这个问题,ARMv8 还添加了一个非全局(nG)页面 table 描述符中的标志,因此通过清除标志 " - https://dl.acm.org/citation.cfm?id=3062267 "Instruction-Level Data Isolation for the Kernel on ARM")忽略特定页面上的 ASID:每个请求都从当前 ASID 匹配到nG=1(进程)映射的 PTE ASID,并且将仅基于 nG=0(全局)映射的虚拟地址进行匹配。因此,在所有页面 table 中保持全局映射相同是非常方便的。并且只将它们用于全局的东西,比如内核地址-space,不要经常更改。

  1. What happens in case of an inconsistency? I mean, if one process has nG = 0 and another has nG = 1 for same virtual->physical mapping, is that a faulty page-table creation from OS?

当错误的 PTE 在内存中时没有任何反应。当缓存在TLB中,进程切换时,访问这个虚拟地址(映射)会产生错误的物理地址。

how does OS make sure that every global PTE is coherent across different processes, so that one update on Global PTE is seen by all processes' page-tables?

当 OS 创建一些映射时,它会编辑相关页面 table。因此,当添加全局映射时,它会将其写入正确的位置。我认为(但不确定)可以在进程之间部分共享 kernel-space pagetables 的一些子树(当体系结构将 page tables 实现为 x86 中的分层树时).经常有内核 space - 用户 space split (historically 2GB/2GB of virtual address space https://lkml.org/lkml/2006/1/10/189), and half of virtual memory is mapped for kernel (globally). On ARM this split is usually static using EL1's TTBR0 for user-space page table root and TTBR1 for kernel-space page table root (http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/BABBEFAE.html with Translation Control Register TCR_EL1 used to find the split point). With L2/L3 page tables ARM will have subtrees in page tables too, so some L2 records of different processes may point to the same L3 page table for part of kernel/global mappings (check Figure 12.8 Virtual to Physical Address translation for a 64KB page in http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/ch12s03.html ARM Cortex-A Series Programmer's Guide for ARMv8-A - 12.3. 翻译虚拟地址到物理地址)。在不同进程中管理全局映射的另一种可能的解决方案是从 OS 内存描述符(Linux 中的 VMA)到它注册的所有页面 tables 的链接,并使用一些进行更新停止所有可以使用它的 cpus/cores/processes,更改映射,在每个 CPU 核心上对范围进行 tlb 刷新,取消停止所有 cpus/cores/processes.

据我了解,Linux ARM64 内核 4.11 知道 NG 位为 PTE_NG arch/arm64/include/asm/pgtable-hwdef.h:

 #define PTE_NG         (_AT(pteval_t, 1) << 11)    /* nG */

just uses it 通过将它设置为 nG=1(进程),对于用户-space 和 nG=0(全局)对于内核-space(PROT_DEVICE_*, PROT_NORMAL_*, PROT_KERNEL_*): http://elixir.free-electrons.com/linux/v4.11/source/arch/arm64/include/asm/pgtable-prot.h#L67

#define PAGE_KERNEL     __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
#define PAGE_KERNEL_RO      __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
#define PAGE_KERNEL_ROX     __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
#define PAGE_KERNEL_EXEC    __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
#define PAGE_KERNEL_EXEC_CONT   __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
...
#define PAGE_NONE       __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_PXN | PTE_UXN)
#define PAGE_SHARED     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
#define PAGE_SHARED_EXEC    __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
#define PAGE_COPY       __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
#define PAGE_COPY_EXEC      __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
#define PAGE_READONLY       __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
#define PAGE_READONLY_EXEC  __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
#define PAGE_EXECONLY       __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN)

Linux/Aarch64 的文档仅说明 TTBR0/TTBR1:https://www.kernel.org/doc/Documentation/arm64/memory.txt "Memory Layout on AArch64 Linux"

User addresses have bits 63:48 set to 0 while the kernel addresses have the same bits set to 1. TTBRx selection is given by bit 63 of the virtual address. The swapper_pg_dir contains only kernel (global) mappings while the user pgd contains only user (non-global) mappings. The swapper_pg_dir address is written to TTBR1 and never written to TTBR0.