Процесс загрузки ядра linux

Linux First: Загрузка ядра

После предыдущего поста “Кратко о linux-ядре” есть общее представление как устроено ядро. Дальше поговорим про загрузку компьютера в общем и ядра в частности.

Попутно создадим образ жесткого диска, на базе которого продолжим разбираться с linux в следующих статьях.

Загрузка от включения ПК до устройства #

  • После включения код BIOS загружается в оперативную память (ОЗУ) из постоянной памяти (ПЗУ)
  • После загрузки в ОЗУ код BIOS выполняет тест оборудования Power-On Self-Test (POST-тест)
  • Читает настройки BIOS из ПЗУ
  • Ищет и загружает в оперативную память код загрузчика
  • Передает управление загрузчику

Кроме этого BIOS предоставляет API для работы с устройствами еще до загрузки Операционной Системы

Подробно останавливаться на этом этапе смысла нет, мы будем собирать образ диска с linux и загружать его используя эмулятор QEMU

Эмулятор аппаратных платформ, позволяет эмулировать разные процессоры.

Мы будем использовать qemu для x86_64

Загрузка с устройства #

Все команды выполнялись на ubuntu 16.04

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

в случае с QEMU это выглядит так:

$ qemu-system-x86_64 \ # запускаем эмулятор с архитектурой x86_64 
-nographic \ # весь вывод будет в консоль, иначе откроется gui-окно
-m 128m # оперативки будет 128 Мб - нам хватит

...

Booting from Hard Disk...
Boot failed: could not read the boot disk

Booting from Floppy...
Boot failed: could not read the boot disk

Booting from DVD/CD...
Boot failed: Could not read from CDROM (code 0003)
Booting from ROM...

...

Ни CDROM, ни диск не указан, поэтому и загрузки не происходит.

Исправляем это и создаем маленький по современным меркам жесткий диск на 256 mb.

Перед созданием образа стоит поговорить про стандарты таблиц разделов на диске. Сейчас их два:

  • MBR (Main Boot Record) — старый стандарт таблицы разделов (из 1983 года)
  • GPT (Guid Partition Table) — современный стандарт разделов, является частью стандарта EFI (Extensible Firmware Interface), разработанного Intel для замены BIOS

Подробнее про стандарты будет ссылка в конце статьи. Сейчас сделаем образ с MBR, а как-нибудь в другой серии с GPT, потому что с ним все немного сложнее

$ dd if=/dev/zero of=./mbr_hdd.img bs=1024k count=256
256+0 records in
256+0 records out
268435456 bytes transferred in 0.362737 secs (740027899 bytes/sec)

dd позволяет копировать файлы блоками заданного размера

в данном случае мы копируем нули из /dev/zero блоками по 1024 килобайт (1Mb) 256 раз

Читайте также:  Linux user add root permission

про dd и устройство файловой систему будем разбираться в следующих статьях

Если сразу попытаться подсунуть образ диска в qemu, то ничего не поменятся, так как на диске нет таблицы разделов, а только нули.

Создаем один загрузочный linux-раздел, например, с помощью fdisk (или cfdisk или parted)

$ fdisk -l ./mbr_hdd.img
Disk ./mbr_hdd.img: 256 MiB, 268435456 bytes, 524288 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000

Device Boot Start End Sectors Size Id Type
./mbr_hdd.img1 * 2048 524287 522240 255M 83 Linux

Теперь на диске есть таблица разделов, пробуем загружаться:

$ qemu-system-x86_64 -nographic -m 128m \ 
-boot c \ # загружаться с жесткого диска
-hda ./mbr_hdd.img # указываем образ первого жесткого диска

...

Booting from Hard Disk...

У нас есть жесткий диск, на нем есть таблица разделов, есть загрузочный раздел — пришло время поговорить про загрузчики.

Загрузчик (bootloader) #

Для linux по большому счету существует два загрузчика: LILO и GRUB.

LILO считается устаревшим, он не умеет работать с файловыми системами и для его конфигурации нужно каждый раз обновлять загрузочную запись на диске. Его рассматривать не будем.

GRUB умеет работать с разными файловыми системами, multiboot, grub-shell, консоль восстановления и много чего еще.

