Наши партнеры

UnixForum






Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Тематический каталог -> Процесс начальной загрузки системы

Загружаем ОС...

Владимир Попов, 2003-02-04 21:02:36.

"С чего начинается..."

Жизнь вычислительных систем изрядно скучна. Это у нас, если верить Ф. Энгельсу, жизнь - это, прежде всего самовоспроизведение, а у них... Оператор за оператором, иногда - прерывания, да и те не всегда "по делу". К тому же, всё это (спасибо Джону фон Нейману) в одном и том же пространстве: и инструкции, и данные... Главное - не сбиться. С самого начала. С загрузки, то есть. Есть, конечно, системы, не использующие динамических данных, и поэтому не нуждающиеся в ОЗУ, но, по нынешним временам, это - экзотика. Для большинства вычислительных систем пространство, в котором находятся эти самые инструкции и данные - это пространство ОЗУ. Следовательно, прежде чем "жить", вычислительной системе нужно загрузить в ОЗУ нечто и передать на него управление. Легко сказать, если единственное, что умеешь - это выполнять инструкции, УЖЕ находящиеся в памяти. Именно об этом сказано: "поднять себя за шнурки собственных ботинок". И словечко подходящее подобрали: "boot". Наше "загрузить" - только полдела описывает. А вот: "с носка её!". К счастью, память бывает не только оперативная. В ПЗУ, например, программу загрузки можно записать при производстве ЭВМ, а она уже остальное загрузит... Только вот, что - остальное? Операционных систем много больше, чем аппаратных платформ. Не исключено также, что аппаратура переживёт ПО... Хотя может - и наоборот, конечно. Требуется соглашение и инициатором его, как правило, выступает производитель ЭВМ. Для персональных компьютеров это - IBM, как известно.

В первом приближении соглашение о загрузке IBM PC выглядит достаточно просто: загрузка происходит с блочного устройства и состоит в переносе в память "нулевого" блока этого самого устройства с последующей передачей на него управления. Размер блока - 512 байт: не шибко "разгуляешься". Блок этот назвали boot record (загрузочная запись), а для жёсткого диска, который предполагалось разделить на несколько разделов, добавили эпитет master. Отсюда аббревиатура MBR (master boot record) - главная загрузочная запись, по-нашему. Не захотели, стало быть, конструкторы от IBM оставлять своё детище заведомо "моноосным". То ли предчувствовали грядущую размолвку с MicroSoft, то ли действительно дорожили идеалами свободной конкуренции, однако договорились: часть MBR отвести под таблицу, описывающую максимум четыре раздела, любой из которых может загружаться. Таблицу эту, "не мудрствуя лукаво", так и назвали - partition table (таблица разделов). Описывает она физические размеры и расположение разделов (с некоторых пор: с учётом логической адресации блоков - LBA), типы их файловых систем и, так называемую, "активность" - признак загружаемости: если равноправных разделов больше одного, то надо же знать, который именно загружается. Технические детали этого описания опустим: "ищущий да обрящет".

За вычетом таблицы разделов в MBR остаётся всего-то 384 байта. Они-то и стали "полем боя" для программок, называемых загрузчиками. Не серьёзно, на первый взгляд. Но если эти без малого четыре сотни байт определяют, какая ОС загружается дальше... Не к ночи будь названа, MicroSoft определилась моментально: возможность "потеснить" потенциальных конкурентов намного важнее количества первичных разделов или какой-то там мультизагрузки. Нет их - и всё тут. Сработало. Абсолютное большинство пользователей IBM PC в "обёртке" от MicroSoft понятия не имеют о мультизагрузке, да и о разделах вообще. Естественно, как реакция, тут же нашлись желающие продавать "потенциально" существующую мультизагрузку. Их продукты стали называть "менеджерами загрузки", но... MicroSoft почти не оставила им шансов на выживание, "походя" переписывая MBR при каждой инсталляции. Учитывая то, что реинсталляция MS Windows требуется приблизительно так же часто, как размораживание холодильника (говорят, и эффект тот же: помогает, но ненадолго), не удивительно, что сохранять при этом работающим мультизагрузчик удавалось только самым компетентным.

Другое дело - Open Source. Здесь никто никого не теснил. Напротив: обязательным казалось предоставление возможности загрузки как можно большему числу ОС. MS Windows - в том числе. Стандартный загрузчик Linux (LILO - LInux LOader) для линуксоидов практически всем хорош: не пугает их ни необходимость переустановки LILO после каждой реконфигурации, ни то, что для такой переустановки нужно сначала загрузить Linux. Последним словом в истории мультизагрузчиков LILO, однако, не стал...

