Разница между значением CR3 и pgd_t

#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