Загрузка системы

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

В кросс-системах эта проблема решается просто. Как правило, значительная часть памяти разделяется между host-системой и целевой системой. Память целевой системы может быть видна host-машине как часть ее собственного физического адресного пространства (так называемая backpane memoryпамять окна на двор), либо как специальное внешнее устройство.

Например, в для практических занятий по изучению процессора память целевого компьютера на процессоре К580 (Советский клон процессора Intel 8080) загружалась из host-машины Электроника-60 (Советский клон PDP-11) через параллельный порт последней. Часто такая же техника используется при отладке программ для микроконтроллеров. Для этой цели на целевой плате должно стоять специальное устройство, имитатор ПЗУ, который имеет разъемы, совпадающие с кристаллом ПЗУ, который предполагается там поставить. Содержимое имитируемого ПЗУ может загружаться в такой имитатор через последовательный или параллельный порт, или какими-то другими методами.

Еще одна похожая техника заключается в наличие высокоскоростных последовательных каналов, называемых линками, которые глубоко интегрированы в архитектуру процессора. Кроме того, процессор такого компьютера имеет специальный разъем, по которому передается сигнал boot from link. Такой вид загрузки имеет транспьютер фирмы Inmos. Если этот сигнал установлен, при включении питания или после получения сигнала сброса (reset) транспьютер начинает ждать, пока с какого-то из линков не придет байт, больший чем 1. Такой байт воспринимается как длина сообщения, которое сейчас должно прийти по этому же линку. Сообщение загружается в память с выделенного адреса и запускается как программа. В Inmos'овской документации такая программа называется первичным загрузчиком. Как правило, эта программа загружает следующую, более сложную, называемую вторичным загрузчиком, которая и занимается инициализацией всей системы. В случае сложной конфигурации она может затянуть в память еще один, третичный загрузчик, который и произведет инициализацию. При отсутствии сигнала boot from link транспьютер грузится с определенного адреса, в котором находится ПЗУ.

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

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

На многих системах в ПЗУ бывает прошито нечто большее, чем первичный загрузчик. Это может быть целая контрольно-диагностическая система, называемая консольным монитором. Такая система есть на всех машинах линии PDP-11/VAX и на VME-системах, рассчитанных на OS-9 или VxWorks. Такой монитор позволяет вам просматривать содержимое памяти по заданному адресу, записывать туда данные, запускать какую-то область памяти как программу, и многое другое. Он же позволяет выбирать устройство, с которого будет производиться дальнейшая загрузка. В PDP-11/VAX на таком мониторе можно даже писать программы, почти с таким же успехом, как на ассемблере. Нужно только уметь считать в уме в восьмеричной системе счисления.

На машинах фирмы Sun в качестве консольного монитора используется интерпретатор языка Forth. На ранних моделях IBM PC в ПЗУ был прошит интерпретатор BASIC. Именно поэтому клоны IBM PC имеют огромное количество плохо используемого адресного пространства выше сегмента 0xC000. Вы можете убедиться в том, что BASIC там должен быть, вызвав из программы прерывание 0x60. Вы получите на мониторе сообщение вроде: NO ROM BASIC. PRESS ANY KEY TO REBOOT. Вообще говоря, этот BASIC не является консольным монитором в строгом смысле этого слова, так как получает управление не перед загрузкой, а лишь после того, как загрузка со всех устройств завершилась неудачей.

На многих больших компьютерах существует отдельная консольная подсистема. Это маломощная машина, используемая для инициализации центрального процессора и его загрузки. Так, у VAX-11/780 внутри стоит консольная PDP-11/03 (с которой и скопирована Электроника-60; у нее даже корпус точно такой же), которая загружает микропрограмму в процессор VAX и инициализует консольный терминал.

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

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

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

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