GRUB, как загрузчик "всех времён..."

Как, собственно, и Linux - не единственная ОС, созданная и развиваемая сторонниками Open Source. Я бы даже сказал: далеко не единственная. Причём, кроме достаточно близких "родственников" по линии UNIX, есть и "оригиналы", как HURD, например. Вернёмся, однако, к загрузчикам. Из сказанного следует, что раз появляются принципиально новые ОС, то возникает потребность и в новых загрузчиках. Так, в 1995 году Erich Boleyn в попытках загрузить GNU Hurd решил создать новый загрузчик, вместо того, чтобы модифицировать загрузчик FreeBSD. А для того, чтобы работа эта не пропала "втуне", в содружестве с Brian Ford была разработана спецификация мультизагрузки (Multiboot Specification). Любое ядро, построенное в соответствии с данной спецификацией, может быть загружено соответствующим мультизагрузчиком. Первым из таковых и стал GRUB - GRand Unified Bootloader. Сильные стороны Open Source можно демонстрировать, среди прочего, и на примере GRUB: хорошие разработки не пропадают. Когда в 1999 году Erich Boleyn перестал уделять своему детищу достаточно внимания, Gordon Matzigkeit и Yoshinori K. Okuji оформили GRUB как официальный пакет GNU, каким он по сей день и является.

На настоящий момент GRUB входит практически во все дистрибутивы Linux, для большинства из них является "загрузчиком по умолчанию" и завоёвывает всё большую популярность у пользователей других операционных систем. Оправдывает, одним словом, свой титул. И это не только моё мнение. Для приверженцев Gentoo, коих большинство среди посетителей этого сайта, сошлюсь только на тот факт, что автор одного из наиболее известных описаний GRUB - Daniel Robbins, не нуждающийся в представлении в кругу Gentoo-адептов.

Кроме уже названного соответствия спецификации мультизагрузки, вот неполный перечень возможностей GRUB:

  • дружественность основных функций к пользователю;
  • высокая функциональность в интересах разработчиков ядер;
  • обратная совместимость для загрузки ядер FreeBSD, NetBSD, OpenBSD и Linux;
  • загрузка DOS, Windows NT и OS/2 методом "по цепи";
  • возможность "цепочечной" загрузки для открытых ОС (Net- и OpenBSD) версий, более новых, чем текущая версия GRUB;
  • множество загружаемых форматов;
  • текстовый (и прозрачно ясный по структуре) файл конфигурации;
  • меню-интерфейс;
  • гибкий командный интерфейс;
  • множество поддерживаемых файловых систем;
  • автоматическая декомпрессия;
  • способность читать данные с любого из определяемых BIOS устройств;
  • независимость от геометрии дисков;
  • поддержка LBA;
  • поддержка загрузки по сети;
  • возможность работы с удалёнными терминалами.

Споры между приверженцами LILO и GRUB мало напоминают "религиозные войны", склонность к которым, к сожалению, иногда демонстрирует UNIX-сообщество. Возможно, потому, что "пристрастный" анализ практически неминуемо убеждает, что GRUB превосходит соперника. Оставим в стороне функции, которых нет у LILO, но есть у GRUB: в конце концов, может вам никогда и не требовалось работать с удалёнными терминалами или загружаться исключительно с дискеты (по причине невозможности загрузки с HDD или CD-ROM). Сравним, как эти загрузчики выполняют только одну, общую для них функцию. Причём - основную: собственно загрузку ядер ОС.

Любой из загрузчиков при инсталляции "перехватывает инициативу", записывая начальную порцию своего кода (всё те же 512 байт - больше BIOS просто не прочитает) в главную загрузочную запись устройства. В этом смысле все они одинаковы: другого способа получить управление от BIOS не существует. Эта начальная порция кода в терминологии GRUB называется stage1. Трудно, однако, в 512 байтах (даже меньше, как мы уже выяснили) разместить код, способный загружать разные ядра или даже ОС, да ещё и в меню-ориентированном режиме. Ближе всех к этому был Илья Евсеев, предложивший код главного загрузчика, способный загружать любой из загрузчиков трёх первичных разделов. Здорово, но при чём тут ядра Linux, BSD и прочая? Чай не DOS... Да и почему ограничиваться только первичными разделами?... "Патовая" ситуация разрешается загрузкой второй порции загрузчика. Вот тут-то и начинаются различия. Где BIOS находит код первой фазы загрузки (для GRUB - stage1) - известно: 0:0:0, как и договаривались, а вот где, в свою очередь, эта первая фаза будет искать своё продолжение (для GRUB - stage2, то есть)? LILO поступает просто: первая часть кода при инсталляции получает адрес продолжения в виде списка блоков, в которых и записано это самое "продолжение". "Продолжение" - не обязательно код. Это может быть и список необходимых файлов, но адресуемых физически, как блоки. GRUB же поступает изощрённее: в блоки, следующие за загрузочным, последовательно записывается код промежуточной фазы: stage1_5. Одного взгляда на имена файлов, содержащих инструкции этой фазы (все, оканчивающиеся на stage1_5) достаточно, что бы предположить её назначение: читать последующие данные средствами, предоставляемыми файловыми системами. И это предположение - верно. А вот что из этого следует:

  • реконфигурация загрузчика не требует перезаписи главной загрузочной записи;
  • предназначенные для загрузки ядра адресуются обычным для файловых систем способом;
  • физические операции над содержимым диска (дефрагментация, перенос файлов), никак не отражаются на работе загрузчика;
  • плюс следствие: логическая адресация объектов загрузки делает возможным управление ими не только по заранее определённому сценарию, но и в интерактивном режиме. И возможность эта реализована в виде командного режима работы.

