Загрузка самой ОС

При загрузке самой ОС возникает специфическая проблема: в пустой м шине, скорее всего, нет программы, которая могла бы это сделать. В системах, в которых программа находится в ПЗУ (или другой энергонезависимой памяти) этой проблемы не существует: при включении питания программа в памяти уже есть и сразу начинает исполняться. При включении питания или аппаратном сбросе процессор исполняет команду, находящуюся по определенному адресу, например, OxFFFFFFFA. Если там находите ПЗУ, а в нем записана программа, она и начинает исполняться. При разработке программ для встраиваемых приложений часто используются внутрисхемные имитаторы ПЗУ, доступные целевой системе как ПЗУ, а системе разработчика — как ОЗУ или специальное внешнее устройство. Компьютеры общего назначения также не могут обойтись без ПЗУ. Программа, записанная в нем, называется загрузочным монитором. Стартовая точка этой программы должна находиться как раз по тому адресу, по которому процессор передает управление в момент включения питания. Эта программа производит первичную инициализацию процессора, тестирование памяти и обязательного периферийного оборудования, и, наконец, начинает загрузку системы. В компьютерах, совместимых с IBM PC, загрузочный монитор известен как BIOS.

На многих системах в ПЗУ бывает прошито нечто большее, чем первичный грузчик. Это может быть целая контрольно-диагностическая система, называемая консольным монитором. Такая система есть на всех машинах линии PDI 11/VAX и на VME-системах, рассчитанных на OS-9 или VxWorks. Такой монитор позволяет вам просматривать содержимое памяти по заданному адресу, записывать туда данные, запускать какую-то область памяти как программ и многое другое. Он же позволяет выбирать устройство, с которого производиться дальнейшая загрузка. В PDP-11/VAX на таком мониторе можно даже писать программы, почти с таким же успехом, как на ассемблере. Нужно только уметь считать в уме в восьмеричной системе счисления. На машинах фирмы Sun в качестве консольного монитора используется ин­терпретатор языка Forth. На ранних моделях IBM PC в ПЗУ был прошит интерпретатор BASIC. Именно поэтому клоны IBM PC имеют огромное ко­личество плохо используемого адресного пространства выше сегмента ОхСООО. Вы можете убедиться в том, что BASIC там должен быть, вызвав из программы прерывание 0x60. Вы получите на мониторе сообщение вроде: no rom basic, press any key то reboot. Вообще говоря, этот BASIC не является консольным монитором в строгом смысле этого слова, так как получает управление не перед загрузкой, а лишь после того, как загрузка со всех уст­ройств завершилась неудачей.

После запуска консольного монитора и инициализации системы вы можете приказать системе начать собственно загрузку ОС. На IBM PC такое прика­зание отдается автоматически, и часто загрузка производится вовсе не с того устройства, с которого хотелось бы. На этом и основан жизненный цикл загрузочных вирусов.

Чтобы загрузочный монитор смог, что бы то ни было загрузить, он должен уметь проинициализировать устройство, с которого предполагается загрузка, и считать с него загружаемый код. Поэтому загрузочный монитор обязан содержать модуль, способный управлять загрузочным устройством. Напри­мер, типичный BIOS PC-совместимого компьютера содержит модули управ­ления гибким диском и жестким диском с интерфейсом Seagate 506 (в со­временных компьютерах это обычно интерфейс EIDE, отличающийся от Seagate 506 конструктивом, но программно совместимый с ним сверху вниз). Кроме того, конструктивы многих систем допускают установку ПЗУ на пла­тах контроллеров дополнительных устройств. Это ПЗУ должно содержать программный модуль, способный проинициализировать устройство и про­извести загрузку с него.

Как правило, сервисы загрузочного монитора доступны загружаемой системе. Так, модуль управления дисками BIOS PC-совместимых компьютер предоставляет функции считывания, и записи отдельных секторов диска Доступ к функциям ПЗУ позволяет значительно сократить код первичного загрузчика ОС, и, нередко, сделать его независимым от устройства.

Проще всего происходит загрузка с различных последовательных устройств - лент, перфолент, магнитофонов, перфокарточных считывателей и т. д. Загрузочный монитор считывает в память все, что можно считать с заданного устройства и передает управление на начало той информации, которую прочитал.

В современных системах такая загрузка практически не используется. В них загрузка происходит с устройств с произвольным доступом, как правило, с дисков. При этом обычно в память считывается нулевой сектор нулевой дорожки диска. Содержимое этого сектора называют первичным загрузчиком. В IBM PC этот загрузчик называют загрузочным сектором, или boot-сектором.

Как правило, первичный загрузчик, пользуясь сервисами загрузочного монитора, ищет на диске начало файловой системы своей родной ОС, находит в этой файловой системе файл с определенным именем, считывает его в память и передает этому файлу управление. В простейшем случае такой файл является ядром операционной системы.

Размер первичного загрузчика ограничен чаще всего размером сектора диска, т. е. 512 байтами. Если файловая система имеет сложную структуру, иногда первичному загрузчику приходится считывать вторичный, размер которого может быть намного больше. Из-за большего размера этот загрузчик намного умнее и в состоянии разобраться в структурах файловой системы. В некоторых случаях используются и третичные загрузчики.

