#linux #linux-kernel #x86 #x86-64 #kernel-module
#linux #linux-ядро #x86 #x86-64 #kernel-module
Вопрос:
Я играю и пытаюсь вручную выполнить обход таблицы страниц на моем процессоре x86_64 с установленным Linux.
Я хочу попытаться получить то же значение с помощью Linux API и вручную просмотреть значения таблицы страниц.
Я нашел здесь: https://www.kernel.org/doc/gorman/html/understand/understand006.htmlчто значение CR3 должно быть равно current->mm->pgd. Но это не:
current->mm->pgd = 0x457ec6067
cr3 = 0x45700a006
current-> mm-> pgd, похоже, остается постоянным при выполнении. Чего я не понимаю?
Спасибо!
Редактировать. Это мой код:
__asm__ __volatile__ (
"mov %%cr3, %%raxnt"
"mov %%rax, %0nt"
: "=m" (cr3)
:
: "%rax"
);
pr_err("cr3 = 0x%lx ", (long)cr3);
pr_err("tcurrent->mm->pgd = 0x%lxn", current->mm->pgd->pgd);
Комментарии:
1. Какая у вас версия ядра Linux?
2. 4.15.0-45-универсальный с отключенным KPTI (это i9-9900K, который имеет аппаратные исправления)
3. Вы читаете
mm->pgd
иcr3
сразу одно за другим? Возможно ли, что расположение таблицы страниц верхнего уровня изменилось между чтениемmm->pgd
иcr3
?4. Приведенный вами код не подходит для чтения cr3 и pgd сразу друг за другом. Между ними есть ввод-вывод, возможно, включающий системный вызов.
5. Ссылка, на которую вы ссылались, не говорит о четырехуровневых таблицах страниц. У вас есть ссылка, в которой говорится, как pgd используется в x86-64?
Ответ №1:
Начиная с Linux 4.14, pgd
может быть преобразован в физический адрес страницы глобального каталога, в котором будет использоваться страница, cr3
путем вызова __sme_pa
и перехода к нему pgd
. Обратите внимание, что 12 младших значащих битов возвращаемого значения (которые представляют ASID) равны нулю. Таким образом, ASID должен быть связан с ним.
До Linux 4.14 __pa
можно было использовать вместо __sme_pa
, который не поддерживался. Обратите внимание, что это __pa
эквивалентно __sme_pa
на процессорах Intel, поскольку SME доступен только на процессорах AMD.
По крайней мере, начиная с Linux 2.6, pgd
и cr3
могут быть эквивалентны, а могут и не быть, в зависимости от двух факторов:
pgd
Больше ли виртуального базового адреса образа ядра__START_KERNEL_map
.phys_base
, которое представляет собой разницу между физическим базовым адресом образа ядра во время компиляции и физическим базовым адресом образа во время выполнения. Если изображение было перемещено,phys_base
не будет равно нулю.
Процесс перевода выполняется функцией с именем __phys_addr, к которой вы можете обратиться, чтобы следовать следующим примерам.
Я тестировал это на двух системах. В Linux 4.4.0 я получил следующие значения:
cr3 = 0x3581E000
pgd = 0x3581E000
__pa(pgd) = 0x3581E000
__START_KERNEL_map = 0x80000000
phys_base = 0x00000000
В этом случае pgd
и cr3
эквивалентны. В Linux 4.15:
cr3 = 0x8980A005
pgd = 0xC980A000
__pa(pgd) = 0x8980A000
__START_KERNEL_map = 0x80000000
phys_base = 0xEC000000