Выше изложенного уже достаточно, что бы предпочесть GRUB. При этом не надо думать, что адресация посредством физических блоков не известна GRUB. Если запись stage1_5 по каким-либо причинам невозможна, то применяется адресация посредством физических блоков. То есть, в этом случае GRUB как бы "опускается" до методологии LILO. Надеюсь, убедил. Перейдём к конкретным деталям.

Как сделать:

Если не обнаружено в дистрибутиве (что, в настоящее время, уже маловероятно), то на ftp://alpha.gnu.org/gnu/grub/ можно обнаружить следующие файлы:

  • grub-VERSION.tar.gz
  • grub-VERSION-i386-pc.ext2fs
  • grub-VERSION-i386-pc.tar.gz

Первый из перечисленных - привычный tarball, предназначенный для распространения в исходных текстах. Из его содержимого GRUB можно бесхитростно построить:

	$ ./configure
	$ make
	$ make install

В результате получится так называемая host-версия загрузчика - почти полнофункциональная, но запускаемая не BIOS, после обнаружения в загрузочном блоке, а как обычное приложение.

Второй - образ дискеты с файловой системой ext2. Загрузившись с этой дискеты, получаем возможность работы с полнофункциональным, системно независимым вариантом загрузчика.

Третий - бинарный вариант распространения, содержащий все необходимые файлы. Редкий случай: даже последовательные сторонники самостоятельной компиляции ПО признают, что использование предлагаемых бинарных файлов вполне оправдано: самостоятельная компиляция ничего не добавит, поскольку процесс определяется архитектурой IBM PC и особенностями различных файловых систем. Отсутствует только host-версия. Но при наличии дискеты, загружающей GRUB, без неё вполне можно обойтись.

Примечание А.Ф.: для пользователей именно Gentoo Linux компиляция GRUB (через систему портежей) часто оказывается необходимостью - вследствие ошибки в прекомпилированной версии из штатного базового тарбалла.

Способов инсталляции загрузчика несколько и, как мне кажется, проще разобраться в сути происходящего, нежели их запомнить. Действительно необходимыми являются только две вещи: каталог /boot/grub/ (с содержимым: stage1, stage2 и stage1_5 для интересующих файловых систем) и наличие stage1 и stage1_5 в начальных блоках устройства. Разумеется, stage1_5 должна соответствовать файловой системе, на которой расположен каталог /boot/grub/.

С созданием каталога /boot/grub/ проблем вообще никаких быть не может, а вот способов поместить stage1 и stage1_5 в начальные блоки действительно несколько. И хотя применение команды dd, своей мощностью, простотой и, одновременно, опасностью напоминающей лом, против которого, как известно, "нет приёма", не возбраняется, в данном случае рекомендуется всё-таки пользоваться средствами GRUB. Сойдёт и host-версия, и загруженная с оригинальной дискеты. В любом случае достаточно набрать команды:

	grub> root (fd0)
	grub> setup (fd0)

Разумеется, вместо (fd0) может быть любое другое блочное устройство. Вообще setup - скрипт, включающий в себя несколько команд более низкого уровня (install, embed, etc...), но коль уж он существует, почему бы им не воспользоваться? Нужно только помнить, что:

  • идентификатор устройства или раздела всегда "обрамляется" круглыми скобками;
  • нумерация устройств и разделов начинается с нуля;
  • логические разделы HDD имеют номера, начиная с 4 (что для пользователей UNIX не должно быть удивительным).

Полный формат идентификатора выглядит так:

	(device[,part-num][,bsd-subpart-letter])

