Что произойдет в ARMv8, если запись глобальной таблицы страниц конфликтует между разными процессами?

Я понимаю, что у каждого процесса могут быть отдельные таблицы страниц, и на них можно указать во время переключения контекста, обновив TTBR0/1_EL1. Внутри таблицы страниц каждого процесса некоторые записи будут специфичными для процесса (nG=1), а другие записи будут указывать на общие ресурсы (nG=0).

  1. Если запись в таблице страниц (PTE) помечена как глобальная в таблице страниц одного процесса, означает ли это, что PTE должен быть точно таким же/указывать на один и тот же физический блок во всех других таблицах страниц?
  2. Если да, что произойдет в случае несоответствия? Я имею в виду, если один процесс имеет nG = 0, а другой имеет nG = 1 для одного и того же виртуального -> физического сопоставления, является ли это ошибочным созданием таблицы страниц из ОС?
  3. Если мой второй вопрос актуален, как ОС обеспечивает согласованность каждого глобального PTE в разных процессах, чтобы одно обновление глобального PTE отображалось во всех таблицах страниц процессов?

Я искал в stack-overflow и других сайтах, но не смог найти удовлетворительного объяснения относительно обслуживания глобальных страниц.

Заранее спасибо !


person thorondor1990    schedule 24.06.2017    source источник
comment
Существует некоторый процесс с одним или несколькими потоками. ОС создает для этого процесса единую виртуальную трансляцию в физическую (таблицу страниц). Когда любой поток этого процесса находится на любом ЦП, регистры PT ЦП устанавливаются так, чтобы они указывали на таблицу страниц процесса. Таким образом, ОС делает PTE процессов согласованными, используя единую копию таблицы страниц со всех процессоров. И реальная проблема заключается в кэшировании PTE в TLB — когда один из PTE в памяти изменяется, TLB других процессоров, выполняющих потоки этого процесса (или имеющие кэш PTE в своем TLB), должны обновляться flush_tlb_*: kernel.org/doc/Documentation/cachetlb.txt   -  person osgx    schedule 25.06.2017
comment
Я понимаю аннулирование TLB для другого ядра, когда одно ядро ​​​​обновляет таблицу страниц того же процесса. Меня смущают глобальные страницы, которые должны быть одинаковыми (или, по крайней мере, я так думаю) для разных процессов. Если один процесс обновляет глобальный PTE, нужно ли распространять это обновление на таблицы страниц других процессов? Как это делается?   -  person thorondor1990    schedule 25.06.2017
comment
Это про линукс, какая версия? Можете ли вы связать некоторые документы ARM с описанием битов nG? В мире x86/x86_64 глобальная часть таблицы страниц (отрицательные адреса - мы интерпретируем указатель как знаковый) используется для памяти ядра, и она часто отображается с использованием больших страниц (2M, 1G) статически при загрузке и не изменяется. Другой (теоретический) способ - использовать поддерево таблицы с одной страницей для пространства ядра и просто ссылаться на него из всех таблиц страниц процесса (для этого все равно потребуется сброс tlb при изменении некоторых сопоставлений ядра). Ранее ttbr1 использовался для ядра elinux.org/Tims_Notes_on_ARM_memory_allocation.   -  person osgx    schedule 25.06.2017
comment
Я не спрашивал о какой-то конкретной ОС; просто хотел узнать пример того, как поддерживаются глобальные страницы. Вот ссылка, описывающая бит nG: static.docs.arm.com/ddi0487/ b/DDI0487B_a_armv8_arm.pdf . См. стр. D4-2116.   -  person thorondor1990    schedule 25.06.2017
comment
В Linux 4.11 он (nG=1) используется в отображении EFI и nG=1 для всех отображений нормалей: elixir.free-electrons.com/linux/v4.11/ident/PTE_NG.   -  person osgx    schedule 25.06.2017


Ответы (1)


  1. Если запись в таблице страниц (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 (глобальных). Поэтому очень удобно, чтобы глобальные сопоставления были одинаковыми во всех таблицах страниц. И использовать их только для чего-то глобального, вроде адресного пространства ядра, без частых изменений.

  1. Что происходит в случае несоответствия? Я имею в виду, если один процесс имеет 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
comment
Спасибо за объяснение! Таким образом, действительно существует требование, чтобы все записи глобальной таблицы страниц были одинаковыми для разных таблиц страниц процесса. - person thorondor1990; 26.06.2017
comment
В архитектуре ARM нет жестких требований к этому, это просто наиболее удобный способ управления. Мы можем представить некоторые случаи, когда будет несколько глобальных отображений, если у нас есть два набора процессов и мы никогда не будем отображать их в один и тот же набор ядер ЦП. По-видимому, Linux использует global только для TTBR1 и всегда использует одно и то же полудерево таблиц страниц для TTBR1 всех ядер. - person osgx; 26.06.2017