[Booting] Обновление ссылок на изображения

pull/709/head
proninyaroslav 5 years ago
parent fc9b625ee7
commit 050bd8d709

@ -138,7 +138,7 @@ nasm -f bin boot.nasm && qemu-system-x86_64 boot
Вы увидите: Вы увидите:
![Простой загрузчик, который печатает только `!`](http://oi60.tinypic.com/2qbwup0.jpg) ![Простой загрузчик, который печатает только `!`](images/simple_bootloader.png)
В этом примере мы можем видеть, что код будет выполнен в 16-битном режиме реальных адресов и начнёт выполнение с адреса `0x7c00`. После запуска он вызывает прерывание [0x10](http://www.ctyme.com/intr/rb-0106.htm), которое просто печатает символ `!`. Оставшиеся 510 байт заполняются нулями, и код заканчивается двумя магическими байтами `0xaa` и `0x55`. В этом примере мы можем видеть, что код будет выполнен в 16-битном режиме реальных адресов и начнёт выполнение с адреса `0x7c00`. После запуска он вызывает прерывание [0x10](http://www.ctyme.com/intr/rb-0106.htm), которое просто печатает символ `!`. Оставшиеся 510 байт заполняются нулями, и код заканчивается двумя магическими байтами `0xaa` и `0x55`.
@ -247,7 +247,7 @@ X + sizeof(KernelBootSector) + 1
``` ```
где `X` - это адрес загруженного сектора загрузки ядра. В моем случае `X` это `0x10000`, как мы можем видеть в дампе памяти: где `X` - это адрес загруженного сектора загрузки ядра. В моем случае `X` это `0x10000`, как мы можем видеть в дампе памяти:
![Первый адрес ядра](http://oi57.tinypic.com/16bkco2.jpg) ![Первый адрес ядра](images/kernel_first_address.png)
Сейчас загрузчик поместил ядро Linux в память, заполнил поля заголовка, а затем переключился на него. Теперь мы можем перейти непосредственно к коду настройки ядра. Сейчас загрузчик поместил ядро Linux в память, заполнил поля заголовка, а затем переключился на него. Теперь мы можем перейти непосредственно к коду настройки ядра.
@ -263,7 +263,7 @@ qemu-system-x86_64 vmlinuz-3.18-generic
то увидите: то увидите:
![Попытка использовать vmlinuz в qemu](http://oi60.tinypic.com/r02xkz.jpg) ![Попытка использовать vmlinuz в qemu](images/try_vmlinuz_in_qemu.png)
На самом деле, `header.S` начинается с [MZ](https://en.wikipedia.org/wiki/DOS_MZ_executable) (см. картинку выше), вывода сообщения об ошибке и [PE](https://en.wikipedia.org/wiki/Portable_Executable) заголовка: На самом деле, `header.S` начинается с [MZ](https://en.wikipedia.org/wiki/DOS_MZ_executable) (см. картинку выше), вывода сообщения об ошибке и [PE](https://en.wikipedia.org/wiki/Portable_Executable) заголовка:
@ -403,7 +403,7 @@ _start:
Здесь мы видим выравнивание сегмента `dx` (содержащего значение `sp`, полученное загрузчиком) до 4 байт и проверку - является ли полученное значение нулём. Если ноль, то помещаем `0xfffx` (выровненный до `4` байт адрес до максимального значения сегмента в 64 Кб) в `dx`. Если не ноль, продолжаем использовать `sp`, полученный от загрузчика (в моём случае `0xf7f4`). После этого мы помещаем значение `ax` в `ss`, который хранит корректный адрес сегмента `0x1000` и устанавливает корректное значение `sp`. Теперь мы имеем корректный стек: Здесь мы видим выравнивание сегмента `dx` (содержащего значение `sp`, полученное загрузчиком) до 4 байт и проверку - является ли полученное значение нулём. Если ноль, то помещаем `0xfffx` (выровненный до `4` байт адрес до максимального значения сегмента в 64 Кб) в `dx`. Если не ноль, продолжаем использовать `sp`, полученный от загрузчика (в моём случае `0xf7f4`). После этого мы помещаем значение `ax` в `ss`, который хранит корректный адрес сегмента `0x1000` и устанавливает корректное значение `sp`. Теперь мы имеем корректный стек:
![стек](http://oi58.tinypic.com/16iwcis.jpg) ![стек](images/stack1.png)
* Второй сценарий (когда `ss` != `ds`). Во-первых, помещаем значение [_end](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld#L52) (адрес окончания кода настройки) в `dx` и проверяем поле заголовка `loadflags` инструкцией `testb`, чтобы понять, можем ли мы использовать кучу (heap). [loadflags](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L321) является заголовком с битовой маской, который определён как: * Второй сценарий (когда `ss` != `ds`). Во-первых, помещаем значение [_end](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld#L52) (адрес окончания кода настройки) в `dx` и проверяем поле заголовка `loadflags` инструкцией `testb`, чтобы понять, можем ли мы использовать кучу (heap). [loadflags](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/header.S#L321) является заголовком с битовой маской, который определён как:
@ -427,11 +427,11 @@ _start:
``` ```
Если бит `CAN_USE_HEAP` установлен, мы помещаем `heap_end_ptr` в `dx` (который указывает на `_end`) и добавляем к нему `STACK_SIZE` (минимальный размер стека, `512` байт). После этого, если `dx` без переноса (будет без переноса, поскольку `dx = _end + 512`), переходим на метку `2` (как в предыдущем случае) и создаём корректный стек. Если бит `CAN_USE_HEAP` установлен, мы помещаем `heap_end_ptr` в `dx` (который указывает на `_end`) и добавляем к нему `STACK_SIZE` (минимальный размер стека, `512` байт). После этого, если `dx` без переноса (будет без переноса, поскольку `dx = _end + 512`), переходим на метку `2` (как в предыдущем случае) и создаём корректный стек.
![стек](http://oi62.tinypic.com/dr7b5w.jpg) ![стек](images/stack2.png)
* Если флаг `CAN_USE_HEAP` не установлен, мы просто используем минимальный стек от `_end` до `_end + STACK_SIZE`: * Если флаг `CAN_USE_HEAP` не установлен, мы просто используем минимальный стек от `_end` до `_end + STACK_SIZE`:
![минимальный стек](http://oi60.tinypic.com/28w051y.jpg) ![минимальный стек](images/minimal_stack.png)
Настройка BSS Настройка BSS
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -458,7 +458,7 @@ _start:
``` ```
Во-первых, адрес [__bss_start](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld#L47) помещается в `di`. Далее, адрес `_end + 3` (+3 - выравнивает до 4 байт) помещается в `cx`. Регистр `eax` очищается (с помощью инструкции `xor`), а размер секции BSS (`cx`-`di`) вычисляется и помещается в `cx`. Затем `cx` делится на 4 (размер 'слова' (англ. word)), а инструкция `stosl` используется повторно, сохраняя значение `eax` (ноль) в адрес, на который указывает `di`, автоматически увеличивая `di` на 4 (это продолжается до тех пор, пока `cx` не достигнет нуля). Эффект от этого кода в том, что теперь все 'слова' в памяти от `__bss_start` до `_end` заполнены нулями: Во-первых, адрес [__bss_start](https://github.com/torvalds/linux/blob/v4.16/arch/x86/boot/setup.ld#L47) помещается в `di`. Далее, адрес `_end + 3` (+3 - выравнивает до 4 байт) помещается в `cx`. Регистр `eax` очищается (с помощью инструкции `xor`), а размер секции BSS (`cx`-`di`) вычисляется и помещается в `cx`. Затем `cx` делится на 4 (размер 'слова' (англ. word)), а инструкция `stosl` используется повторно, сохраняя значение `eax` (ноль) в адрес, на который указывает `di`, автоматически увеличивая `di` на 4 (это продолжается до тех пор, пока `cx` не достигнет нуля). Эффект от этого кода в том, что теперь все 'слова' в памяти от `__bss_start` до `_end` заполнены нулями:
![bss](http://oi59.tinypic.com/29m2eyr.jpg) ![bss](images/bss.png)
Переход к основному коду Переход к основному коду
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

@ -166,7 +166,7 @@ lgdt gdt
Схематично это будет выглядеть следующим образом: Схематично это будет выглядеть следующим образом:
![линейный адрес](http://oi62.tinypic.com/2yo369v.jpg) ![линейный адрес](images/linear_address.png)
Алгоритм перехода из режима реальных адресов в защищённый режим: Алгоритм перехода из режима реальных адресов в защищённый режим:

@ -40,7 +40,7 @@ vga=<mode>
Таким образом, мы можем добавить параметр `vga` в конфигурационный файл GRUB (или любого другого загрузчика) и он передаст его в командную строку ядра. Как говорится в описании, этот параметр может иметь разные значения. Например, это может быть целым числом `0xFFFD` или `ask`. Если передать `ask` в `vga`, вы увидите примерно такое меню: Таким образом, мы можем добавить параметр `vga` в конфигурационный файл GRUB (или любого другого загрузчика) и он передаст его в командную строку ядра. Как говорится в описании, этот параметр может иметь разные значения. Например, это может быть целым числом `0xFFFD` или `ask`. Если передать `ask` в `vga`, вы увидите примерно такое меню:
![video mode setup menu](http://oi59.tinypic.com/ejcz81.jpg) ![video mode setup menu](images/video_mode_setup_menu.png)
которое попросит выбрать видеорежим. Мы посмотрим на его реализацию, но перед этим рассмотрим некоторые другие вещи. которое попросит выбрать видеорежим. Мы посмотрим на его реализацию, но перед этим рассмотрим некоторые другие вещи.

Loading…
Cancel
Save