Конфиги GRUB, архивы с ядрами и initrd можно смотреть и править в каталоге (разделе) /boot .

Для начала нужно создать файловую систему в разделе нашего hdd.

Для реальных hdd разделы диска будут отображатся с номерами в /dev и в выводе команды lsblk выглядят примерно так:

# lsblk показывает блочные устройства в системе

$ lsblk

...
sda 8:0 0 10G 0 disk
└─sda1 8:1 0 10G 0 part /mnt
...

Видим что примонтирован диск sda с одним разделом sda1. Для нашего образа диска нам нужно как-то подключить файл образа как устройство.

Один из способов — команда losetup , с помощью нее можно подключать образы как блочные устройства.

$ sudo losetup \ 
--find \ # ищет свободный id для блочного устройства
--partscan \ # ищет на устройстве разделы, а нас как раз один раздел
./mbr_hdd.img

$ lsblk

...
loop0 7:0 0 256M 0 loop # видим наш диск с одним разделом
└─loop0p1 259:0 0 255M 0 loop
...

Теперь можем форматировать раздел в ext4:

$ sudo mkfs.ext4 /dev/loop0p1

mke2fs 1.42.13 (17-May-2015)
...
Writing superblocks and filesystem accounting information: done

Примонтируем раздел и посмотрим что на нем есть.

$ mkdir /mnt/hdd # создаем точку монтирования

$ mount /dev/loop0p1 /mnt/hdd # монтируем раздел

$ ls -l /mnt/hdd # внутри только lost+found

total 12
drwx------ 2 root root 12288 May 13 16:45 lost+found

Вот мы плавно и подошли к установке загрузчика — как говорил ранее, будем ставить grub.

Читайте также:  Установить новое устройство linux

При установке загрузчик будет записывать файлы непосредственно в файловую систему и изменять MBR на самом диске.

sudo grub-install \ 
--root-directory=/mnt/hdd \ # тут нужно указывать полный путь до примонтированного раздела
/dev/loop0 # тут указываем сам диск, а не раздел

Installing for i386-pc platform.
Installation finished. No error reported.

На диске появилась директория boot

$ ls -l /mnt/hdd/boot/grub/
total 12
drwxr-xr-x 2 root root 1024 May 13 16:50 fonts
-rw-r--r-- 1 root root 1024 May 13 16:50 grubenv
drwxr-xr-x 2 root root 9216 May 13 16:50 i386-pc
drwxr-xr-x 2 root root 1024 May 13 16:50 locale

# а команда file говорит так
$ file mbr_hdd.img
mbr_hdd.img: DOS/MBR boot sector

Загрузчик установлен, пробуем загружаться в QEMU

$ qemu-system-x86_64 -nographic -m 128m -boot c -hda ./mbr_hdd.img

...

Booting from Hard Disk...

GNU GRUB version 2.02

Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists possible
device or file completions.


grub>

Видим приветствие GRUB и grub shell.

В шелле можно посмотреть диски, информацию по разделам, поставить классные картинки на boot-screen, но то что нам пригодится сейчас — это возможность указать путь до образа ядра и ram-диска.

Загрузка ядра #

самый простой вариант получить образ ядра это скопировать его уже из готовой системы

ls -l /boot
total 31584
-rw-r--r-- 1 root root 217458 Apr 22 18:31 config-4.15.0-99-generic
drwxr-xr-x 5 root root 4096 May 11 15:58 grub
-rw-r--r-- 1 root root 19659681 May 11 15:57 initrd.img-4.15.0-99-generic
-rw------- 1 root root 4071696 Apr 22 18:31 System.map-4.15.0-99-generic
-rw------- 1 root root 8380056 Apr 22 18:32 vmlinuz-4.15.0-99-generic

$ cp /boot/vmlinuz-4.15.0-99-generic /mnt/hdd/boot

Запускаем QEMU и в консоли grub грузим ядро:

тут поменял -nographic на -curses, так лучше отображается в консоли, но этот ключ можно вообще убрать и работать в отдельном окне.

$ qemu-system-x86_64 -curses -m 128m -boot c -hda ./mbr_hdd.img

grub> ls /boot
grub/ vmlinuz-4.15.0-99-generic # вот ядро в директории /boot

