Open-Club.Net Проект полностью ориентирован на Open Source-подход(изучаем, настраиваем, устанавливаем и общаемся о Linux).
Мы в соц. сетях:
Главная » Статьи » Статьи о Linux [ Добавить статью ]

Подробности процесса загрузки Linux

Когда-то давно термин bootstrapping (загрузка) в компьютерной области означал загрузку бумажной ленты, на которой хранилась программа начальной загрузки, или же ввод программы начальной загрузки вручную при помощи расположенных на передней панели переключателей адреса/данных/управления. Современные компьютеры оборудованы устройствами, которые значительно упрощают процесс первоначальной загрузки – однако это не означает, что этот процесс является простым.

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

Общие сведения

На рисунке 1 показан вид с "высоты птичьего полета".


Рисунок 1. Вид на процесс начальной загрузки в Linux с высоты птичьего полета
Взгляд на загрузку ядра Linux с самого высокого уровня

При первоначальной загрузке системы или при ее перезагрузке системы процессор выполняет код, который расположен в хорошо известном месте. В персональном компьютере это место соответствует базовой системе ввода/вывода (BIOS), которая хранится в расположенной на системной плате микросхеме энергонезависимой flash-памяти. Центральный процессор (CPU) встраиваемой системы обращается к reset-вектору для получения адреса программы, которая хранится по известному адресу в flash/ROM-памяти. В любом случае это приводит к одному и тому же результату. Так как персональные компьютеры отличаются намного большей универсальностью, BIOS должна определить, какие именно устройства являются кандидатами на выполнение начальной загрузки. Мы подробно рассмотрим данный процесс позже.

После того, как устройство, с которого будет осуществляться начальная загрузка, найдено, начальный загрузчик первой ступени загружается в оперативную память и начинается его выполнение. Этот начальный загрузчик имеет размер менее 512 байт (один сектор), и его задачей является загрузка начального загрузчика второй ступени.

После того, как в оперативную память загружается и начинает выполняться начальный загрузчик второй ступени, на экране обычно отображается заставка и в память загружаются Linux вместе с необязательным начальным RAM-диском (временная система корневых файлов). После того как эти образы будут загружены, начальный загрузчик второй ступени передает управление ядру и выполняется декомпрессия и инициализация ядра. На этой стадии начальный загрузчик второй ступени проверяет аппаратное обеспечение системы, выполняет нумерацию подключенных устройств, монтирует корневое устройство и затем загружает необходимые модули ядра. После завершения этих задач запускается первая пользовательская программа (init) и затем выполняется инициализация системы высокого уровня.

Таков в общих чертах процесс начальной загрузки в Linux. Теперь давайте углубимся чуть далее и рассмотрим некоторые подробности начальной загрузки в Linux.






Запуск системы

Запуск системы определяется той аппаратной платформой, на которой выполняется начальная загрузка Linux. На встраиваемых платформах при включении питания системы или при перезагрузке используется bootstrap-среда. В качестве примеров можно привести U-Boot, RedBoot и MicroMonitor от компании Lucent. Эти программы хранятся в специальной области flash-памяти, расположенной во встраиваемой системе: они предоставляют средства для загрузки образа ядра Linux во flash-память и в дальнейшем обеспечивают выполнение этого ядра. В дополнение к функциям по хранению и загрузке образа Linux эти мониторы загрузки также выполняют тестирование системы на каком-то уровне и инициализацию аппаратного обеспечения. Во встраиваемых системах подобные мониторы загрузки обычно объединяют функции загрузчиков первой и второй ступени.

Просмотр содержимого MBR

Для просмотра содержимого MBR используйте следующую команду:

# dd if=/dev/hda of=mbr.bin bs=512 count=1
# od -xa mbr.bin

Командаdd, которая выполняется с правами root, считывает первые 512 байт с /dev/hda (первый IDE-жесткий диск) и записывает их в файл mbr.bin. Команда od выполняет печать полученного двоичного файла в форматах hex и ASCII.

На персональных компьютерах загрузка Linux начинается в BIOS с адреса 0xFFFF0. Первым действием, которое выполняет BIOS, является тестирование при включении питания (POST, power-on self test). Задачей такого тестирования является выполнение проверки аппаратного обеспечения. Вторым действием POST является выполнение нумерации и инициализации для локальных устройств.

Если учитывать различное назначение функций BIOS, то можно считать, что BIOS состоит из двух частей: кода POST и сервисов времени выполнения. После завершения POST соответствующий код удаляется из памяти, однако сервисы времени выполнения BIOS остаются в памяти и доступны для операционной системы.

Для выполнения загрузки операционной системы сервисы времени выполнения BIOS выполняют поиск таких устройств, которые являются активными и способны выполнять загрузку – причем поиск выполняется в порядке, который определяется настройками, сохраненными в CMOS-памяти. В качестве загрузочных устройств могут выступать флоппи-диски, CD-ROM, разделы на жестком диске, подключенное к сети устройство или даже портативный USB-накопитель.

