- 如果頁表項(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(全局)映射的虛擬地址進行匹配。因此,在全部頁面表中保持全局映射是相同的。並且只將它們用於全局的東西,比如內核地址空間,而沒有頻繁的變化。
- 在不一致的情況下,會發生什麼?我的意思是,如果一個進程具有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_NG
arch/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。
有一些進程有一個或多個線程。 OS爲此過程(頁面表)創建單個虛擬到物理轉換。當此進程的任何線程位於任何CPU上時,CPU的PT寄存器將被設置爲指向進程頁表。因此,通過使用所有CPU的頁表的單個副本,操作系統如何使PTE的過程保持一致。而真正的問題是TLB中的PTE緩存 - 當內存中的一個PTE改變時,其他CPU的TLB運行此進程的線程(或者將PTE緩存在它們的TLB中)應該更新爲'flush_tlb_ *':https:// www .kernel.org/doc/Documentation/cachetlb.txt – osgx
當一個內核更新SAME進程的頁表時,我將TLB失效理解爲另一個核心。我對全球頁面感到困惑,這些頁面需要與不同流程相同(或至少我認爲)。如果一個進程更新全局PTE,那麼更新是否需要傳播到其他進程的頁表?這是如何完成的? – thorondor1990
關於Linux,哪個版本?你能用nG位描述鏈接一些ARM文檔嗎?在x86/x86_64世界中,頁表中的全局「全局」部分(「負地址」是我們將指針解釋爲已簽名的)用於內核內存,並且通常在引導時使用較大的頁面(2M,1G)更改。其他(理論上)的方法是使用單頁表子樹作爲內核空間,並從所有進程頁表中鏈接到它(當某些內核映射發生更改時,它仍然需要tlb刷新)。早期的ttbr1被用於內核http:// elinux。org/Tims_Notes_on_ARM_memory_allocation – osgx