From 1ea0c43e7e6c85d1882a52f5762dd7ca87911500 Mon Sep 17 00:00:00 2001 From: proninyaroslav Date: Fri, 27 Jul 2018 21:05:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=20=D1=82=D0=B5=D1=80=D0=BC=D0=B8=D0=BD=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Booting/README.md | 3 ++- Booting/linux-bootstrap-2.md | 8 ++++---- Booting/linux-bootstrap-4.md | 20 ++++++++++---------- Initialization/linux-initialization-1.md | 16 ++++++++-------- Initialization/linux-initialization-2.md | 4 ++-- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Booting/README.md b/Booting/README.md index e9cab6c..1230259 100644 --- a/Booting/README.md +++ b/Booting/README.md @@ -1,6 +1,6 @@ # Процесс загрузки ядра -Эта глава описывает процесс загрузки ядра Linux. +Эта глава описывает процесс загрузки ядра Linux. Здесь вы увидите несколько статей, которые описывают полный цикл загрузки ядра: * [От загрузчика к ядру](linux-bootstrap-1.md) - описывает все стадии от включения компьютера до запуска первой инструкции ядра. @@ -8,3 +8,4 @@ * [Инициализация видеорежима и переход в защищённый режим](linux-bootstrap-3.md) - описывает инициализацию видеорежима в коде настройки ядра и переход в защищённый режим. * [Переход в 64-битный режим](linux-bootstrap-4.md) - описывает подготовку к переходу в 64-битный режим и детали перехода. * [Декомпрессия ядра](linux-bootstrap-5.md) - описывает подготовку перед декомпрессией ядра и детали самой декомпрессии. +* [Рандомизация адреса ядра](linux-bootstrap-6.md) - описывает рандомизацию адреса загрузки ядра Linux. diff --git a/Booting/linux-bootstrap-2.md b/Booting/linux-bootstrap-2.md index 2572e80..f714589 100644 --- a/Booting/linux-bootstrap-2.md +++ b/Booting/linux-bootstrap-2.md @@ -25,14 +25,14 @@ Основная причина не использовать [режим реальных адресов](http://wiki.osdev.org/Real_Mode) заключается в том, что возможен лишь очень ограниченный доступ к оперативной памяти. Как вы помните из предыдущей части, есть только 220 байт или 1 мегабайт, а иногда даже 640 килобайт оперативной памяти, доступной в режиме реальных адресов. -Защищённый режим принёс много изменений, но главным является отличие в управлении памятью. 20-битная адресная шина была заменена на 32-битную. Это позволило обеспечить доступ к 4 Гб памяти против 1 мегабайта в режиме реальных адресов. Также была добавлена поддержка [подкачки страниц](http://en.wikipedia.org/wiki/Paging), про которую вы можете прочитать в следующих разделах. +Защищённый режим принёс много изменений, но главным является отличие в управлении памятью. 20-битная адресная шина была заменена на 32-битную. Это позволило обеспечить доступ к 4 Гб памяти против 1 мегабайта в режиме реальных адресов. Также была добавлена поддержка [страничной организации памяти](http://en.wikipedia.org/wiki/Paging), про которую вы можете прочитать в следующих разделах. Управление памятью в защищённом режиме разделяется на две, почти независимые части: * Сегментация -* Подкачка страниц +* Страничная организация -Здесь мы будем рассматривать только сегментацию. Подкачка страниц будет обсуждаться в следующих разделах. +Здесь мы будем рассматривать только сегментацию. Страничная организация будет обсуждаться в следующих разделах. Как вы можете помнить из предыдущей части, адреса в режиме реальных адресов состоят из двух частей: @@ -162,7 +162,7 @@ lgdt gdt * Селектор сегмента должен быть загружен в один из сегментных регистров * CPU пытается найти дескриптор сегмента по адресу GDT + Index из селектора и загрузить дескриптор в *скрытую* часть сегментного регистра -* Базовый адрес (из дескриптора сегмента) + смещение будет линейным адресом сегмента, который является физическим адресом (если подкачка страниц отключена). +* Базовый адрес (из дескриптора сегмента) + смещение будет линейным адресом сегмента, который является физическим адресом (если страничная организация отключена). Схематично это будет выглядеть следующим образом: diff --git a/Booting/linux-bootstrap-4.md b/Booting/linux-bootstrap-4.md index 2921065..5e3c0a6 100644 --- a/Booting/linux-bootstrap-4.md +++ b/Booting/linux-bootstrap-4.md @@ -4,7 +4,7 @@ Переход в 64-битный режим -------------------------------------------------------------------------------- -Это четвёртая часть `Процесса загрузки ядра`, в которой вы увидите первые шаги в [защищённом режиме](http://en.wikipedia.org/wiki/Protected_mode), такие как проверка поддержки процессором [long mode](http://en.wikipedia.org/wiki/Long_mode) и [SSE](http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions), [подкачка страниц](http://en.wikipedia.org/wiki/Paging), инициализация таблиц страниц и в конце мы обсудим переход в [long mode](https://en.wikipedia.org/wiki/Long_mode). +Это четвёртая часть `Процесса загрузки ядра`, в которой вы увидите первые шаги в [защищённом режиме](http://en.wikipedia.org/wiki/Protected_mode), такие как проверка поддержки процессором [long mode](http://en.wikipedia.org/wiki/Long_mode) и [SSE](http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions), [страничная организация памяти](http://en.wikipedia.org/wiki/Paging), инициализация таблиц страниц и в конце мы обсудим переход в [long mode](https://en.wikipedia.org/wiki/Long_mode). **ЗАМЕЧАНИЕ: данная часть содержит много ассемблерного кода, так что если вы не знакомы с ним, вы можете прочитать соответствующую литературу** @@ -422,9 +422,9 @@ Long mode является расширением унаследованного * Включить [PAE](https://en.wikipedia.org/wiki/Physical_Address_Extension); * Создать таблицу страниц и загрузить адрес таблицы страниц верхнего уровня в регистр `cr3`; * Включить `EFER.LME`; -* Включить подкачку страниц. +* Включить страничную организацию памяти. -Мы уже включили `PAE` путём установки бита `PAE` в регистре управления `cr4`. Наша следующая цель - создать структуру для [подкачки страниц](https://en.wikipedia.org/wiki/Paging). Мы увидим это в следующем параграфе. +Мы уже включили `PAE` путём установки бита `PAE` в регистре управления `cr4`. Наша следующая цель - создать структуру для [страничной организации](https://en.wikipedia.org/wiki/Paging). Мы увидим это в следующем параграфе. Ранняя инициализация таблицы страниц -------------------------------------------------------------------------------- @@ -433,7 +433,7 @@ Long mode является расширением унаследованного **ПРИМЕЧАНИЕ: я не буду описывать теорию виртуальной памяти. Если вам необходимо больше информации по виртуальной памяти, см. ссылки в конце этой части.** -Ядро Linux использует `4 уровневую` подкачку страниц, и в целом мы создадим 6 таблиц страниц: +Ядро Linux использует `4 уровневую` страничную организацию, и в целом мы создадим 6 таблиц страниц: * Одну таблицу `PML4 (карта страниц 4 уровня, Page Map Level 4)` с одной записью; * Одну таблицу `PDP (указатель директорий страниц, Page Directory Pointer)` с четырьмя записями; @@ -497,7 +497,7 @@ pgtable: jnz 1b ``` -Мы помещаем базовый адрес указателя директорий страниц, который равен `4096` или, другими словами, смещение `0x1000` от таблицы `pgtable` в `edi`, и адрес первой записи указателя директорий страниц в регистр `eax`. Значение `4`, помещённое в регистр `ecx`, будет счётчиком в следующем цикле, в котором мы записываем адрес первой записи таблицы указателя директорий страниц в регистр `edi`. После этого `edi` будет содержать адрес первой записи указателя директорий страниц с флагами `0x7`. Далее мы просто вычисляем адрес следующих записей указателя директорий страниц, где каждая запись имеет размер `8` байт, и записываем их адреса в `eax`. Последний шаг в создании структуры подкачки страниц - создание `2048` записей с `2 мегабайтными` страницами: +Мы помещаем базовый адрес указателя директорий страниц, который равен `4096` или, другими словами, смещение `0x1000` от таблицы `pgtable` в `edi`, и адрес первой записи указателя директорий страниц в регистр `eax`. Значение `4`, помещённое в регистр `ecx`, будет счётчиком в следующем цикле, в котором мы записываем адрес первой записи таблицы указателя директорий страниц в регистр `edi`. После этого `edi` будет содержать адрес первой записи указателя директорий страниц с флагами `0x7`. Далее мы просто вычисляем адрес следующих записей указателя директорий страниц, где каждая запись имеет размер `8` байт, и записываем их адреса в `eax`. Последний шаг в создании страничной организации памяти - создание `2048` записей с `2 мегабайтными` страницами: ```assembly leal pgtable + 0x2000(%ebx), %edi @@ -547,7 +547,7 @@ pgtable: leal startup_64(%ebp), %eax ``` -После этого мы помещаем адрес в стек и включаем поддержку подкачки страниц путём установки битов `PG` и `PE` в регистре `cr0`: +После этого мы помещаем адрес в стек и включаем поддержку страничной организации путём установки битов `PG` и `PE` в регистре `cr0`: ```assembly pushl %eax @@ -590,10 +590,10 @@ ENTRY(startup_64) * [Документация для разработчиков ПО на архитектуре Intel® 64 и IA-32](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html) * [GNU компоновщик](http://www.eecs.umich.edu/courses/eecs373/readings/Linker.pdf) * [SSE](http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions) -* [Подкачка страниц (Википедия)](http://en.wikipedia.org/wiki/Paging) +* [Страничная организация памяти (Википедия)](http://en.wikipedia.org/wiki/Paging) * [Моделезависимый регистр](http://en.wikipedia.org/wiki/Model-specific_register) * [Инструкция .fill](http://www.chemie.fu-berlin.de/chemnet/use/info/gas/gas_7.html) * [Предыдущая часть](linux-bootstrap-3.md) -* [Подкачка страниц (OSDEV)](http://wiki.osdev.org/Paging) -* [Системы подкачки страниц](https://www.cs.rutgers.edu/~pxk/416/notes/09a-paging.html) -* [Пособие по подкачке страниц на x86](http://www.cirosantilli.com/x86-paging/) +* [Страничная организация памяти (OSDEV)](http://wiki.osdev.org/Paging) +* [Системы страничной организации памяти](https://www.cs.rutgers.edu/~pxk/416/notes/09a-paging.html) +* [Пособие по страничной организации на x86](http://www.cirosantilli.com/x86-paging/) diff --git a/Initialization/linux-initialization-1.md b/Initialization/linux-initialization-1.md index e5a582b..61830e8 100644 --- a/Initialization/linux-initialization-1.md +++ b/Initialization/linux-initialization-1.md @@ -88,7 +88,7 @@ rbp = 0x1000000 - (0xffffffff81000000 - 0xffffffff80000000) jnz bad_address ``` -Мы сравниваем нижнюю часть регистра `rbp` с дополняемым значением `PMD_PAGE_MASK`. `PMD_PAGE_MASK` указывает маску для `каталога страниц среднего уровня` (см. [подкачку страниц](../Theory/Paging.md)) и определён как: +Мы сравниваем нижнюю часть регистра `rbp` с дополняемым значением `PMD_PAGE_MASK`. `PMD_PAGE_MASK` указывает маску для `промежуточного каталога страниц` (см. [страничную организацию памяти](../Theory/Paging.md)) и определён как: ```C #define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1)) @@ -122,7 +122,7 @@ rbp = 0x1000000 - (0xffffffff81000000 - 0xffffffff80000000) Исправление базовых адресов таблиц страниц -------------------------------------------------------------------------------- -Первым шагом, прежде чем начать настройку подкачки страниц "один в один" (identity paging), является исправление следующих адресов: +Первым шагом, прежде чем начать настройку отображения страничной организации "один в один" (identity paging), является исправление следующих адресов: ```assembly addq %rbp, early_level4_pgt + (L4_START_KERNEL*8)(%rip) @@ -163,9 +163,9 @@ NEXT_PAGE(level1_fixmap_pgt) _PAGE_ACCESSED | _PAGE_DIRTY) ``` -Вы можете больше узнать об этом в статье [Подкачка страниц](../Theory/Paging.html). +Вы можете больше узнать об этом в статье [страничная организация памяти](../Theory/Paging.html). -`level3_kernel_pgt` хранит две записи, которые отображают пространство ядра. В начале его определения мы видим, что он заполнен нулями `L3_START_KERNEL` или `510` раз. `L3_START_KERNEL` - это индекс в верхнем каталоге страниц, который содержит адрес `__START_KERNEL_map` и равен `510`. После этого мы можем видеть определение двух записей `level3_kernel_pgt`: `level2_kernel_pgt` и `level2_fixmap_pgt`. Первая очень проста - это запись в таблице страниц, которая содержит указатель на каталог страниц среднего уровня, который отображает пространство ядра и содержит права доступа: +`level3_kernel_pgt` хранит две записи, которые отображают пространство ядра. В начале его определения мы видим, что он заполнен нулями `L3_START_KERNEL` или `510` раз. `L3_START_KERNEL` - это индекс в верхнем каталоге страниц, который содержит адрес `__START_KERNEL_map` и равен `510`. После этого мы можем видеть определение двух записей `level3_kernel_pgt`: `level2_kernel_pgt` и `level2_fixmap_pgt`. Первая очень проста - это запись в таблице страниц, которая содержит указатель на промежуточный каталог страниц, который отображает пространство ядра и содержит права доступа: ```C #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | \ @@ -199,7 +199,7 @@ level2_fixmap_pgt[507] -> level1_fixmap_pgt Настройка отображения "один в один" (identity mapping) -------------------------------------------------------------------------------- -Теперь мы можем увидеть настройку отображения "один в один" начальных таблиц страниц. В подкачке, отображённой "один в один", виртуальные адреса сопоставляются с физическими адресами, которые имеют одно и то же значение, `один в один`. Давайте рассмотрим это подробнее. Прежде всего, мы получаем `rip-относительные` адреса `_text` и `_early_level4_pgt` и помещаем их в регистры `rdi` и `rbx`: +Теперь мы можем увидеть настройку отображения "один в один" начальных таблиц страниц. В страничной организации с отображением "один в один", виртуальные адреса сопоставляются с физическими адресами, которые имеют одно и то же значение, `один в один`. Давайте рассмотрим это подробнее. Прежде всего, мы получаем `rip-относительные` адреса `_text` и `_early_level4_pgt` и помещаем их в регистры `rdi` и `rbx`: ```assembly leaq _text(%rip), %rdi @@ -264,7 +264,7 @@ extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD]; jmp 1f ``` -На данный момент это всё. Наша ранняя подкачка страниц настроена и нам нужно совершить последнее приготовление, прежде чем мы перейдём к коду на C и к точке входа в ядро. +На данный момент это всё. Наша ранняя страничная структура настроена и нам нужно совершить последнее приготовление, прежде чем мы перейдём к коду на C и к точке входа в ядро. Последнее приготовление перед переходом на точку входа в ядро -------------------------------------------------------------------------------- @@ -333,7 +333,7 @@ extern pmd_t early_dynamic_pgts[EARLY_DYNAMIC_PAGE_TABLES][PTRS_PER_PMD]; * `X86_CR0_NE` - позволяет включить внутреннюю x87 отчётность об ошибках с плавающей запятой, иначе включает PC-стиль x87 обнаружение ошибок; * `X86_CR0_WP` - если установлен, CPU не может писать в страницы только для чтения, когда уровень привилегий равен 0; * `X86_CR0_AM` - проверка выравнивания включена, если установлен AM и флаг AC (в регистре EFLAGS), а уровень привелигий равен 3; -* `X86_CR0_PG` - включает подкачку страниц. +* `X86_CR0_PG` - включает страничную организацию. с помощью выполнения данного ассемблерного кода: @@ -611,7 +611,7 @@ write_cr3(__pa_nodebug(early_level4_pgt)); -------------------------------------------------------------------------------- * [Моделезависимый регистр](http://en.wikipedia.org/wiki/Model-specific_register) -* [Подкачка страниц](Theory/Paging.md) +* [Страничная организация памяти](Theory/Paging.md) * [Предыдущая часть - Декомпрессия ядра](https://proninyaroslav.gitbooks.io/linux-insides-ru/content/Booting/linux-bootstrap-5.html) * [Бит NX](http://en.wikipedia.org/wiki/NX_bit) * [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization) diff --git a/Initialization/linux-initialization-2.md b/Initialization/linux-initialization-2.md index 9185720..9596d49 100644 --- a/Initialization/linux-initialization-2.md +++ b/Initialization/linux-initialization-2.md @@ -4,7 +4,7 @@ Начальная обработка прерываний и исключений -------------------------------------------------------------------------------- -В предыдущей [части](linux-initialization-1.md) мы остановились перед настройкой начальных обработчиков прерываний. На данный момент мы находимся в распакованном ядре Linux, у нас есть базовая структура [подкачки](https://en.wikipedia.org/wiki/Page_table) для начальной загрузки, и наша текущая цель - завершить начальную подготовку до того, как основной код ядра начнёт свою работу. +В предыдущей [части](linux-initialization-1.md) мы остановились перед настройкой начальных обработчиков прерываний. На данный момент мы находимся в распакованном ядре Linux, у нас есть базовая структура [страничной организации памяти](https://en.wikipedia.org/wiki/Page_table) для начальной загрузки, и наша текущая цель - завершить начальную подготовку до того, как основной код ядра начнёт свою работу. Мы уже начали эту подготовку в предыдущей [первой](linux-initialization-1.md) части этой [главы](README.md). Мы продолжим в этой части и узнаем больше об обработке прерываний и исключений. @@ -475,7 +475,7 @@ pud_p += pud_index(address); pud = *pud_p; ``` -На следующем шаге мы делаем те же действия что и ранее, но со средним каталогом страниц. В конце мы исправляем адрес среднего каталога страниц, который содержит отображения текста ядра+виртуальные адреса данных: +На следующем шаге мы делаем те же действия что и ранее, но с промежуточным каталогом страниц. В конце мы исправляем адрес промежуточного каталога страниц, который содержит отображения текста ядра+виртуальные адреса данных: ```C pmd = (physaddr & PMD_MASK) + early_pmd_flags;