7.9 ЗАГРУЗКА СИСТЕМЫ И НАЧАЛЬНЫЙ ПРОЦЕСС
Для того, чтобы перевести систему из неактивное состояние в активное, администратор выполняет процедуру „начальной загрузки“. На разных машинах эта процедура имеет свои особенности, однако во всех случаях она реализует одну и ту же цель: загрузить копию операционной системы в основную память машины и запустить ее на исполнение. Обычно процедура начальной загрузки включает в себя несколько этапов. Переключением клавиш на пульте машины администратор может указать адрес специальной программы аппаратной загрузки, а может, нажав только одну клавишу, дать команду машине запустить процедуру загрузки, исполненную в виде микропрограммы. Эта программа может состоять из нескольких команд, подготавливающих запуск другой программы. В системе UNIX процедура начальной загрузки заканчивается считыванием с диска в память блока начальной загрузки (нулевого блока). Программа, содержащаяся в этом блоке, загружает из файловой системы ядро ОС (например, из файла с именем „/unix“ или с другим именем, указанным администратором). После загрузки ядра системы в память управление передается по стартовому адресу ядра и ядро запускается на выполнение (алгоритм start Рисунок 7.30).
Ядро инициализирует свои внутренние структуры данных. Среди прочих структур ядро создает связные списки свободных буферов и индексов, хеш-очереди для буферов и индексов, инициализирует структуры областей, точки входа в таблицы страниц и т. д. По окончании этой фазы ядро монтирует корневую файловую систему и формирует среду выполнения нулевого процесса, среди всего прочего создавая пространство процесса, инициализируя нулевую точку входа в таблице процесса и делая корневой каталог текущим для процесса.
Когда формирование среды выполнения процесса заканчивается, система исполняется уже в виде нулевого процесса. Нулевой процесс „ветвится“, запуская алгоритм fork прямо из ядра, поскольку сам процесс исполняется в режиме ядра. Порожденный нулевым новый процесс, процесс 1, запускается в том же режиме и создает свой пользовательский контекст, формируя область данных и присоединяя ее к своему адресному пространству. Он увеличивает размер области до надлежащей величины и переписывает программу загрузки из адресного пространства ядра в новую область: эта программа теперь будет определять контекст процесса 1. Затем процесс 1 сохраняет регистровый контекст задачи, „возвращается“ из режима ядра в режим задачи и исполняет только что переписанную программу. В отличие от нулевого процесса, который является процессом системного уровня, выполняющимся в режиме ядра, процесс 1 относится к пользовательскому уровню. Код, исполняемый процессом 1, включает в себя вызов системной функции exec, запускающей на выполнение программу из файла „/etc/init“. Обычно процесс 1 именуется процессом init, поскольку он отвечает за инициализацию новых процессов.
алгоритм start /* процедура начальной загрузки системы */
входная информация: отсутствует
выходная информация: отсутствует
{
проинициализировать все структуры данных ядра;
псевдо-монтирование корня;
сформировать среду выполнения процесса 0;
создать процесс 1;
{
/* процесс 1 */
выделить область;
подключить область к адресному пространству процесса init
;
увеличить размер области для копирования в нее исполняемого кода;
скопировать из пространства ядра в адресное пространство процесса код программы, исполняемой процессом;
изменить режим выполнения: вернуться из режима ядра в режим задачи;
/* процесс init далее выполняется самостоятельно — в результате выхода в режим задачи, init исполняет файл „/etc/init“ и становится „обычным“ пользовательским процессом, производящим обращения к системным функциям */
}
/* продолжение нулевого процесса */
породить процессы ядра;
/* нулевой процесс запускает программу подкачки, управляющую распределением адресного пространства процессов между основной памятью и устройствами выгрузки. Это бесконечный цикл; нулевой процесс обычно приостанавливает свою работу, если необходимости в нем больше нет. */
исполнить программу, реализующую алгоритм подкачки;
}
Рисунок 7.30. Алгоритм загрузки системы
Казалось бы, зачем ядру копировать программу, запускаемую с помощью функции exec, в адресное пространство процесса 1? Он мог бы обратиться к внутреннему варианту функции прямо из ядра, однако, по сравнению с уже описанным алгоритмом это было бы гораздо труднее реализовать, ибо в этом случае функции exec пришлось бы производить анализ имен файлов в пространстве ядра, а не в пространстве задачи. Подобная деталь, требующаяся только для процесса init, усложнила бы программу реализации функции exec и отрицательно отразилась бы на скорости выполнения функции в более общих случаях.
Читать дальше