Библиотека сайта rus-linux.net
Исследуем процесс загрузки Linux
(C) В.А.Костромин, 2007
(версия файла от 27.07.2007 г.)
Назад | Оглавление | Вперед |
Этап 1: BIOS
Когда вы включаете питание компьютера, в его оперативной памяти еще нет никакой программы, поэтому управление компьютером может осуществляться только аппаратным обеспечением. На Intel-овских платформах начальная загрузка операционной системы осуществляется посредством так называемой “базовой системы ввода/вывода” или BIOS. Достаточно подробное описание того, как это происходит, я нашел в статьях [4,5,6,7]. Я не буду приводить здесь это описание полностью (заинтересованные читатели могут обратиться к первоисточникам), перечислю только кратко основные этапы.
После включения компьютера блок питания проверяет все необходимые уровни напряжений. Если все уровни напряжений соответствуют номинальным, то на материнскую плату поступит сигнал PowerGood. До появления этого сигнала на вход процессора подается сигнал RESET, который удерживает процессор в сброшенном состоянии. Но после получения сигнала PowerGood от блока питания сигнал RESET будет снят и процессор начнет выполнять свои первые инструкции. При этом процессор стартует от вполне известного состояния: командный регистр CS содержит 0xFFFF, указатель команд (региcтр IP) содержит 0, сегментные регистры данных и стека содержат 0. Таким образом, после снятия RESET процессор в реальном режиме выполняет инструкции, размещающиеся в области ROM BIOS, начинающейся с адреса FFFF:0000 (физический адрес, соответственно, - 0xFFFF0). Размер этой области, очевидно, составляет 16 байт, вплоть до конца максимально адресуемого адресного пространства в реальном режиме - 0xFFFFF. По этому адресу располагается инструкция перехода на реально исполняемый код BIOS.
По соображениям снижения стоимости код BIOS в современных материнских платах хранится в постоянной памяти (ПЗУ) в сжатом виде. Только небольшая его часть, используемая на самых первых этапах загрузки, является непосредственно исполняемой. Поэтому первая задача, которая решается сразу после включения питания, заключается в том, чтобы инициализировать контроллер DRAM, декомпрессировать основной код BIOS и загрузить его в ту область оперативной памяти (RAM), которую именуют "теневой" (shadow RAM). Эта область затем защищается от записи и управление передается на записанный в нее исполняемый код BIOS. Теневая память в ходе дальнейшей работы отдана в полное владение чипсета материнской платы; операционная система к ней доступа не имеет. Но аппаратными средствами обеспечивается отображение теневой памяти на те области, которые в реальном режиме работы доступны для старых операционных систем типа MS-DOS, так что последние обнаруживают код BIOS именно там, где ожидают его найти.
Исполняемый код BIOS вначале реализует функцию начального самотестирования (POST - Power-On Self Test). При этом тестируются процессор, память и системные средства ввода/вывода, а также производится конфигурирование программно-управляемых аппаратных средств компьютера. Кроме того производится поиск и обнаружение периферийных устройств. При этом производится сравнение установок, записанных в CMOS (Complementary Metal Oxide Semiconductor) с тем, что реально обнаружено в системе. Некоторые несовпадения, например, различие типов флоппи-дисковода, могут быть допустимы и процесс загрузки продолжится. Другие ошибки, например, отсутствие видеокарты, приводят к невозможности дальнейшей загрузки. Но все сообщения о выявленных на этом этапе ошибках сводятся только к тому, что раздастся несколько коротких звуковых сигналов.
Можно еще отметить, что некоторые типы периферийных устройств могут содержать расширения BIOS в собственных ПЗУ. В таком случае устанавливаются соответствующие ссылки на эти расширения. Основная причина, по которой это необходимо, заключается в том, что по историческим причинам размер первичного загрузчика (загрузчика первого этапа, как мы его будем дальше называть) на персональных компьютерах ограничен величиной 446 байт. Этого явно недостаточно для того, чтобы включить в этот загрузчик драйверы всех периферийных устройств (например, дисплея и устройств хранения данных), которые могут понадобиться на этапе начальной загрузки системы. Тем более, что драйверы могут различаться для однотипных устройств от разных производителей. Поэтому функция загрузки некоторых драйверов возлагается на BIOS.
В составе исполняемого кода BIOS имеется утилита Setup, которая позволяет выполнить некоторые действия по конфигурированию аппаратных средств компьютера. Утилиту Setup обычно можно вызвать, если во время процесса самотестирования нажать указанную на экране клавишу. Параметры конфигурирования, установленные с помощью этой утилиты, запоминаются в энергонезависимой памяти, питаемой от миниатюрного аккумулятора, размещенного на материнской плате. Утилиту Setup можно использовать для некоторых настроек, но мы на этом не задерживаемся. Для интересующихся приведу несколько ссылок на материалы, в которых этот вопрос освещается подробнее.
После завершения процедуры самотестирования та часть кода BIOS, которая реализует процедуры самотестирования (POST), удаляется из оперативной памяти за ненадобностью. Оставшаяся часть BIOS, реализующая функции BIOS (runtime services), остается в ОП. Она будет доступна в последующем для загруженной операционой системы.
Первой задачей той части BIOS, которая осталась в ОП, является поиск активного загрузочного устройства. Список устройств, которые могут являться загрузочными, хранится в энергонезависимой памяти компьютера (CMOS), а порядок просмотра этого списка является одним из настраиваемых параметров BIOS. Загрузочным устройством может быть дискета, CD-ROM, раздел жесткого диска, сетевое устройство или даже USB-устройство (флеш-диск). Поиск загрузочного устройства осуществляется путем вызова прерывания INT19h BIOS.
Процедура обработки прерывания INT19h состоит в том, что считывается сектор с координатами Cylinder:0 Head:0 Sector:1 на очередном устройстве, его содержимое помещается в ОП по адресу 0000:7С00h, после чего осуществляется проверка, является ли этот сектор загрузочным, то есть содержит ли он код первичного загрузчика. Загрузочные сектора помечаются "волшебным" числом 0x55AA в позиции 0x1FE = 510. Это последние два байта сектора. Наличие (или отсутствие) такого кода в последних байтах сектора позволяет программе BIOS решить, является ли данное устройство загрузочным.
Как только программа обработки прерывания обнаружит, что загруженный в память сектор содержит это самое "магическое число" 0x55AA, управление передается на начало этого сектора (по абсолютному адресу 0000:7С00h). Дальнейшие события зависят от того, где обнаружен загрузочный сектор - на жестком диске или на одном из других устройств: дискете, CD или flash-диске (на всех этих устройствах обычно создается образ загрузочной дискеты).
Если при проверке загрузочный сектор не обнаружен ни на одном устройстве, вызывается прерывание INT18h. Когда-то (в первых персональных компьютерах, производимых компанией IBM) это прерывание служило для вызова интерпретатора ROM-BASIC, который дальше управлял работой компьютера. Клоны IBM-PC не имеют BASIC в ROM-памяти и теперь это прерывание используют для организации загрузки по сети. Но мы не будем рассматривать эту ветку развития событий и вернемся к тому случаю, когда прерывание INT19h обнаружило загрузочный диск и передало управление находящейся в нем программе.
Примечание: Как следует из приведенного выше описания, BIOS выполняет массу работы по тестированию системы. Как мы увидим чуть позже, ядро Linux потом повторно проделывает всю эту работу. Как правило, после загрузки ядра большинство функций BIOS не используется (хотя есть некоторые исключения) и, тем не менее, этот уже бесполезный код BIOS сохраняется в "теневой" памяти компьютера, отнимая часть драгоценного ресурса у работающей системы.
Назад | Оглавление | Вперед |