где device - имя устройства, part-num - номер раздела, bsd-subpart-letter - буквенный идентификатор подраздела, известный, очевидно, пользователям FreeBSD (где первичный раздел именуется слайсом, а термин partitions закреплен за логическими его частями).

Что умеет

Умеет GRUB много. С точки зрения некоторых пользователей - даже слишком. Количество используемых команд существенно превышает полсотни. В документации они разделены на меню-специфичные, используемые только в глобальной секции конфигурационного файла, общие, используемые как в описании меню, так и в командном режиме, и команды интерактивного режима, которые если и могут быть включены в конфигурационный файл, то только в секциях, писывающих отдельные позиции меню. Повторение описания - занятие неблагодарное. GRUB прекрасно документирован: распространяемый пакет включает в себя небольшой man и исчерпывающее info. С соответствующей странички сайта GNU можно скачать документацию в html-формате. Но, возможно, ничего этого делать и не придётся: GRUB имеет встроенную систему помощи, которая в ответ на <help> всегда выведет список доступных к выполнению команд, а в ответ на <help command> выдаст дополнительную информацию. Автозаполнение строки подскажет не только синтаксис команды, но и, в некоторых случаях, варианты её продолжения (доступные устройства, разделы). Одним словом, эпитет bash-подобной командная оболочка GRUB имеет вполне заслуженно. При всём этом как-то даже неловко повторяться... Последовав примеру Daniel Robbins, просто приведём конфигурационный файл, включающий в себя наиболее часто используемые команды:

	default 0
	timeout 30
	color light-gray/blue black/light-gray

	title=Boot Linux
	root (hd0,4)
	kernel /boot/bzImage ro root=/dev/hda5 vga=792 hdd=ide-scsi

	title=Boot Linux using initrd
	root (hd0,5)
	kernel /boot/bzImage root=/dev/loop0 vga=791 init=/initdisk.gz
	initrd /initdisk.gz

	title=Windows NT
	root (hd0,3)
	chainloader +1

Параметры ядру передаются, очевидно, обычным образом. Разумеется, значение параметра root описывает корневой раздел в нотации Linux, а не GRUB, а в остальном, мне кажется, ошибиться довольно трудно.

Примечание А.Ф.: из приведенного примера легко понять, как средствами GRUB обеспечить загрузку Linux. Аналогична ситуация и с операционками BSD-клана, например, FreeBSD. Однако в некоторых случаях ядро BSD-системы, такой, как NetBSD или OpenBSD, загрузить не удается. Это бывает, когда версия ядра оказывается более новой, чем имеющаяся в наличии версия GRUB. Однако повода отчаиваться нет: в такой ситуации вполне можно привегнуть к загрузке "по цепочке", как это делается для ОС Windows-семейства.

Все "горячие" клавиши, действующие при появлении меню на экране, описаны в нижней части самого же меню. В командном режиме <help> к вашим услугам: авторы, кажется, сделали всё, что бы избавить склонных к графомании от стремления описывать их детище, за что им особое спасибо.

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

  • создание новых первичных разделов;
  • изменение типов разделов;
  • изменение флагов активности (загружаемости) первичных разделов;
  • "скрытие" разделов прибавлением 0x80 к их идентификатору;
  • map-ирование устройств: подмена одного блочного устройства другим, как это делает BIOS, для того, что бы осуществить загрузку не с первого винчестера, например.

А вот файловые операции, облегчающие работу в командном режиме:

  • получение списка блоков файла, как раз для того случая, когда stage1_5 для используемой файловой системы не существует;
  • просмотр содержимого файла. Очень полезно. Например:
        	grub> cat /etc/fstab
  • сравнение файлов;
  • поиск файла;
  • загрузка ядра и модулей;

И ещё...

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

  • вывод меню в графическом режиме, на фоне, определяемом так называемым splashimage;
  • загрузка по сети при наличии tftp-сервера. То есть, сервер присваивает клиенту ip-адрес, после чего становится возможной загрузка конфигурационного файла или ядра непосредственно с сервера. Возможно и ручное конфигурирование сетевого интерфейса;
  • защита паролем меню или его отдельных позиций. Пароль может шифроваться;
  • скрытие меню. Загрузка в этом случае произойдёт в соответствии с позицией меню "по умолчанию", если только тайм-аут не будет прерван нажатием <Esc>;
  • загрузка вычислительных систем, не снабжённых клавиатурой и дисплеем. В этом случае используется последовательный интерфейс;
  • возможность протестировать адекватность чтения файловой системы до загрузки ядра;
  • возможность переназначения клавиш.