Обычно загрузка Linux производится с жесткого диска, на котором в MBR содержится первичный начальный загрузчик. MBR представляет собой сектор размером 512 байт, который располагается в первом секторе диска (сектор 1 цилиндра 0, головка 0). После того как MBR загружается в память, BIOS передает ему управление.






Загрузчик 1-й ступени

Первичный начальный загрузчик, хранящийся в MBR, представляет собой образ размером 512 байт, который содержит как программный код, так и небольшую таблицу разделов (см. рисунок 2). Первые 446 байт представляют собой собственно первичный загрузчик, который содержит как программный код, так и текст сообщений об ошибках. Следующие 64 байта представляют собой таблицу разделов, которая содержит запись для каждого из четырех разделов диска (по 16 байт каждая). В конце MBR располагаются два байта, которые носят название "магического числа" (0xAA55). Это магическое число служит для целей проверки MBR.


Рисунок 2. Строение MBR
Строение MBR

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






Загрузчик 2-й ступени

Вторичный загрузчик или загрузчик второй ступени было бы более логично назвать загрузчиком ядра. Его задачей на данной стадии является загрузка ядра Linux и, возможно, загрузка начального RAM-диска.

Загрузчики GRUB разных ступеней

Директория /boot/grub содержит загрузчики stage1,stage1.5 и stage2, а также некоторые альтернативные загрузчики (например, CR-ROM использует iso9660_stage_1_5).

Загрузчики для среды x86, которые объединяют в себе загрузчики первой и второй стадии, носят название Linux Loader (LILO) или GRand Unified Bootloader (GRUB). Так как LILO имел некоторые недостатки, которые были исправлены в GRUB, то далее мы будем рассматривать именно GRUB. (Большое количество дополнительных ссылок на материалы по GRUB, LILO и связанным с ними темам содержится в разделе Ресурса в конце данной статьи.)

Одним из наибольших достоинств GRUB является то, что он способен понимать используемые в Linux файловые системы. Вместо того чтобы подобно LILO, обращаться непосредственно к секторам жесткого диска, загрузчик GRUB способен загружать ядро Linux с файловых систем ext2 или ext3. Это достигается благодаря превращению двухступенчатого загрузчика в трехступенчатый. Ступень 1 (MBR) загружает загрузчик 1.5-ступени, способный понимать файловую систему, в которой хранится образ ядра Linux. Примерами могут служитьreiserfs_stage1_5(для загрузки из файловой системы с журналированием Reiser) илиe2fs_stage1_5 (для загрузки из файловых систем ext2 или ext3). После того, как загрузчик 1.5 ступени загружен и выполняется, может быть загружен загрузчик 2-й ступени.

После загрузки 2 ступени GRUB способен по запросу показать список имеющихся ядер (которые определяются в /etc/grub.conf, с поддержкой мягких ссылок из/etc/grub/menu.lst и/etc/grub.conf). Вы можете выбрать нужное ядро и даже передать ему дополнительные параметры ядра. Также существует возможность воспользоваться оболочкой с поддержкой командной строки, что обеспечивает большую степень контроля над процессом загрузки.

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






Ядро

Ручная загрузка в GRUB

Из командной строки в GRUB можно загрузить нужное ядро с указанным образом initrd следующим образом:

grub> kernel /bzImage-2.6.14.2
[Linux-bzImage, setup=0x1400, size=0x29672e]

grub> initrd /initrd-2.6.14.2.img
[Linux-initrd @ 0x5f13000, 0xcc199 bytes]

grub> boot

Uncompressing Linux... Ok, booting the kernel.

Если известно название ядра, которое вы хотите загрузить, то просто введите символ прямого слэша (/) и затем нажмите клавишу Tab. После этого GRUB отобразит список ядер и образов initrd.

После того как образ ядра оказывается в памяти и ему передается управление от загрузчика 2-й ступени, наступает стадия ядра. Однако образ ядра не является исполняемым, это сжатый образ ядра. Обычно это zImage (сжатый образ размером менее 512KB) или bzImage (большой сжатый образ, размером более 512KB), который был сжат при помощи zlib. В начале такого образа ядра располагается программа, которая выполняет минимальную настройку аппаратного обеспечения и затем распаковывает ядро, хранящееся внутри образа ядра, и помещает его в верхнюю область памяти. Если имеется образ начального RAM-диска, то программа также перемещает его в память и помечает для дальнейшего использования, а затем вызывает само ядро, после чего начинается загрузка ядра.

