B.1. Загрузка системы.
Во время загрузки ПК процессор 80x86 запускается в режиме реального времени и запускает код ROM-BIOS по адресу 0xFFFF0. PS BIOS проводит тестирование системы и инициализирует вектор прерывания на 0-й физический адрес. После этого она загружает сектор загрузочного устройства по адресу 0x7C00 и обращается по этому адресу. Это устройство обычно представляет собой жесткий диск или накопитель в дисководе. Данная выкладка сильно упрощена, однако она дает представление о инициализации ядра.
Основная (первая) часть ядра Linux была написана на ассемблере 8086 (boot/bootsect.s). Во время запуска она помещает себя по абсолютному адресу 0x90000, считывая следующие 2Кб кода с загрузочного устройства по адресу 0x90200 и часть ядра по адресу 0x10000. Во время загрузки системы появляется сообщение "Loading...". Далее контроль передается коду в boot/Setup.S (другой исходник режима реального времени на ассемблере).
Установленная часть определяет остальные компоненты системы и тип карты vga. Если нужно, она может дать право выбора видеорежима. Затем она переносит всю систему с адреса 0x10000 по адресу 0x1000, включает защищенный режим и обращается к остальной части системы (по адресу 0x1000).
Следующим шагом является распаковка ядра. Код по адресу 0x1000 берется из zBoot/head.S, которая устанавливает регистры и вызывает decompress_kernel(), которая создает zBoot/inflate.c, zBoot/unzip.c и zBoot/misc.c. Распакованная информация помещается по адресу 0x1000000 (1Мб), поэтому Linux не может быть запущена на компьютере с ОЗУ, меньшим 1Мб.
Сокрытие ядра в файле gzip делается Makefile и утилитами в каталоге zBoot. Среди них есть занимательные программы. Ядро версии 1.1.75 помещает каталоги boot и zBoot в arch/i386/boot. Это изменение позволяет ядру подстраиваться под разные архитектуры.
Распакованный код запускается по адресу 0x1010000, где делаются все 32- битные установки: загружаются IDT, GDF и LTD, производятся установки процессору и сопроцессору, устанавливаются страницы и вызывается подпрограмма start_kernel. Исходные тексты предыдущих операций находятся в boot/head.S. Это наиболее изощренный код во всем ядре.
Помните, что в случае возникновения ошибки во время выполнения предыдущих шагов компьютер остановит работу. ОС не может справляться с ошибками, если она не полностью установлена.
start_kernel помещается в init/main и никогда не прекращает работу.
Единственное, что до этого момента написано на Си - это управление прерываниями и системный вызов enter/leave (однако и здесь большинство макросов нвписано на ассемблере). В.2
После обработки самых тонких вопросов, start_kernel инициализирует все по отдельности части ядра.
После этого ядро готово к move_to_user_mode() (перемещение в пользовательский режим. Затем 0-й процесс, так называемая идеальная задача, продолжает функционировать в бесконечном цикле.
Процесс init петаетса запустить /exec/init, или /bin/init, или /sbin/init. Если ни один из перечисленных методов не запускается, система запускает "/bin/sh /etc/rc" и ведает основную оболочку на первый терминал. Эта процедура была написана в Linux 0.01, когда ОС состояла из одного ядра и не поддерживала операцию login.
После запуска функцией exec() программы init с одной из стандартных позиций (предположим что мы находимся в одной из них), ядро не контролирует процесс работы программы. Его ролью в этот момент становится поддерживать процессы с помощью системных вызовов и обслуживать асинхронные события, такие как прерывания аппаратного обеспечения. Многозадачность также устанавливается до этого, поэтому управлением доступа задач с помощью fork() и login занимается программа init. Данный обзор рассмотрит обслуживание ядром асинхронные события, также подробно как размещение информации и организацию кода.