вторник, 9 июля 2013 г.

PhantomEx: Готовим почву (создание образа HDD и установка загрузчика GRUB2)

Начинать мы будем с того, что определимся откуда будет грузится наше ядро. В большинстве руководств по написанию ОС, блуждающих в сети этот вопрос решается довольно просто: образ ядра вместе с загрузчиком жестко "вшивается" в образ дискеты, которая затем устанавливается в виртуальную машину. 
Кроме того, многие HOW-TO обладают тем недостатком, что начинаются с описания создания загрузчика для самодельной ОС.

Кроме образовательного эффекта - изучения принципов работы BIOS и порядка загрузки ОС такой подход не имеет других достоинств. Кроме того, ваша ОС будет не приспособлена для совместного проживания с другими ОС (одна ОС известной фирмы тоже этим грешит ;) ).
Поэтому сделаем всё основательно - создадим образ жесткого диска, разобьем его на разделы и установим на него загрузчик GRUB2. Так чтобы наше ядро с детства училось жить в разделе жесткого диска и грузится используя спецификацию Multiboot или Multiboot2.
Что для этого понадобится?


  1. Эмулятор QEMU установленный на вашей Linux-машине.
  2. Загрузочный CD какого-нибудь 32-разрядного дистрибутива Linux. Я использовал установочный CD Arch Linux от 1 июня 2013.
Итак, в командной строке переходим в каталог где будет хранится образ HDD

$ cd ~/myOSkernel/hdd/

Далее выполняем

$ qemu-img create -f raw hard_disk.img 2G

Эта команда создаст raw-образ (не сжатый) жесткого диска объемом 2Гб, чего нам вполне достаточно для первоначальных экспериментов.

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

ВНИМАНИЕ! Все нижеследующие команды выполняются от имени суперпользователя. Будьте внимательны!

Прежде всего подготовим драйвер блочного устройства к работе с нашим образом.

# modprobe -r loop
# modprobe loop max_part=15
# losetup -f hard_disk.img


Тем самым мы связали наш образ с блочным устройством loop, посмотрим какое имя было ему присвоено

# losetup
NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0         0      0         0  0 /home/maisvendoo/phantom/hdd/hard_disk.img


Отлично, устройство присутствует в системе с именем loop0. Далее выполним

# parted /dev/loop0
GNU Parted 3.1
Используется /dev/loop0
Добро пожаловать в GNU Parted! Наберите 'help' для просмотра списка команд.
(parted)


Утилита parted необходима нам для создания на диске таблицы разделов. В появившемся приглашении введем команду print

(parted) print                                                           
Ошибка: /dev/loop0: метка диска не определена
Модель: Loopback device (loopback)                                       
Диск /dev/loop0: 2147MB
Размер сектора (логич./физич.): 512B/512B
Таблица разделов: unknown
Disk Flags:
(parted)


Таблица разделов - unknown, диск у нас свеженький и таблицы разделов на нем нет. Исправляем это командой mklabel msdos

(parted) mklabel msdos
(parted) print                                                   
Модель: Loopback device (loopback)
Диск /dev/loop0: 2147MB
Размер сектора (логич./физич.): 512B/512B
Таблица разделов: msdos
Disk Flags:

Номер  Начало  Конец  Размер  Тип  Файловая система  Флаги

(parted)


Отлично, теперь у нас есть таблица разделов. Дальше можно выполнить разбиение диска на разделы в том же parted, однако для меня он таки непривычен, поэтому я выхожу из этой утилиты набрав quit, и запускаю более привычный мне fdisk

# fdisk /dev/loop0

Далее создадим раздел дав комаду n. Нам последовательно предложат:

  • задать тип раздела - выбираем p (первичный раздел)
  • указать место где будет начинаться раздел в секторах. Здесь укажем число 4096 секторов, так как необходимо отступить 2 мегабайта от начала дистка, для последующей установки туда загрузчика.
  • указать размер раздела - тут жмем просто Enter, чтобы fdisk разметил весь диск до конца.
Теперь запишем изменения на диск введя команду w.

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

# ls /dev/loop*

Среди всего списка вы увидите такое устройство - /dev/loop0p1 - это и есть созданный нами раздел. Теперь создадим на нем файловую систему ext2

# mkfs.ext2 /dev/loop0p1

Теперь мы можем смонтировать этот раздел

# mount /dev/loop0p1 /mnt

Посмотрим что у нас вышло


Великолепно - мы сделали раздел на виртуальном жестком диске. Для установки GRUB2 и хранения нашего ядра создадим на нем каталок boot

# mkdir /mnt/boot

Если у вас 32-разрядная версия Linux с загрузчиком GRUB2 то можно сразу установить его командой

# grub-install --root-directory=/mnt  /dev/loop0

У меня Arch Linux 64-разрядный, поэтому мне пришлось загрузится с установочного диска, выбрав 32-битный вариант установки. Отмонтируем блочное устройство и удалим его

# umount /mnt
# losetup -d /dev/loop0

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

$ qemu-system-x86_64 ~/myOSkernel/hdd/hard_disk.img -cdrom ~/install/archlinux/archlinux-setup.iso -boot d -enable-kvm

Здесь указываем путь к образу HDD; в ключе -cdrom указываем путь к образу загрузочного CD; в ключе -boot ставим директиву d, сообщающую эмулятору что надо грузится именно с CD; ключом -enable-kvm разрешаем использование аппаратной виртуализации (для ускорения работы виртуальной машины). Видим такой экран

с вариантами установки. Выбираем 32-разрядный вариант. Грузимся....

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

# mount /dev/sda1 /mnt

Просматриваем содержимое раздела, убеждаемся что созданная нами папка boot на месте.

# grub-install --root-directory=/mnt  /dev/sda

где /dev/sda - имя нашего "винта" в виртуальной системе. Всё! Отмонтируем диск и выключаем виртуальную машину

# umount /mnt
# systemctl poweroff

И запускаем её заново, только теперь используя команду

$ qemu-system-x86_64 ~/myOSkernel/hdd/hard_disk.img -enable-kvm

После загрузки мы увидим следующую картину


Что это? Всё в порядке - это приглашение командной строки GRUB2. Он установлен на диск и работоспособен, только вот на этом HDD у нас ничего кроме загрузчика пока что нет, и GRUB2 просит дать команды для загрузки какой-либо ОС. Чуть позже, когда у нас будет ядро, мы рассмотрим эти команды, и сконфигурируем меню GRUB2 для загрузки нашей "игрушечной" операционной системы.