При вызове bzImage (образ для i386) выполнение начинается в./arch/i386/boot/head.Sс ассемблерной функцииstart (основные этапы показаны на рисунке 3). Эта программа выполняет основную настройку аппаратного обеспечения и вызывает процедуруstartup_32, располагающуюся в ./arch/i386/boot/compressed/head.S. Процедура настраивает базовую среду (стек и т.п.) и очищает Block Started by Symbol (BSS). Затем выполняется декомпрессия ядра при помощи вызова C-функцииdecompress_kernel(которая хранится в ./arch/i386/boot/compressed/misc.c). После декомпрессии ядра в память происходит его вызов. Это еще одна функция startup_32, но она располагается в файле ./arch/i386/kernel/head.S.

В новой функцииstartup_32 (которая называется swapper или process 0) инициализируются таблицы страниц (page tables) и обеспечивается подключение функции memory paging (отображение страниц). Также определяется тип центрального процессора и сопроцессора для вычислений с плавающей точкой (FPU), если он имеется, и данная информация сохраняется для последующего использования. Далее вызывается функцияstart_kernelиз(init/main.c), которая осуществляет переход в ту часть ядра Linux, которая не зависит от особенностей конкретной аппаратной платформы. Можно сказать, что это функция main для ядра Linux.


Рисунок 3. Выполнение основных функций при загрузке ядра Linux для i386
Основные функции в процессе загрузки ядра Linux i386

При обращении к start_kernel вызывается длинный список функций инициализации, которые выполняют настройку прерываний, производят дальнейшее конфигурирование памяти и загружают начальный RAM-диск. После этого вызывается функция kernel_thread (изarch/i386/kernel/process.c), запускающая функциюinit, которая является первым процессом, выполняющимся в пространстве пользователя. В заключение запускается idle task, после чего управление может взять на себя планировщик (scheduler) (после вызова cpu_idle). Если разрешены прерывания, вытесняющий планировщик (pre-emptive scheduler) будет периодически перехватывать контроль для поддержки многозадачности.

В процессе загрузки ядра выполняется загрузка в оперативную память и монтирование начального RAM-диска (initrd), который был загружен в память загрузчиком 2-й ступени. Данныйinitrdслужит временной корневой файловой системой в оперативной памяти и позволяет ядру полностью загрузиться, не выполняя монтирование каких-то физических дисков. Так как модули, необходимые для взаимодействия с периферийными устройствами, могут являться частьюinitrd, то ядро получается очень компактным и тем не менее способно поддерживать самые разнообразные аппаратные конфигурации. После загрузки ядра корневая файловая система заменяется (при помощиpivot_root); при этом корневая файловая система initrd удаляется и монтируется действительная корневая файловая система.

Вывод функции decompress_kernel

Функцияdecompress_kernel отвечает за те обычные сообщения о разархивировании, которые появляются на экране :

Uncompressing Linux... Ok, booting the kernel.

Функция initrd позволяет создать компактное ядро Linux, где драйверы скомпилированы как загружаемые модули. Эти загружаемые модули обеспечивают доступ ядра к дискам и файловым системам, которые имеются на этих дисках. Также имеются драйверы для других аппаратных устройств. Так как корневая файловая система представляет собой файловую систему на диске, то функция initrd обеспечивает для загрузчика возможность обратиться к диску и смонтировать действительную корневую файловую систему. Во встраиваемой системе без жесткого диска initrd может представлять собой окончательную файловую систему, или же окончательная файловая система может монтироваться при помощи сетевой файловой системы (Network File System, NFS).






Init

После загрузки и инициализации ядра запускается первое приложение в пространстве пользователя. Это первая из вызываемых программ, которые скомпилированы со стандартной библиотекой C. До этого момента процесса стандартные C-приложения еще не выполнялись.

На обычных настольных системах с операционной системой Linux обычно первым запускаемым приложением является/sbin/init. Однако это обязательно. Во встраиваемых системах редко требуется такая обширная инициализация, которую обеспечиваетinit(которая конфигурируется при помощи /etc/inittab). Во многих случаях можно запустить простой shell-скрипт, который запускает необходимые встраиваемые приложения.






Заключение

Как и сама операционная система Linux, процесс загрузки ядра является чрезвычайно гибким и универсальным и поддерживает большое количество процессоров и аппаратных платформ. В самом начале загрузчик loadlin обеспечивал простой способ загрузки Linux без поддержки каких-либо необязательных аксессуаров. Загрузчик LILO расширил круг поддерживаемых функций, однако его недостатком являлось отсутствие поддержки файловых систем. Последнее поколение загрузчиков, таких как GRUB, позволяет загружать Linux с самых различных файловых систем (начиная с Minix и заканчивая Reiser).

Категория: Статьи о Linux | Добавил: Root (11.11.2008)
Просмотров: 4258 | Рейтинг: 0.0/0
Похожие материалы:
Всего комментариев: 0
ComForm">
avatar
Профиль
Поиск
Категории раздела
Участвуйте в опросе
Какой у вас Linux ?!
Всего ответов: 348
Статистика

Яндекс.Метрика

Онлайн всего: 3
Гостей: 3
Пользователей: 0

Нас уже: 1302 Линуксоидов
Сегодня нас посетили следующие Линуксоиды -