Переименование early_level4_pgt в early_top_pgt

pull/709/head
proninyaroslav 6 years ago
parent 6dc7698d6d
commit 1ec0602cc3

@ -125,16 +125,16 @@ rbp = 0x1000000 - (0xffffffff81000000 - 0xffffffff80000000)
Первым шагом, прежде чем начать настройку отображения страничной организации "один в один" (identity paging), является исправление следующих адресов:
```assembly
addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip)
addq %rbp, early_top_pgt + (L4_START_KERNEL*8)(%rip)
addq %rbp, level3_kernel_pgt + (510*8)(%rip)
addq %rbp, level3_kernel_pgt + (511*8)(%rip)
addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
```
Все адреса: `early_level4_pgt`, `level3_kernel_pgt` и другие могут быть некорректными, если `startup_64` не равен адресу по умолчанию - `0x1000000`. Регистр `rbp` содержит разницу адресов, поэтому мы добавляем его к `early_level4_pgt`, `level3_kernel_pgt` и `level2_fixmap_pgt`. Давайте попробуем понять, что означают эти метки. Прежде всего посмотрим на их определение:
Все адреса: `early_top_pgt`, `level3_kernel_pgt` и другие могут быть некорректными, если `startup_64` не равен адресу по умолчанию - `0x1000000`. Регистр `rbp` содержит разницу адресов, поэтому мы добавляем его к `early_top_pgt`, `level3_kernel_pgt` и `level2_fixmap_pgt`. Давайте попробуем понять, что означают эти метки. Прежде всего посмотрим на их определение:
```assembly
NEXT_PAGE(early_level4_pgt)
NEXT_PAGE(early_top_pgt)
.fill 511,8,0
.quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
@ -156,7 +156,7 @@ NEXT_PAGE(level1_fixmap_pgt)
.fill 512,8,0
```
Выглядит сложно, но на самом деле это не так. Прежде всего, давайте посмотрим на `early_level4_pgt`. Он начинается с (4096 - 8) нулевых байтов, это означает, что мы не используем первые `511` записей. После этого мы видим одну запись `level3_kernel_pgt`. Обратите внимание на то, что мы вычитаем из него `__START_KERNEL_map + _PAGE_TABLE`. Как известно, `__START_KERNEL_map` является базовым виртуальным адресом сегмента кода ядра, поэтому, если мы вычтем `__START_KERNEL_map`, мы получим физический адрес `level3_kernel_pgt`. Теперь давайте посмотрим на `_PAGE_TABLE`, это просто права доступа к странице:
Выглядит сложно, но на самом деле это не так. Прежде всего, давайте посмотрим на `early_top_pgt`. Он начинается с (4096 - 8) нулевых байтов, это означает, что мы не используем первые `511` записей. После этого мы видим одну запись `level3_kernel_pgt`. Обратите внимание на то, что мы вычитаем из него `__START_KERNEL_map + _PAGE_TABLE`. Как известно, `__START_KERNEL_map` является базовым виртуальным адресом сегмента кода ядра, поэтому, если мы вычтем `__START_KERNEL_map`, мы получим физический адрес `level3_kernel_pgt`. Теперь давайте посмотрим на `_PAGE_TABLE`, это просто права доступа к странице:
```C
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
@ -176,34 +176,34 @@ NEXT_PAGE(level1_fixmap_pgt)
После того как мы увидели определения этих символов, вернёмся к коду, описанному в начале раздела. Вы должны помнить, что регистр `rbp` содержит разницу между адресом символа `startup_64`, который был получен во время [компоновки](https://en.wikipedia.org/wiki/Linker_%28computing%29) ядра, и фактическим адреса. Итак, на данный момент нам просто нужно добавить эту разницу к базовому адресу некоторых записей таблицы страниц, чтобы получить корректные адреса. В нашем случае это записи:
```assembly
addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip)
addq %rbp, early_top_pgt + (L4_START_KERNEL*8)(%rip)
addq %rbp, level3_kernel_pgt + (510*8)(%rip)
addq %rbp, level3_kernel_pgt + (511*8)(%rip)
addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
```
последняя запись `early_level4_pgt` является каталогом `level3_kernel_pgt`, последние две записи `level3_kernel_pgt` являются каталогами `level2_kernel_pgt` и `level2_fixmap_pgt` соответственно, и 507 запись `level2_fixmap_pgt` является каталогом `level1_fixmap_pgt`.
последняя запись `early_top_pgt` является каталогом `level3_kernel_pgt`, последние две записи `level3_kernel_pgt` являются каталогами `level2_kernel_pgt` и `level2_fixmap_pgt` соответственно, и 507 запись `level2_fixmap_pgt` является каталогом `level1_fixmap_pgt`.
После этого у нас будет:
```
early_level4_pgt[511] -> level3_kernel_pgt[0]
early_top_pgt[511] -> level3_kernel_pgt[0]
level3_kernel_pgt[510] -> level2_kernel_pgt[0]
level3_kernel_pgt[511] -> level2_fixmap_pgt[0]
level2_kernel_pgt[0] -> 512 Мб, отображённые на ядро
level2_fixmap_pgt[507] -> level1_fixmap_pgt
```
Обратите внимание, что мы не исправили базовый адрес `early_level4_pgt` и некоторых других каталогов таблицы страниц, потому что мы увидим это во время построения/заполнения структур для этих таблиц страниц. После исправления базовых адресов таблиц страниц, мы можем приступить к их построению.
Обратите внимание, что мы не исправили базовый адрес `early_top_pgt` и некоторых других каталогов таблицы страниц, потому что мы увидим это во время построения/заполнения структур для этих таблиц страниц. После исправления базовых адресов таблиц страниц, мы можем приступить к их построению.
Настройка отображения "один в один" (identity mapping)
--------------------------------------------------------------------------------
Теперь мы можем увидеть настройку отображения "один в один" начальных таблиц страниц. В страничной организации с отображением "один в один", виртуальные адреса сопоставляются с физическими адресами, которые имеют одно и то же значение, `один в один`. Давайте рассмотрим это подробнее. Прежде всего, мы получаем `rip-относительные` адреса `_text` и `_early_level4_pgt` и помещаем их в регистры `rdi` и `rbx`:
Теперь мы можем увидеть настройку отображения "один в один" начальных таблиц страниц. В страничной организации с отображением "один в один", виртуальные адреса сопоставляются с физическими адресами, которые имеют одно и то же значение, `один в один`. Давайте рассмотрим это подробнее. Прежде всего, мы получаем `rip-относительные` адреса `_text` и `_early_top_pgt` и помещаем их в регистры `rdi` и `rbx`:
```assembly
leaq _text(%rip), %rdi
leaq early_level4_pgt(%rip), %rbx
leaq early_top_pgt(%rip), %rbx
```
После этого мы сохраняем адрес `_text` в регистр `rax` и получаем индекс записи глобального каталога страниц, который хранит адрес `_text`, путём сдвига адреса `_text` на `PGDIR_SHIFT`:
@ -221,7 +221,7 @@ level2_fixmap_pgt[507] -> level1_fixmap_pgt
#define PMD_SHIFT 21
```
После этого мы помещаем адрес первой записи таблицы страниц `early_dynamic_pgts` в регистр `rdx` с правами доступа `_KERNPG_TABLE` (см. выше) и заполняем `early_level4_pgt` двумя записями `early_dynamic_pgts`:
После этого мы помещаем адрес первой записи таблицы страниц `early_dynamic_pgts` в регистр `rdx` с правами доступа `_KERNPG_TABLE` (см. выше) и заполняем `early_top_pgt` двумя записями `early_dynamic_pgts`:
```assembly
leaq (4096 + _KERNPG_TABLE)(%rbx), %rdx
@ -229,7 +229,7 @@ level2_fixmap_pgt[507] -> level1_fixmap_pgt
movq %rdx, 8(%rbx,%rax,8)
```
Регистр `rbx` содержит адрес `early_level4_pgt` и здесь `%rax * 8` - это индекс глобального каталога страниц, занятого адресом `_text`. Итак, здесь мы заполняем две записи `early_level4_pgt` адресами двух записей `early_dynamic_pgts`, который связан с `_text`. `early_dynamic_pgts` является массивом массивов:
Регистр `rbx` содержит адрес `early_top_pgt` и здесь `%rax * 8` - это индекс глобального каталога страниц, занятого адресом `_text`. Итак, здесь мы заполняем две записи `early_top_pgt` адресами двух записей `early_dynamic_pgts`, который связан с `_text`. `early_dynamic_pgts` является массивом массивов:
```C
extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
@ -237,7 +237,7 @@ extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
который будет хранить временные таблицы страниц для раннего ядра и которые мы не будем перемещать в `init_level4_pgt`.
После этого мы добавляем `4096` (размер `early_level4_pgt`) в регистр `rdx` (теперь он содержит адрес первой записи `early_dynamic_pgts`) и помещаем значение регистра `rdi` (теперь он содержит физический адрес `_text`) в регистр `rax`. Далее мы смещаем адрес `_text` на `PUD_SHIFT`, чтобы получить индекс записи из верхнего каталога страниц, который содержит этот адрес, и очищаем старшие биты, для того чтобы получить только связанную с `pud` часть:
После этого мы добавляем `4096` (размер `early_top_pgt`) в регистр `rdx` (теперь он содержит адрес первой записи `early_dynamic_pgts`) и помещаем значение регистра `rdi` (теперь он содержит физический адрес `_text`) в регистр `rax`. Далее мы смещаем адрес `_text` на `PUD_SHIFT`, чтобы получить индекс записи из верхнего каталога страниц, который содержит этот адрес, и очищаем старшие биты, для того чтобы получить только связанную с `pud` часть:
```assembly
addq $4096, %rdx
@ -257,10 +257,10 @@ extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD];
На следующем шаге мы выполняем ту же операцию для последнего каталога таблиц страниц, но заполняем не две записи, а все, чтобы охватить полный размер ядра.
После заполнения наших начальных каталогов таблиц страниц мы помещаем физический адрес `early_level4_pgt` в регистр `rax` и переходим на метку `1`:
После заполнения наших начальных каталогов таблиц страниц мы помещаем физический адрес `early_top_pgt` в регистр `rax` и переходим на метку `1`:
```assembly
movq $(early_level4_pgt - __START_KERNEL_map), %rax
movq $(early_top_pgt - __START_KERNEL_map), %rax
jmp 1f
```
@ -587,14 +587,14 @@ BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END);
```C
for (i = 0; i < PTRS_PER_PGD-1; i++)
early_level4_pgt[i].pgd = 0;
early_top_pgt[i].pgd = 0;
next_early_pgt = 0;
write_cr3(__pa_nodebug(early_level4_pgt));
write_cr3(__pa_nodebug(early_top_pgt));
```
Вскоре мы создадим новые таблицы страниц. Далее в цикле мы проходим по всему глобальному каталогу страниц (`PTRS_PER_PGD` равен `512`) и обнуляем его. После этого мы устанавливаем `next_early_pgt` в ноль (подробнее об этом в следующей статье) и записываем физический адрес `early_level4_pgt` в `cr3`. `__pa_nodebug` - макрос, который выглядит следующим образом:
Вскоре мы создадим новые таблицы страниц. Далее в цикле мы проходим по всему глобальному каталогу страниц (`PTRS_PER_PGD` равен `512`) и обнуляем его. После этого мы устанавливаем `next_early_pgt` в ноль (подробнее об этом в следующей статье) и записываем физический адрес `early_top_pgt` в `cr3`. `__pa_nodebug` - макрос, который выглядит следующим образом:
```C
((unsigned long)(x) - __START_KERNEL_map + phys_base)

@ -133,10 +133,10 @@ ENTRY(clear_page)
После заполнения нулями `init_level4_pgt`, мы помещаем последнюю запись в `init_level4_pgt`:
```C
init_level4_pgt[511] = early_level4_pgt[511];
init_level4_pgt[511] = early_top_pgt[511];
```
Вы должны помнить, что мы очистили все записи `early_level4_pgt` функцией `reset_early_page_table` и сохранили только отображение ядра.
Вы должны помнить, что мы очистили все записи `early_top_pgt` функцией `reset_early_page_table` и сохранили только отображение ядра.
Последний шаг в функции `x86_64_start_kernel` заключается в вызове функции `x86_64_start_reservations`:

Loading…
Cancel
Save