在ARMv8中,如果全局页表条目在不同进程间发生冲突,会发生什么情况?

问题描述:

我知道每个进程都可以有单独的页表,并且可以在上下文切换期间通过更新TTBR0/1_EL1来指向每个进程。每个进程的内部页表中,一些条目将是特定于进程的(nG = 1),其他条目将指向公共资源(nG = 0)。在ARMv8中,如果全局页表条目在不同进程间发生冲突,会发生什么情况?

  1. 如果页表项(PTE)被标记为一个进程的页表全球性的,它意味着PTE必须完全相同/指向其它页表以完全相同的物理块?
  2. 如果是,在不一致情况下会发生什么情况?我的意思是,如果一个进程具有nG = 0,另一个进程对于相同的虚拟 - >物理映射具有nG = 1,是否从OS创建了错误的页表?
  3. 如果我的第二个问题是相关的,操作系统如何确保每个全局PTE在不同进程间保持一致,以便所有进程的页表都能看到全局PTE更新?

我在堆栈溢出和其他网站搜索,但无法得到关于全球页面维护的令人满意的解释。

在此先感谢!

+0

有一些进程有一个或多个线程。 OS为此过程(页面表)创建单个虚拟到物理转换。当此进程的任何线程位于任何CPU上时,CPU的PT寄存器将被设置为指向进程页表。因此,通过使用所有CPU的页表的单个副本,操作系统如何使PTE的过程保持一致。而真正的问题是TLB中的PTE缓存 - 当内存中的一个PTE改变时,其他CPU的TLB运行此进程的线程(或者将PTE缓存在它们的TLB中)应该更新为'flush_tlb_ *':https:// www .kernel.org/doc/Documentation/cachetlb.txt – osgx

+0

当一个内核更新SAME进程的页表时,我将TLB失效理解为另一个核心。我对全球页面感到困惑,这些页面需要与不同流程相同(或至少我认为)。如果一个进程更新全局PTE,那么更新是否需要传播到其他进程的页表?这是如何完成的? – thorondor1990

+0

关于Linux,哪个版本?你能用nG位描述链接一些ARM文档吗?在x86/x86_64世界中,页表中的全局“全局”部分(“负地址”是我们将指针解释为已签名的)用于内核内存,并且通常在引导时使用较大的页面(2M,1G)更改。其他(理论上)的方法是使用单页表子树作为内核空间,并从所有进程页表中链接到它(当某些内核映射发生更改时,它仍然需要tlb刷新)。早期的ttbr1被用于内核http:// elinux。org/Tims_Notes_on_ARM_memory_allocation – osgx

  1. 如果页表项(PTE)在一个进程的页表标记为全球性的,它意味着PTE必须完全相同/指向其他页与完全相同的物理块表?

如果PTE有NG = 0一些页表(在内存中)(设置为全局),没什么意思。但是,当此PTE加载到TLB缓存中时,此位将更改TLB如何将此虚拟地址与此缓存的PTE相匹配(在支持ASID的模式下;“”)要解决此问题,ARMv8还会在页面中添加一个非全局(nG)标志表格描述符,因此通过清除标志“ - https://dl.acm.org/citation.cfm?id=3062267”ARM内核的指令级别数据隔离“在特定页面上忽略ASID):每个请求都从当前ASID匹配到PTE ASID,nG = 1(进程)映射,并且仅基于nG = 0(全局)映射的虚拟地址进行匹配。因此,在全部页面表中保持全局映射是相同的。并且只将它们用于全局的东西,比如内核地址空间,而没有频繁的变化。

  1. 在不一致的情况下,会发生什么?我的意思是,如果一个进程具有nG = 0,另一个进程对于相同的虚拟 - >物理映射具有nG = 1,是否从OS创建了错误的页表?
开始=>

当不正确的PTE在内存中时没有任何反应。当它被缓存在TLB中并且进程切换时,将会为访问这个虚拟地址(映射)而生成错误的物理地址。

OS如何确保每个全局PTE在不同进程间保持一致,以便所有进程的页表都能看到全局PTE的一个更新?

当OS创建一些映射时,它会编辑相关的页表。所以,当添加全局映射时,它会将它写入正确的位置。我认为(但不确定)可以在进程间部分共享内核空间页表的一些子树(当架构在x86中像层次树一样实现页表时)。通常有内核空间 - 用户空间拆分(历史上2GB/2GB的虚拟地址空间https://lkml.org/lkml/2006/1/10/189),虚拟内存的一半映射为内核(全局)。在ARM上,使用EL1的用户空间页表根的TTBR0和用于内核空间页表根的TTBR1(带有用于查找分割点的转换控制寄存器TCR_EL1的http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/BABBEFAE.html),此拆分通常是静态的。对于L2/L3页表,ARM在页表中也会有子树,所以对于内核/全局映射的一部分,不同进程的某些L2记录可能指向相同的L3页表(请查看图12.8 64KB页的虚拟到物理地址转换在http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/ch12s03.html ARM Cortex-A系列ARMv8-A编程人员指南 - 12.3。将虚拟地址转换为物理地址)。在不同进程中管理全局映射的另一种可能的解决方案是从操作系统内存描述符(Linux中的VMA)到注册的所有页表的链接,并通过某种方式停止所有可以使用它的cpus/cores /进程,更改映射,在每个CPU内核上执行tlb刷新范围,停止所有cpus/cores /进程。

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

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

just uses it将其设置为G = 1(进程)处处为用户空间和NG = 0(全局)的内核空间(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

用户地址有位63:48设置为0,而内核地址具有 设置为1的相同位“上AArch64 Linux的内存布局” TTBRx选择由虚拟地址的第63位给出。 swapper_pg_dir仅包含内核(全局) 映射,而用户pgd仅包含用户(非全局)映射。 swapper_pg_dir地址写入TTBR1,并且从未写入 TTBR0。

+0

感谢您的解释!因此,对于不同的进程页表,确实需要保持所有全局页表项不变 – thorondor1990

+0

在ARM体系结构中没有硬性要求,它只是管理它的最便捷的方式。我们可以设想一些情况,如果我们有两组进程并且不会将它们映射到同一组CPU内核中,那么会有几个全局映射。显然,Linux只使用全局的TTBR1,并且在所有内核的TTBR1上始终使用相同的页表半树。 – osgx