Update linux-bootstrap-1.md

pull/709/head
proninyaroslav 6 years ago
parent b2faefc759
commit 598c320635

@ -37,7 +37,7 @@ CS base 0xffff0000
```
Процессор начинает свою работу в [режиме реальных адресов](https://en.wikipedia.org/wiki/Real_mode). Давайте немного задержимся и попытаемся понять сегментацию памяти в этом режиме. Режим реальных адресов поддерживается всеми x86-совместимыми процессорами, от [8086](https://en.wikipedia.org/wiki/Intel_8086) до самых новых 64-битных CPU Intel. Процессор 8086 имел 20-битную шину адреса, т.е. он мог работать с адресным пространством в диапазоне 0-0xFFFFF (1 мегабайт). Но регистры у него были только 16-битные, а в таком случае максимальный размер адресуемой памяти составляет `2^16 - 1` или `0xffff` (64 килобайта).
[Сегментация памяти](http://en.wikipedia.org/wiki/Memory_segmentation) используется для того, чтобы задействовать всё доступное адресное пространство. Вся память делится на небольшие, фиксированного размера сегменты по `65536` байт (64 Кб) каждый. Поскольку мы не можем адресовать память свыше `64 Кб` с помощью 16-битных регистров, был придуман альтернативный метод.
[Сегментация памяти](https://en.wikipedia.org/wiki/Memory_segmentation) используется для того, чтобы задействовать всё доступное адресное пространство. Вся память делится на небольшие, фиксированного размера сегменты по `65536` байт (64 Кб) каждый. Поскольку мы не можем адресовать память свыше `64 Кб` с помощью 16-битных регистров, был придуман альтернативный метод.
Адрес состоит из двух частей: селектора сегмента, который содержит базовый адрес, и смещение от этого базового адреса. В режиме реальных адресов базовый адрес селектора сегмента это `Селектор Сегмента * 16`. Таким образом, чтобы получить физический адрес в памяти, нужно умножить селектор сегмента на `16` и прибавить к нему смещение:
@ -73,29 +73,31 @@ CS base 0xffff0000
'0xfffffff0'
```
Мы получили `0xfffffff0`, т.е. 16 байт ниже 4 Гб. По этому адресу располагается так называемый [вектор прерываний](http://en.wikipedia.org/wiki/Reset_vector). Это область памяти, в которой CPU ожидает найти первую инструкцию для выполнения после сброса. Она содержит инструкцию [jump](http://en.wikipedia.org/wiki/JMP_%28x86_instruction%29) (`jmp`), которая обычно указывает на точку входа в BIOS. Например, если мы взглянем на исходный код [coreboot](http://www.coreboot.org/) (`src/cpu/x86/16bit/reset16.inc`), то увидим следующее:
Мы получили `0xfffffff0`, т.е. 16 байт ниже 4 Гб. По этому адресу располагается так называемый [вектор прерываний](https://en.wikipedia.org/wiki/Reset_vector). Это область памяти, в которой CPU ожидает найти первую инструкцию для выполнения после сброса. Она содержит инструкцию [jump](https://en.wikipedia.org/wiki/JMP_%28x86_instruction%29) (`jmp`), которая обычно указывает на точку входа в BIOS. Например, если мы взглянем на исходный код [coreboot](https://www.coreboot.org/) (`src/cpu/x86/16bit/reset16.inc`), то увидим следующее:
```assembly
.section ".reset"
.section ".reset", "ax", %progbits
.code16
.globl reset_vector
reset_vector:
.globl _start
_start:
.byte 0xe9
.int _start - ( . + 2 )
.int _start16bit - ( . + 2 )
...
```
Здесь мы можем видеть [опкод инструкции jmp](http://ref.x86asm.net/coder32.html#xE9) - `0xe9`, и его адрес назначения `_start - ( . + 2)`.
Здесь мы можем видеть [опкод инструкции jmp](http//ref.x86asm.net/coder32.html#xE9) - `0xe9`, и его адрес назначения `_start16bit - ( . + 2)`.
Мы также можем видеть, что секция `reset` занимает `16` байт и начинается с `0xfffffff0` (`src/cpu/x86/16bit/reset16.lds`):
Мы также можем видеть, что секция `reset` занимает `16` байт и начинается с `0xfffffff0` (`src/cpu/x86/16bit/reset16.ld`):
```
SECTIONS {
/* Trigger an error if I have an unuseable start address */
_bogus = ASSERT(_start16bit >= 0xffff0000, "_start16bit too low. Please report.");
_ROMTOP = 0xfffffff0;
. = _ROMTOP;
.reset . : {
*(.reset)
. = 15 ;
*(.reset);
. = 15;
BYTE(0x00);
}
}
@ -132,7 +134,7 @@ db 0xaa
nasm -f bin boot.nasm && qemu-system-x86_64 boot
```
Команда оповещает эмулятор [QEMU](http://qemu.org) о необходимости использовать в качестве образа диска созданный только что бинарный файл. Пока последний проверяет, удовлетворяет ли загрузочный сектор всем необходимым требованиям (в origin записывается `0x7c00`, а в конце магическая последовательность), QEMU будет работать с бинарным файлом как с главной загрузочной записью (MBR) образа диска.
Команда оповещает эмулятор [QEMU](https://qemu.org) о необходимости использовать в качестве образа диска созданный только что бинарный файл. Пока последний проверяет, удовлетворяет ли загрузочный сектор всем необходимым требованиям (в origin записывается `0x7c00`, а в конце магическая последовательность), QEMU будет работать с бинарным файлом как с главной загрузочной записью (MBR) образа диска.
Вы увидите:
@ -179,7 +181,7 @@ objdump -D -b binary -mi386 -Maddr16,data16,intel boot
0x000F0000 - 0x000FFFFF - Системная BIOS
```
В начале статьи я написал, что первая инструкция, выполняемая CPU, расположена по адресу `0xFFFFFFF0`, значение которого намного больше, чем `0xFFFFF` (1 Мб). Каким образом CPU получает доступ к этому участку в режиме реальных адресов? Ответ на этот вопрос находится в документации [coreboot](http://www.coreboot.org/Developer_Manual/Memory_map):
В начале статьи я написал, что первая инструкция, выполняемая CPU, расположена по адресу `0xFFFFFFF0`, значение которого намного больше, чем `0xFFFFF` (1 Мб). Каким образом CPU получает доступ к этому участку в режиме реальных адресов? Ответ на этот вопрос находится в документации [coreboot](https://www.coreboot.org/Developer_Manual/Memory_map):
```
0xFFFE_0000 - 0xFFFF_FFFF: 128 Кб ROM отображаются на адресное пространство
@ -189,9 +191,9 @@ objdump -D -b binary -mi386 -Maddr16,data16,intel boot
Загрузчик
--------------------------------------------------------------------------------
Существует несколько загрузчиков Linux, такие как [GRUB 2](https://www.gnu.org/software/grub/) и [syslinux](http://www.syslinux.org/wiki/index.php/The_Syslinux_Project). Ядро Linux имеет [протокол загрузки](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/x86/boot.txt), который определяет требования к загрузчику для реализации поддержки Linux. В этом примере будет описан GRUB 2.
Существует несколько загрузчиков Linux, такие как [GRUB 2](https://www.gnu.org/software/grub/) и [syslinux](https://www.syslinux.org/wiki/index.php/The_Syslinux_Project). Ядро Linux имеет [протокол загрузки](https://github.com/torvalds/linux/blob/16f73eb02d7e1765ccab3d2018e0bd98eb93d973/Documentation/x86/boot.txt), который определяет требования к загрузчику для реализации поддержки Linux. В этом примере будет описан GRUB 2.
Теперь, когда BIOS выбрал загрузочное устройство и передал контроль управления коду в загрузочном секторе, начинается выполнение [boot.img](http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/boot.S;hb=HEAD). Этот код очень простой в связи с ограниченным количеством свободного пространства и содержит указатель, который используется для перехода к основному образу GRUB 2. Основной образ начинается с [diskboot.img](http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/diskboot.S;hb=HEAD), который обычно располагается сразу после первого сектора в неиспользуемой области перед первым разделом. Приведённый выше код загружает оставшуюся часть основного образа, который содержит ядро и драйверы GRUB 2 для управления файловой системой. После загрузки остальной части основного образа, код выполняет функция [grub_main](http://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/kern/main.c).
Теперь, когда BIOS выбрал загрузочное устройство и передал контроль управления коду в загрузочном секторе, начинается выполнение [boot.img](https://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/boot.S;hb=HEAD). Этот код очень простой в связи с ограниченным количеством свободного пространства и содержит указатель, который используется для перехода к основному образу GRUB 2. Основной образ начинается с [diskboot.img](https://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/boot/i386/pc/diskboot.S;hb=HEAD), который обычно располагается сразу после первого сектора в неиспользуемой области перед первым разделом. Приведённый выше код загружает оставшуюся часть основного образа, который содержит ядро и драйверы GRUB 2 для управления файловой системой. После загрузки остальной части основного образа, код выполняет функция [grub_main](https://git.savannah.gnu.org/gitweb/?p=grub.git;a=blob;f=grub-core/kern/main.c).
Функция `grub_main` инициализирует консоль, получает базовый адрес для модулей, устанавливает корневое устройство, загружает/обрабатывает файл настроек grub, загружает модули и т.д. В конце выполнения, `grub_main` переводит grub обратно в нормальный режим. Функция `grub_normal_execute` (из `grub-core/normal/main.c`) завершает последние приготовления и отображает меню выбора операционной системы. Когда мы выбираем один из пунктов меню, запускается функция `grub_menu_execute_entry`, которая в свою очередь запускает команду grub `boot`, загружающую выбранную операционную систему.
@ -482,14 +484,14 @@ _start:
Ссылки
--------------------------------------------------------------------------------
* [Справочник программиста Intel 80386 1986](http://css.csail.mit.edu/6.858/2014/readings/i386.pdf)
* [Справочник программиста Intel 80386 1986](https://css.csail.mit.edu/6.858/2014/readings/i386.pdf)
* [Минимальный загрузчик для архитектуры Intel®](https://www.cs.cmu.edu/~410/doc/minimal_boot.pdf)
* [8086](http://en.wikipedia.org/wiki/Intel_8086)
* [80386](http://en.wikipedia.org/wiki/Intel_80386)
* [Вектор прерываний](http://en.wikipedia.org/wiki/Reset_vector)
* [Режим реальных адресов](http://en.wikipedia.org/wiki/Real_mode)
* [8086](https://en.wikipedia.org/wiki/Intel_8086)
* [80386](https://en.wikipedia.org/wiki/Intel_80386)
* [Вектор прерываний](https://en.wikipedia.org/wiki/Reset_vector)
* [Режим реальных адресов](https://en.wikipedia.org/wiki/Real_mode)
* [Протокол загрузки ядра Linux](https://www.kernel.org/doc/Documentation/x86/boot.txt)
* [Справочник разработчика CoreBoot](http://www.coreboot.org/Developer_Manual)
* [Справочник разработчика CoreBoot](https://www.coreboot.org/Developer_Manual)
* [Список прерываний Ральфа Брауна](http://www.ctyme.com/intr/int.htm)
* [Источник питания](http://en.wikipedia.org/wiki/Power_supply)
* [Сигнал "Питание в норме"](http://en.wikipedia.org/wiki/Power_good_signal)
* [Источник питания](https://en.wikipedia.org/wiki/Power_supply)
* [Сигнал "Питание в норме"](https://en.wikipedia.org/wiki/Power_good_signal)

Loading…
Cancel
Save