В старых веpсиях MS DOS (3.30 и pанее) эта проблема была решена еще проще: файлы IO.SYS и MSDOS.SYS обязаны занимать на диске непрерывное пространство. Загрузочный сектор находит корневую директорию, находит в ней ссылки на соответствующие файлы и их длину и считывает требуемое количество секторов, начиная со стартового. Это существенно проще, чем разбираться с типом FAT, размером кластера и всей относящейся к делу информацией. В ранних версиях DOS эти файлы вообще должны были лежать в начале диска.

Легко понять, что первичный и вторичный загрузчики должны быть абсолютными загружаемыми модулями. Так как, возлагать на первичный загрузчик настройку и перемещение вторичного просто нечестно, а для первичного этого просто никто не может сделать. Как правило, третичный и последующие загрузчики также являются абсолютными модулями, потому что у вторичного загрузчика хватает своих проблем, кроме настройки адресов у загрузчика следующего уровня.

В возможен еще один интересный способ загрузки - загрузка из сети. Он происходит аналогично загрузке с диска - стартовое ПЗУ сетевого адаптера посылает в сеть пакет стандартного содержания, который содержит запрос к серверу удаленной загрузки. Этот сервер передает по сети вторичный загрузчик, и т.д. Такая механика может использоваться при загрузке бездисковых рабочих станций. Таким же образом грузились системы VAX/VMS, так грузятся многие современные системы.

Когда ядро системы, наконец-то, окажется в памяти, оно обычно запускает некоторую специальную программу инициализации. В случае MS DOS такая программа содержится в модулях MSDOS.SYS/IO.SYS. Имеется в виду процедура интерпретации файла CONFIG.SYS. Эта процедура определяет параметры настройки системы, драйверы устройств, которые нужно загрузить, и т.д. В системе UNIX старых версий: System V или стаpых системах ветви BSD UNIX стаpее, все эти драйверы и параметры настройки намертво зашиты в ядро. Для изменения конфигурации системы вы должны собирать ядро заново. В случае BSD, которая поставляется в виде исходных текстов на C и ассемблере, вам, возможно, придется также перекомпилировать часть модулей.

Тем не менее, в UNIX имеется специальная инициализационная программа, которая так и называется - init. Эта программа запускает различные процессы-демоны, например cron - программу, которая умеет запускать другие заданные ей программы в заданные моменты времени, различные сетевые сервисы, программы, которые ждут ввода с терминальных устройств (getty), и т.д. То, что она запускает, вообще говоря, задается в специальном файле /etc/inittab. Администратор системы может редактировать этот файл и устанавливать те сервисы, которые в данный момент нужны, избавляться от тех, которые не нужны, и т.д. Отчасти это похоже на группу startup в MS Windows. Вообще, аналогичный инициализационный сервис предоставляют все современные операционные системы.

Существуют операционные системы, которые не умеют самостоятельно выполнять весь цикл бутстрапа. Они используют более примитивную операционную систему, которая исполняет их вторичный загрузчик, и помогает этому загрузчику затянуть в память ядро ОС. На процессорах i80x86 в качестве стартовой системы часто используется MS/DR DOS, а загрузчик новой ОС оформляется в виде .EXE-файла. Так устроены MS Windows, и ряд многозадачных мониторов для MS DOS. Таким же образом загружается сервер Nowell Netware, система Oberon для i386 и т.д.

Многие из перечисленных ОС, например MS Windows 3.x и Windows95, используют DOS и во время работы в качестве дисковой подсистемы. Тем не менее, эти системы умеют самостоятельно загружать пользовательские программы и выполнять все перечисленные во введении функции и должны, в соответствии с нашим определением, считаться полноценными операционными системами.

Итак, загрузчик – программа операционной системы, которая подготавливает заданную программы к загрузке, выполняет загрузку в оперативную память и инициирует выполнение программы.

Более детально функции Загрузчика следующие:

- выделение места для программ в памяти (распределение);

- фактическое размещение команд и данных в памяти (загрузка);

- разрешение символических ссылок между объектами (связывание);

- настройка всех величин в модуле, зависящих от физических адресов в соответствии с выделенной памятью (перемещение);

- передача управления на входную точку программы (инициализация).