Это последовательное исполнение втягивающих друг друга загрузчиков возрастающей сложности называется: бутстрапом (bootstrap), что можно перевести как "втягивание [себя] за шнурки от ботинок".

Большую практическую роль играет еще один способ загрузки — загрузка по сети. Она происходит аналогично загрузке с диска: ПЗУ, установлена на сетевой карте, посылает в сеть пакет стандартного содержания, который содержит запрос к серверу удаленной загрузки. Этот сервер передает по сети вторичный загрузчик и т. д. Такая технология незаменима при загрузке дисковых рабочих станций. Централизованное размещение загрузочных образов рабочих станций на сервере упрощает управление ими, защищает настройки ОС от случайных и злонамеренных модификаций и существенно удешевляет эксплуатацию больших парков настольных компьютеров, поэтому по сети нередко загружаются и машины, имеющие жесткий диск.

Проще всего происходит загрузка систем, ядро которых вместе со всеми дополнительными модулями (драйверами устройств, файловых систем и др.) собрано в единый загрузочный модуль. При переконфигурации системы, добавлении или удалении драйверов и других модулей необходима пересборка ядра, которая может производиться либо стандартным системным редактором связей, либо специальными ути­литами генерации системы. Для такой пересборки в поставку системы долж­ны входить либо исходные тексты (как у Linux и BSD), либо объектные мо­дули ядра. Сборка ядра из объектных модулей на современных системах занимает не более нескольких минут. Полная перекомпиляция ядра из ис­ходных текстов, конечно, продолжается существенно дольше.

На случай, если системный администратор ошибется и соберет неработо­способное ядро, вторичный загрузчик таких систем часто предоставляет возможность выбрать файл, который следует загрузить. Ядро таких систем обычно не использует никаких конфигурационных файлов — все настройки также задаются при генерации.

Большинство современных ОС используют более сложную форму загрузки, при которой дополнительные модули подгружаются уже после старта самого ядра. В терминах предыдущих разделов это называется "сборка в момент загрузки". Список модулей, которые необходимо загрузить, а также пара­метры настройки ядра, собраны в специальном файле или нескольких фай­лах. У DOS и OS/2 этот файл называется CONFIG.SYS, у Win32-систем -реестром (registry).

Сложность при таком способе загрузки состоит в том, что ядро, еще полно­стью не проинициализовавшись, уже должно быть способно работать с фай­ловой системой, находить в ней файлы и считывать их в память.

Особенно сложен этот способ тогда, когда драйверы загрузочного диска и загрузочной файловой системы сами являются подгружаемыми модулями. Обычно при этом ядро пользуется функциями работы с файловой системой, предоставляемыми вторичным (или третичным, в общем, последним по по­рядку) загрузчиком, до тех пор, пока не проинициализирует собственные модули. Вторичный загрузчик обязан уметь читать загрузочные файлы, ина­че он не смог бы найти ядро. Если поставщики ОС не удосужились напи­сать соответствующий вторичный загрузчик, а предоставили только драйвер файловой системы, ОС сможет работать с такой файловой системой, но не сможет из нее загружаться.

Некоторые системы, например DOS, могут грузиться только с устройств, Поддерживаемых BIOS, и только из одного типа файловой системы — FAT, Драйвер которой скомпонован с ядром. Любопытное развитие этой идеи представляет Linux, модули которого могут присоединяться к ядру как ста­тически, так и динамически. Динамически могут подгружаться любые моду­ли, кроме драйверов загрузочного диска и загрузочной ФС.

Преимущества, которые дает динамически собираемое в момент загрузки ядро, не так уж велики по сравнению с системами, в которых ядро собира­ется статически. Впрочем, ряд современных систем (Solaris, Linux, Netware) идут в этом направлении дальше и позволяют подгружать модули уже после загрузки и даже выгружать их. Такая архитектура предъявляет определенные требования к интерфейсу модуля ядра (он должен уметь не только инициа­лизировать сам себя и, если это необходимо, управляемое им устройство, но и корректно освобождать все занятые им ресурсы при выгрузке), но дает значительные преимущества.

Во-первых, это допускает подгрузку модулей по запросу. При этом подсистемы, нужные только иногда, могут не загрузиться вообще. Даже те модули, которые нужны всегда, могут проинициализироваться, только когда станут, нужны, уменьшив тем самым время от начала загрузки до старта некоторых сервисов. Второе, пожалуй, даже более важное для системного администратора, преимущество состоит в возможности реконфигурировать систему без перезагрузки, что особенно полезно для систем коллективного пользования. И, наконец, возможность выгрузки модулей ядра иногда (но не всегда, a лишь если поломка не мешает драйверу корректно освободить ресурсы) позволяет корректировать работу отдельных подсистем - опять-таки без перезагрузки всей ОС и пользовательских приложений.

Оказавшись в памяти и, так или иначе, подтянув все необходимые дополнительные модули, ядро запускает их подпрограммы инициализации. При динамической подгрузке инициализация модулей часто происходит по мере их загрузки. Обычно инициализация ядра завершается тем, что оно загружает определенную программу, которая продолжает инициализацию - уже не ядра, но системы в целом.