- Если запись в таблице страниц (PTE) помечена как глобальная в таблице страниц одного процесса, означает ли это, что PTE должен быть точно таким же/указывать на один и тот же физический блок во всех других таблицах страниц?
Если PTE имеет nG=0 (установлено как глобальное) в какой-то таблице страниц (в памяти), это ничего не значит. Но когда этот PTE загружается в кэш TLB, этот бит меняет способ сопоставления TLB этого виртуального адреса с этим кэшированным PTE (в режимах, когда поддерживаются ASID; «Чтобы решить эту проблему, ARMv8 также добавляет неглобальный (nG) флаг в дескриптор таблицы страниц, поэтому ASID игнорируется на определенных страницах путем снятия флага" - https://dl.acm.org/citation.cfm?id=3062267 «Изоляция данных на уровне инструкций для ядра на ARM»): каждый запрос сопоставляется с текущим ASID с ASID PTE для nG. =1 (процесс) сопоставлений, и будет соответствовать только виртуальному адресу для сопоставлений nG=0 (глобальных). Поэтому очень удобно, чтобы глобальные сопоставления были одинаковыми во всех таблицах страниц. И использовать их только для чего-то глобального, вроде адресного пространства ядра, без частых изменений.
- Что происходит в случае несоответствия? Я имею в виду, если один процесс имеет nG = 0, а другой имеет nG = 1 для одного и того же виртуального -> физического сопоставления, является ли это ошибочным созданием таблицы страниц из ОС?
Ничего не происходит, когда в памяти находится неправильный PTE. Когда он кэшируется в TLB и процесс переключается, для доступа к этому виртуальному адресу будет сгенерирован неверный физический адрес (отображение).
как ОС обеспечивает согласованность каждого глобального PTE в разных процессах, чтобы одно обновление глобального PTE отображалось во всех таблицах страниц процессов?
Когда ОС создает сопоставление, она редактирует соответствующие таблицы страниц. Таким образом, когда будет добавлено глобальное сопоставление, оно будет записано в нужное место. Я думаю (но не уверен), что можно частично разделить некоторые поддеревья таблиц страниц пространства ядра между процессами (когда архитектура реализует таблицы страниц в виде иерархических деревьев, как в x86). Часто существует разделение пространства ядра и пространства пользователя (исторически 2 ГБ/2 ГБ виртуального адресного пространства https://lkml.org/lkml/2006/1/10/189), а половина виртуальной памяти отображается для ядра (глобально). В ARM это разделение обычно является статическим, используя TTBR0 EL1 для корня таблицы страниц пространства пользователя и TTBR1 для корня таблицы страниц пространства ядра (http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/BABBEFAE.html с использованием регистра управления трансляцией TCR_EL1 найти точку разделения). С таблицами страниц L2/L3 ARM также будет иметь поддеревья в таблицах страниц, поэтому некоторые записи L2 разных процессов могут указывать на одну и ту же таблицу страниц L3 для части отображений ядра/глобала (см. рис. 12.8. Преобразование виртуального адреса в физический для страницы размером 64 КБ). в http://infocenter.arm.com/help/topic/com.arm.doc.den0024a/ch12s03.html Руководство программиста ARM Cortex-A Series для ARMv8-A — 12.3. Преобразование виртуального адреса в физический адрес). Другое возможное решение для управления глобальными сопоставлениями в различных процессах состоит в том, чтобы иметь ссылки из дескриптора памяти ОС (VMA в Linux) на все таблицы страниц, где он был зарегистрирован, и выполнять обновления с некоторой остановкой всех процессоров/ядер/процессов, которые могут его использовать. , измените сопоставление, выполните сброс tlb для диапазона на каждом ядре ЦП, отключите все процессоры/ядра/процессы.
Насколько я понимаю, ядро Linux 4.11 для ARM64 знает о бите NG как PTE_NG
arch/arm64/include/asm/pgtable-hwdef.h
:
#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */
но просто использует его, установив для него значение nG=1 ( process) везде для пространства пользователя и 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 «Разметка памяти в AArch64 Linux»
В адресах пользователей биты 63:48 установлены на 0, в то время как адреса ядра имеют те же биты, установленные на 1. Выбор TTBRx задается битом 63 виртуального адреса. swapper_pg_dir содержит только сопоставления ядра (глобальные), в то время как пользовательский pgd содержит только пользовательские (неглобальные) сопоставления. Адрес swapper_pg_dir записывается в TTBR1 и никогда не записывается в TTBR0.
person
osgx
schedule
25.06.2017
flush_tlb_*
: kernel.org/doc/Documentation/cachetlb.txt - person osgx   schedule 25.06.2017