grub> linux /boot/vmlinuz-4.15.0-99-generic # указываем какое ядро загружать
grub> boot # загружаемся

... # тут лог загрузки

# и в итоге получаем ошибку kernel panic

[ 2.159628] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

В этом режиме чтобы выйти из виртуалки нужно перейти в QEMU monitor по Ctrl-Alt-2 и выполнить команду quit . Подробнее про хоткеи в доке раздел “2.4 Keys in the graphical frontends”

После загрузки ядро должно иметь временную файловую систему и из нее запустить первый процесс в пользовательском пространстве с pid=1.

Читайте также:  Linux create zip with password

Временная файловая система (ram-диск) это и есть initrd и этот образ нужно будет собрать.

После загрузки ядра при запуске пользовательского пространства нужны хоть какие-то команды и есть такой набор инструментов — busybox.

busybox — это один бинарный файл, который содержит в себе минимальный набор программ для работы с системой. Добавим busybox в сборке ram-диска.

минимальный initrd #

mkdir initrd
cd initrd

# создаем основные директории
mkdir bin sys dev proc

# загружаем busybox и расставляем симлинки
wget https://busybox.net/downloads/binaries/1.30.0-i686/busybox -O bin/busybox

# обязательно нужно добавить права на выполнение для busybox
chmod +x bin/busybox

# симлинки для некоторых команд, остальные добавим позже
ln -s busybox bin/echo
ln -s busybox bin/ash
ln -s busybox bin/ls
ln -s busybox bin/cat

# копируем файлы устройств, про файлы в linux поговорим в других статьях
cp -a /dev/console ./dev
cp -a /dev/null ./dev
cp -a /dev/tty1 ./dev
cp -a /dev/tty2 ./dev

# создаем скрипт с которого начнется запуск пользовательского пространства

cat >> ./init EOF
#!/bin/ash
/bin/ash --login
EOF


# делаем скрипт исполняемым
chmod +x init

# из этой же директории пакуем initrd в cpio-архив
find . | cpio -o -H newc | gzip -9 > ../initrd.img

копируем полученный initrd.img в /boot на нашем hdd

cd .. && cp ./initrd.img /mnt/hdd/boot
$ qemu-system-x86_64 -curses -m 128m -boot c -hda ./mbr_hdd.img

grub> ls /boot
grub/ vmlinuz-4.15.0-99-generic initrd.img

grub> linux /boot/vmlinuz-4.15.0-99-generic # задаем ядро
grub> initrd /boot/initrd.img # задаем образ initrd

grub> boot # грузимся

...

/ # ls

bin dev init proc root sbin sys

Видим процесс загрузки ядра, после загрузки видим шелл, выполняем ls и видим содержимое диска — самый минимум грузится осталось немного автоматизировать процесс загрузки.

Настроим grub чтобы система стартовала без ручного ввода ядра и ram-диска.

Для этого достаточно в /boot/grub создать файл grub.cfg (для grub2 нужно именно расширение .cfg , а не .conf )

set default=0
set timeout=5

menuentry 'linux'
linux /boot/vmlinuz-4.15.0-99-generic
initrd /boot/initrd.img
>

если снова запустить qemu — увидим меню выбора системы

потом загрузку ядра и шелл

Итого #

В общих чертах разобрались с процессом загрузки и создали образ, в котором загружается ядро и первым процессом стартует shell (ash). Это только начало, дальше будем разбираться с файловой системой и с тем процесс должен быть запущен первым, да и вообще с процессами и не только.

Примеры #

Готовый образ из статьи можно взять тут:

Ссылки #

  • Про BIOS: https://ru.wikipedia.org/wiki/BIOS
  • Про стандарты таблиц разделов MBR, GPT https://losst.ru/chem-otlichaetsya-mbr-ot-gpt
  • Форматирование диска: https://losst.ru/formatirovanie-diska-v-linux
  • GRUB (wikipedia) https://ru.wikipedia.org/wiki/GNU_GRUB
  • GNU GRUB официальная дока https://www.gnu.org/software/grub/manual/grub/grub.html
  • IBM: Подробности процесса загрузки Linux https://www.ibm.com/developerworks/ru/library/l-linuxboot/

Источник

Оцените статью
Adblock
detector