Отправляет email-рассылки с помощью сервиса Sendsay

Unix изнутри

  Все выпуски  

Unix изнутри - Выпуск 2


Информационный Канал Subscribe.Ru


Заочная Школа Программистов
Студия "Unix изнутри"
iunix.narod.ru

От автора.
К сожалению, работа над выпусками идет гораздо медленнее, чем предполагалось. Поэтому, было принято решение разбивать выпуски на более мелкие части.
В этом выпуске описывается процессы, которые проиходят сразу после загрузки ядра Linux в память.
С удовольствием выслушаю ваши предложения и замечания. Пишите мне на адрес iunix@narod.ru.

Процесс первоначальной загрузки.

Часть 2. Подготовка ядра Linux к работе

Итак, ядро Linux загружено в память. Что же просходит дальше?
В прошлом выпуске говорилось, что загрузчик последней стадии загружает ядро в память и передает ему управление. Это правда, но не вся.
Дело в том, что ядро Linux состоит из двух частей - собственно образа ядра и процедуры setup. Эти две части загружаются по разным адресам: Процедура setup - по адресу 0x00090200. Оставшаяся часть ядра - производится либо по адресу 0x00010000 (так называемая загрузка "в нижние адреса" для ядер малого размера, собираемых командой "make zImage"), либо по адресу 0x00100000 (называется загрузкой "в верхние адреса" для больших ядер, собираемых командой "make bzImage"). Это, кстати, означает, что такое ядро не может быть запущено на компьютере с объемом памяти, меньшим 1 Мб.
Необходимо сделать еще одно дополнение к предыдущему выпуску. Может возникнуть вопрос, как же осуществляется загрузка ядра в реальном режиме процессора в память выше 1 мегабайта? Эту проблему решает загрузчик LILO. Он загружает с диска часть ядра, размером 64 Кбайта и вызывает функцию BIOS, которая переносит загруженный фрагмент в верхнюю память (с временным переключением в защищенный режим и прочими приседаниями). После чего процесс повторяется до тех пор, пока не будет загружено все ядро.

1. Настройка аппаратного окружения для работы ядра
Итак, после загрузки ядра в память управление передается функции setup(). Процессор еще работает в реальном режиме. Текущая задача состоит в том, чтобы обнаружить и в нужном порядке инициализировать все имеющиеся в компьютере аппаратные устройства. И хотя BIOS уже проинициализировал большую часть аппаратуры, ядро Linux инициализирует все устройства по-своему. В частности, определяется объем имеющейся оперативной памяти, тип видеоадаптера, переинициализируются дисковые накопители. Отчасти это связано с тем, что Linux работает в защищенном режиме, в то время как BIOS - в реальном, и переключение между этими режимами - довольно медленная процедура.
Можно сказать, что функция setup() создает среду для работы ядра и как бы избавляет его от тяжелого наследия реального режима, в котором нет поддержки многозадачности, размер памяти ограничен 1 мегабайтом, а разрядность процессора - 16 битами. Ядро начинает работать уже в "дружественной" обстановке.

2. Настройка программного окружения для работы ядра.
Как и любая программа, ядро Linux требует для свой работы правильно настроенный стек, инизиализированные значения глобальных переменных и много чего еще. И если для обычной программы все эти действия будут выполнены стандартной библиотекой, функции которой будут выполнены еще до вызова функции main() (про это можно прочитать в статье "Как запускается функция main() в Linux" [1]), то ядро Linux само должно позаботиться о решении этой проблемы.
Кроме того, файл с ядром Linux чаще всего упакован, чтобы сохранить место на диске, и уменьшить время его копирования в память (что становится актуальным при загрузки с дискеты или по сети).
Эти проблемы решает функция startup_32,находящаяся в файле /usr/src/linux-2.4.2/arch/i386/boot/compressed/head.S.
В ходе выполнения эта функция делает следующее:

  • Инициализирует сегментные регистры и временный стек.
  • Заполняет нулями области неинициализированных данных ядра. Сюда входят глобальные переменные, массивы и структуры ядра, которым в исходном тексте ядра не было присвоено значение.
  • Распаковывает образ ядра Linux. Именно в это время на экране появляется надпись "Uncompressing Linux ...". Если запакованый образ был загружен так, что перекрывается с адресом, по которому должно находиться рабочее ядро (при загрузке в "верхние адреса"), то распакованное ядро помещается во временный буфер, сразу за сжатым образом.
  • После того, как образ ядра распакован, на экран выводится сообщение "OK, booting the kernel.".
  • Если ядро было распаковано во временный буфер, будет вызвана функция, перемещающая ядро на положенное ему место, по адресу 0x00100000 (move_routine_start()). Эта функция позиционно-независима, т.е. будет работать независимо от места в памяти, где она находится.
  • И, наконец, управление передается функции startup_32(), находящейся по адресу 0x00100000.
Итак, после выполнения этой функции ядро готово к работе. После этого вызывается другая функция startup_32(), уже из распакованного ядра.
Тут может возникнуть небольшая путаница. Как могут быть в одной программе две функции с одинаковыми именами? На самом деле эта проблема решается очень просто. Одна функция startup_32() находится внутри запакованного ядра, а вторая - в его распаковщике. Во-вторых, процессор вызывается функции не по имени, а по адресу. А уж адреса-то у них разные.

Продолжение следует

Литература
0. http://iunix.narod.ru/material/_N1_bootstrap.html Предыдущий выпуск рассылки.
1. Hyouck "Hawk" Kim "Как запускается функция main() в Linux", Перевод Андрея Киселева.
2.
http://www.linuxgazette.com/issue70/ghosh.html "Bootstrapping a Linux system - an Analysis"
3. http://gazette.linux.ru.net/lg70/articles/rus-ghosh2.html "Bootstrapping, или как Linux сам себя ставит на ноги. Анализ процесса начальной самозагрузки"
4. Ядро ОС Linux. Руководство системного программиста.
5. http://www.moses.uklinux.net/patches/lki.sgml Tigran Aivazian "Linux Kernel 2.4 Internals"

http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное