OSFree L4KaKickstart
Содержание
L4Ka::Kickstart
В нашем процессе загрузки мы используем L4Ka::Kickstart. L4Ka::Kickstart — это универсальный и расширяемый загрузчик для L4Ka::Pistachio, в настоящее время поддерживающий системы IA32 и AMD64. L4Ka::Kickstart загружает и конфигурирует ядро с архитектурными параметрами конфигурации, такими как доступные и зарезервированные области памяти. Далее он загружает и регистрирует местоположение памяти начальных серверов и запускает ядро.
Примечание: Оригинальный kickstart из 0.4 L4Ka:Pistachio имеет повреждённый заголовок Multiboot. В результате он работает некорректно. Мы используем пропатченную версию L4Ka:Kickstart.
Примечание: В этом документе используются части спецификации Multiboot 0.6.95 и материалы группы L4Ka.
Интерфейс KernelLoader/L4Ka:Kickstart
После загрузки L4Ka:Kickstart и передачи ему управления машина должна находиться в следующем состоянии:
Состояние машины
| Регистр | Содержит | Описание | |
|---|---|---|---|
| EAX | Магическое значение | Должен содержать магическое значение 0x2BADB002; наличие этого значения указывает операционной системе, что она была загружена загрузчиком ядра, совместимым с Multiboot (например, в отличие от другого типа загрузчика ядра, из которого операционная система также может быть загружена). | |
| EBX | Указатель на структуру информации Multiboot | Должен содержать 32-битный физический адрес структуры информации Multiboot, предоставленной загрузчиком ядра (см. Формат загрузочной информации). | |
| CS | Должен быть 32-битным сегментом кода для чтения/выполнения со смещением 0 и лимитом 0xFFFFFFFF. Точное значение не определено. | ||
| DS/ES/FS/GS/SS | Должны быть 32-битными сегментами данных для чтения/записи со смещением 0 и лимитом 0xFFFFFFFF. Точные значения все не определены. | ||
| Шлюз A20 | Должен быть включён. | ||
| CR0 | Бит 31 (PG) должен быть сброшен. Бит 0 (PE) должен быть установлен. Остальные биты все не определены. | ||
| EFLAGS | Бит 17 (VM) должен быть сброшен. Бит 9 (IF) должен быть сброшен. Остальные биты все не определены. | ||
Все остальные регистры процессора и биты флагов не определены. Это включает, в частности:
- ESP — образ ядра должен создать свой собственный стек, как только он ему понадобится.
- GDTR — хотя сегментные регистры настроены, как описано выше, GDTR может быть недействительным, поэтому образ ядра не должен загружать какие-либо сегментные регистры (даже просто перезагружая те же значения!), пока он не настроит свою собственную GDT.
- IDTR — образ ядра должен оставить прерывания отключёнными, пока он не настроит свою собственную IDT.
Однако помимо этого состояние машины должно быть оставлено загрузчиком ядра в нормальном рабочем порядке, т.е. как инициализировано BIOS (или DOS, если загрузчик ядра работает оттуда). Другими словами, операционная система должна иметь возможность выполнять вызовы BIOS и тому подобное после загрузки, если только она не перезапишет структуры данных BIOS до этого. Также загрузчик ядра должен оставить PIC запрограммированным со стандартными значениями BIOS/DOS, даже если он изменял их во время переключения в 32-битный режим.
Формат загрузочной информации
При входе в операционную систему регистр EBX содержит физический адрес структуры данных информации Multiboot, через которую загрузчик ядра передаёт операционной системе жизненно важную информацию. Операционная система может использовать или игнорировать любые части структуры по своему выбору; вся информация, передаваемая загрузчиком ядра, носит лишь рекомендательный характер.
Структура информации Multiboot и связанные с ней подструктуры могут быть размещены загрузчиком ядра в любом месте памяти (за исключением, конечно, памяти, зарезервированной для ядра и загрузочных модулей). Ответственность за то, чтобы не перезаписать эту память до окончания её использования, лежит на операционной системе.
Формат структуры информации Multiboot (как определено на данный момент) следующий:
| Смещение | Содержит | Комментарии |
|---|---|---|
| 0 | flags | обязательно |
| 4 | mem_lower | присутствует, если flags[0] установлен |
| 8 | mem_upper | присутствует, если flags[0] установлен |
| 12 | boot_device | присутствует, если flags[1] установлен |
| 16 | cmdline | flags[2] |
| 20 | mods_count | присутствует, если flags[3] установлен |
| 24 | mods_addr | присутствует, если flags[3] установлен |
| 28 - 40 | syms | присутствует, если flags[4] или flags[5] установлен |
| 44 | mmap_length | присутствует, если flags[6] установлен |
| 48 | mmap_addr | присутствует, если flags[6] установлен |
| 52 | drives_length | присутствует, если flags[7] установлен |
| 56 | drives_addr | присутствует, если flags[7] установлен |
| 60 | config_table | присутствует, если flags[8] установлен |
| 64 | boot_loader_name | присутствует, если flags[9] установлен |
| 68 | apm_table | присутствует, если flags[10] установлен |
| 72 | vbe_control_info | должен быть заполнен |
| 76 | vbe_mode_info | |
| 80 | vbe_mode | |
| 82 | vbe_interface_seg | |
| 84 | vbe_interface_off | |
| 86 | vbe_interface_len | |
Если бит 0 в слове flags установлен, то поля mem_* действительны. mem_lower и mem_upper указывают количество нижней и верхней памяти соответственно в килобайтах. Нижняя память начинается с адреса 0, а верхняя память начинается с адреса 1 мегабайт. Максимально возможное значение для нижней памяти — 640 килобайт. Значение, возвращаемое для верхней памяти, максимально равно адресу первой дыры в верхней памяти минус 1 мегабайт. Нет гарантии, что это именно это значение.
Если бит 1 в слове flags установлен, то поле boot_device действительно и указывает, с какого BIOS-устройства загрузчик ядра загрузил образ ядра. Если образ ядра не был загружен с BIOS-диска, то это поле не должно присутствовать (бит 3 должен быть сброшен). Операционная система может использовать это поле как подсказку для определения собственного корневого устройства, но не обязана. Поле boot_device разложено на четыре однобайтовых подполя следующим образом:
| drive | part1 | part2 | part3 |
|---|
Первый байт содержит номер BIOS-диска, как его понимает низкоуровневый дисковый интерфейс BIOS INT 0x13: например, 0x00 для первого гибкого диска или 0x80 для первого жёсткого диска.
Три оставшихся байта указывают загрузочный раздел. part1 указывает номер раздела верхнего уровня, part2 указывает подраздел в разделе верхнего уровня и т.д. Номера разделов всегда начинаются с нуля. Неиспользуемые байты разделов должны быть установлены в 0xFF. Например, если диск разбит на разделы с использованием простой одноуровневой схемы разбиения DOS, то part1 содержит номер раздела DOS, а part2 и part3 оба равны 0xFF. В качестве другого примера, если диск сначала разбит на разделы DOS, а затем один из этих разделов DOS подразделён на несколько разделов BSD с использованием стратегии disklabel BSD, то part1 содержит номер раздела DOS, part2 содержит подраздел BSD внутри этого раздела DOS, а part3 равен 0xFF.
Расширенные разделы DOS указываются как номера разделов, начинающиеся с 4 и увеличивающиеся, а не как вложенные подразделы, даже несмотря на то, что базовая структура диска расширенных разделов иерархична по своей природе. Например, если загрузчик ядра загружается со второго расширенного раздела на диске, разбитом в обычном стиле DOS, то part1 будет равен 5, а part2 и part3 оба будут равны 0xFF.
Если бит 2 в longword flags установлен, поле cmdline действительно и содержит физический адрес командной строки, которая должна быть передана ядру. Командная строка — это обычная C-строка с нулевым завершением.
Если бит 3 в flags установлен, то поля mods указывают ядру, какие загрузочные модули были загружены вместе с образом ядра и где их можно найти. mods_count содержит количество загруженных модулей; mods_addr содержит физический адрес первой структуры модуля. mods_count может быть равен нулю, что указывает на то, что загрузочные модули не были загружены, даже если бит 1 в flags установлен. Каждая структура модуля форматируется следующим образом:
| Смещение | Поле |
|---|---|
| 0 | mod_start |
| 4 | mod_end |
| 8 | string |
| 12 | reserved(0) |
Первые два поля содержат начальный и конечный адреса самого загрузочного модуля. Поле string предоставляет произвольную строку, которую нужно связать с этим конкретным загрузочным модулем; это ASCII-строка с нулевым завершением, точно такая же, как командная строка ядра. Поле string может быть 0, если с модулем не связана никакая строка. Обычно строка может быть командной строкой (например, если операционная система рассматривает загрузочные модули как исполняемые программы) или именем пути (например, если операционная система рассматривает загрузочные модули как файлы в файловой системе), но её точное использование специфично для операционной системы. Поле reserved должно быть установлено в 0 загрузчиком ядра и игнорироваться операционной системой.
Внимание: Биты 4 и 5 взаимоисключающие.
Если бит 4 в слове flags установлен, то следующие поля в структуре информации Multiboot, начиная с байта 28, действительны:
| Смещение | Поле |
|---|---|
| 28 | tabsize |
| 32 | strsize |
| 36 | addr |
| 40 | reserved (0) |
Они указывают, где можно найти таблицу символов из образа ядра формата a.out. addr — это физический адрес размера (4-байтовый unsigned long) массива структур nlist формата a.out, за которым немедленно следует сам массив, затем размер (4-байтовый unsigned long) набора ASCII-строк с нулевым завершением (плюс sizeof(unsigned long) в этом случае) и, наконец, сам набор строк. tabsize равен своему параметру размера (найденному в начале секции символов), а strsize равен своему параметру размера (найденному в начале секции строк) следующей таблицы строк, на которую ссылается таблица символов. Обратите внимание, что tabsize может быть равен 0, что указывает на отсутствие символов, даже если бит 4 в слове flags установлен.
Если бит 5 в слове flags установлен, то следующие поля в структуре информации Multiboot, начиная с байта 28, действительны:
| Смещение | Поле |
|---|---|
| 28 | num |
| 32 | size |
| 36 | addr |
| 40 | shndx |
Они указывают, где находится таблица заголовков секций ELF-ядра, размер каждой записи, количество записей и таблица строк, используемая в качестве индекса имён. Они соответствуют записям shdr_* (shdr_num и т.д.) в спецификации Executable and Linkable Format (ELF) в заголовке программы. Все секции загружены, и поля физических адресов заголовка секции ELF затем ссылаются на то, где секции находятся в памяти (обратитесь к документации i386 ELF для подробностей о том, как читать заголовок(и) секций). Обратите внимание, что shdr_num может быть равен 0, что указывает на отсутствие символов, даже если бит 5 в слове flags установлен.
Если бит 6 в слове flags установлен, то поля mmap_* действительны и указывают адрес и длину буфера, содержащего карту памяти машины, предоставленную BIOS. mmap_addr — это адрес, а mmap_length — общий размер буфера. Буфер состоит из одной или нескольких следующих пар размер/структура (размер действительно используется для перехода к следующей паре):
- 4 — size
| Смещение | Поле |
|---|---|
| 0 | base_addr_low |
| 4 | base_addr_high |
| 8 | length_low |
| 12 | length_high |
| 16 | type |
где size — это размер связанной структуры в байтах, который может быть больше минимального значения в 20 байт. base_addr_low — это младшие 32 бита начального адреса, а base_addr_high — старшие 32 бита, всего 64-битный начальный адрес. length_low — это младшие 32 бита размера области памяти в байтах, а length_high — старшие 32 бита, всего 64-битная длина. type — это разновидность представленного диапазона адресов, где значение 1 указывает доступную RAM, а все остальные значения в настоящее время указывают зарезервированную область.
Предоставленная карта гарантированно перечисляет всю стандартную RAM, которая должна быть доступна для нормального использования.
Если бит 7 в flags установлен, то поля drives_* действительны и указывают адрес физического адреса первой структуры диска и размер структур диска. drives_addr — это адрес, а drives_length — общий размер структур диска. Обратите внимание, что drives_length может быть равен нулю. Каждая структура диска форматируется следующим образом:
| Смещение | Поле |
|---|---|
| 0 | size |
| 4 | drive_number |
| 5 | drive_mode |
| 6 | drive_cylinders |
| 8 | drive_heads |
| 9 | drive_sectors |
| 10-xx | drive_ports |
Поле size указывает размер этой структуры. Размер варьируется в зависимости от количества портов. Обратите внимание, что размер может не быть равен (10 + 2 * количество портов) из-за выравнивания.
Поле drive_number содержит номер BIOS-диска. Поле drive_mode представляет режим доступа, используемый загрузчиком ядра. В настоящее время определены следующие режимы:
| Значение | Режим |
|---|---|
| 0 | Режим CHS (традиционный режим адресации цилиндр/головка/сектор) |
| 1 | Режим LBA (режим логической блочной адресации) |
Три поля, drive_cylinders, drive_heads и drive_sectors, указывают геометрию диска, обнаруженную BIOS. drive_cylinders содержит количество цилиндров. drive_heads содержит количество головок. drive_sectors содержит количество секторов на дорожку.
Поле drive_ports содержит массив портов ввода-вывода, используемых для диска в коде BIOS. Массив состоит из нуля или более беззнаковых двухбайтовых целых чисел и завершается нулём. Обратите внимание, что массив может содержать любое количество портов ввода-вывода, фактически не связанных с диском (например, порты контроллера DMA).
Если бит 8 в flags установлен, то поле config_table действительно и указывает адрес таблицы конфигурации ROM, возвращаемой вызовом BIOS GET CONFIGURATION. Если вызов BIOS завершается неудачно, то размер таблицы должен быть равен нулю.
Если бит 9 в flags установлен, поле boot_loader_name действительно и содержит физический адрес имени загрузчика ядра, загружающего ядро. Имя — это обычная C-строка с нулевым завершением.
Если бит 10 в flags установлен, поле apm_table действительно и содержит физический адрес таблицы APM, определённой ниже:
| Смещение | Поле |
|---|---|
| 0 | version |
| 2 | cseg |
| 4 | offset |
| 8 | cseg_16 |
| 10 | dseg |
| 12 | flags |
| 14 | cseg_len |
| 16 | cseg_16_len |
| 18 | dseg_len |
Поля version, cseg, offset, cseg_16, dseg, flags, cseg_len, cseg_16_len, dseg_len указывают соответственно номер версии, 32-битный сегмент кода защищённого режима, смещение точки входа, 16-битный сегмент кода защищённого режима, 16-битный сегмент данных защищённого режима, флаги, длину 32-битного сегмента кода защищённого режима, длину 16-битного сегмента кода защищённого режима и длину 16-битного сегмента данных защищённого режима. Только поле offset занимает 4 байта, остальные — 2 байта. См. Advanced Power Management (APM) BIOS Interface Specification для получения дополнительной информации.
Бит 11 в flags должен быть равен нулю.
Опции командной строки L4Ka:Kickstart
L4Ka::Kickstart принимает ряд аргументов командной строки, которые можно использовать для настройки системы. Аргументы командной строки указываются в строке kickstart в конфигурационном файле загрузчика. Командная строка передаётся L4Ka::Kickstart, если flags[2] структуры информации Multiboot установлен. Командная строка доступна через указатель Cmdline структуры информации Multiboot. Поддерживаются следующие аргументы командной строки:
- maxmem=num[K|M|G]
Ограничивает объём доступной физической памяти в системе.
- kmem=num[K|M|G] (по умолчанию 16M)
Резервирует определённый объём физической памяти для использования ядром. Дополнительная память записывается в страницу интерфейса ядра как дескриптор памяти с типом зарезервированной памяти и подхватывается ядром во время инициализации.
- bootinfo=<on|off> (по умолчанию on)
Включает/отключает создание универсальной структуры bootinfo. Если включено, местоположение bootinfo будет записано в поле bootinfo страницы интерфейса ядра.
- mbi=<on|off> (по умолчанию on)
Включает/отключает передачу информации multiboot корневым задачам. Если и bootinfo, и mbi включены, местоположение mbi будет записано в специальной записи bootinfo. Если bootinfo не указан, местоположение mbi записывается в поле bootinfo страницы интерфейса ядра.
- decode-all=<on|off> (по умолчанию off)
Включает/отключает декодирование всех ELF-бинарников, найденных в списке модулей. Переключатель полезен для тестирования нескольких приложений без наличия специального декодера ELF в корневой задаче. Местоположение и точки входа для бинарников записываются в записи SimpleExec bootinfo. Kickstart не будет жаловаться, если декодированные бинарники перекрываются.
Дескрипторы памяти
L4Ka::Kickstart, в дополнение к обычным дескрипторам памяти, определённым в спецификации L4, вставит ряд специфичных для загрузчика дескрипторов памяти в страницу интерфейса ядра. Эти дескрипторы памяти будут иметь тип 0xE (т.е. специфичный для загрузчика тип) и один из следующих подтипов:
- 0x0
Неопределённая/разное память загрузчика. Используется для типов памяти, которые не подходят ни под одну из других категорий.
- 0x1
Начальные структуры данных, необходимые для начальной загрузки системы (например, структура информации multiboot или универсальная структура bootinfo). Эти структуры данных можно безопасно освободить после инициализации системы.
- 0x2
Начальный сервер L4 (т.е. sigma0, sigma1 или корневой сервер).
- 0x3
Загрузочные модули. Модули (простые файлы или исполняемые файлы), загружаемые загрузчиком.
| OSFree | |
|---|---|
| osFree | Архитектура • План работ • Компоненты • Используемые проекты • Экраны • FreePM • L4 • Скриншоты |
| Загрузчик | [ Последовательность загрузки: поток выполнения • изменение карты памяти ] • Загрузочный сектор • L4Ka::Kickstart |
| Personalities | Win16 personality • MVM/DOS/Win16 personality |
| Разработка | Получение исходных кодов • Сборка • Отладка • Отправка отчетов |
| API | TPCrt • FamilyAPI • Win16API • VIO API • MVM API |
| Сообщество | IRC |
| OS/2 | Presentation Manager • IFS • Петиции к IBM |