В данной статье мы соберем Linux Kernel и запустим на qemu с busybox.
Для начала скачайте Busybox:
https://busybox.net/downloads/
Нужный вам Linux Kernel:
https://www.kernel.org/pub/linux/kernel/
И qemu:
NOTE Busybox:
Взято с http://samag.ru/archive/article/1908
Несмотря на безудержный рост графических оболочек и «дружелюбных» интерфейсов, представить себе UNIX без командной строки и основных утилит в наши дни невозможно. Многочисленные интерпретаторы и базовые системные утилиты не стоят на месте, растут и развиваются, что неизбежно ведет и к увеличению их объема. В то же время существуют сферы деятельности, в которых компактность любых приложений по очевидным причинам очень важна, например, во встраиваемых устройствах. Вместе с тем во многих случаях не требуется значительная часть той функциональности, которая присуща базовым утилитам «общего назначения».
Для решения этих проблем еще в середине 90-х Брюсом Перенсом (Bruce Perens) был создан пакет BusyBox. Сейчас проект позиционируется как «швейцарский нож для встраиваемых Linux-систем» и в первую очередь ориентирован на использование в небольших дистрибутивах GNU/Linux. Распространяется под второй версией лицензии GNU GPL.
BusyBox представляет собой единственный исполняемый файл, при запуске которого загружается полноценный командный интерфейс. Как гласит официальная документация BusyBox, для формирования минимальной версии GNU/Linux к этому достаточно добавить лишь ядро ОС и каталоги /etc, /dev.
Одна из главных целей, которую преследуют разработчики BusyBox, – оптимизированность и компактность кода – расчет на ограниченность памяти. Это не только вновь говорит о плюсах его использования во встраиваемых устройствах, но и хорошо сочетается с другим подходом в духе UNIX way: высокий уровень настраиваемости (в бинарный файл BusyBox можно включить только необходимые компоненты).
Еще на стадии компиляции (а точнее, до самого процесса сборки) можно выбрать только те базовые утилиты, которые нужны. Реализовано это в стиле настройки ядра Linux. Вместо более распространенного среди собираемых с automake приложений способа в виде скрипта «configure» для предварительной конфигурации BusyBox нужно выполнить одну из следующих команд:
$ make config
$ make menuconfig
$ make defconfig
Аргумент «config» инициирует запуск «вопросника» со списком доступных опций и базовых утилит, предлагающего проставлять «Y» или «N» на месте нужных и ненужных возможностей соответственно.
Аргумент «menuconfig» вызывает более удобную конфигурацию в виде меню с интерфейсом на базе curses.
Аргумент «defconfig» автоматически включает все доступные опции, подготавливая к сборке BusyBox «общего назначения».
Так же, как и в случае с ядром Linux, после настройки создается конфигурационный файл .config, к которому можно затем всегда возвращаться командой:
$ make oldconfig
Это актуально при переходе на более новую версию BusyBox со старой конфигурацией (чтобы при настройке работать только с появившимися в очередном релизе опциями).
По умолчанию, если до вызова «make menuconfig» не существовал файл .config, make автоматически предварительно запускается с аргументом «defconfig». Таким образом, пользователю останется только отключить ненужные возможности. Предусмотрен и обратный вариант: запуск make с «allnoconfig» отключает все опции, чтобы после этого можно было выбрать только то, что нужно.
Далее все традиционно:
$ make
$ sudo make install
Помимо альтернативного набора coreutils (ls, cat, mv, cp, rm, chmod, df, ln, date, wc, nice, test…) в состав BusyBox входит и множество других программ.
Для работы с архивами есть такие утилиты, как tar, gzip, bzip2, ar, zip, rpm, dpkg. Для обработки содержимого файлов есть как awk, sed, patch, так и текстовые редакторы ed и vi.
Широко представлены сетевые средства: и клиентские, и серверные. Среди демонов выделю httpd, dnsd, telnetd, inetd, udhcpd. Для FTP есть ftpget, ftpput и клиент tftp. Кроме того, присутствует и собственная версия GNU wget. Из прочих стандартных утилит: ifconfig, route, traceroute, ping/ping6, netstat, nslookup, arp и arping.
Устанавливаем busybox:
make defconfig
make menuconfig
Далее в меню ставим галочку в:
-> Busybox Settings
-> Build Options
[ ] Build BusyBox as a static binary (no shared libs)
сохраняем и выходим.
Далее
make
make CONFIG_PREFIX=./../busybox_rootfs install
CONFIG_PREFIX=./../busybox_rootfs — указывает на папочку, куда busybox сложит выходные файлы.
NOTE initramfs:
Initrd (сокращение от англ. Initial RAM Disk, диск в оперативной памяти для начальной инициализации) — временная файловая система, используемая ядром Linux при начальной загрузке. Initrd обычно используется для начальной инициализации перед монтированием «настоящих» файловых систем.
Начиная с версии ядра 2.6 пришли к понятию initramfs. Это, обычно сжатый cpio архив, в котором располагается мини-система busybox, которая выполняет ту же роль, что и initrd.
Можно использовать ее для тестирования какой либо функциональности встраиваемой системы — когда вы просто хотите поместить всю систему в память, чтоб она быстро работала, при этом вам не важно, сохранятся ли ваши изменения после перезагрузки.
Содержимое initramfs делается путем создания cpio-архива.
Все файлы, инструменты, библиотеки, настройки конфигурации (если они применимы), и т.д. помещаются в cpio-архив. Этот архив затем сжимается с использованием утилиты gzip и сохраняется в том же месте, что и ядро Linux. Далее, загрузчик передаст его ядру Linux во время загрузки, чтобы ядро знало о том, что требуется initramfs.
При его обнаружении, ядро Linux создаст файловую систему tmpfs, извлечет на нее содержимое архива и затем запустит сценарий init, расположенный в корневом каталоге файловой системы tmpfs.
Теперь создадим initramfs с нашим построенным busybox:
mkdir rootfs
cd rootfs
mkdir bin
mkdir dev
mkdir etc
mkdir home
mkdir mnt
mkdir proc
mkdir sys
mkdir usr
cd ./dev
sudo mknod sda b 8 0
sudo mknod console c 5 1
Note: node можно не создавать через mknod, а скопировать из основной ОС.
Далее копируем все из папки busybox_rootfs в папку rootfs. Таким образом, в нашем initrd появятся утилиты Linux, которые реализует busybox.
Создаем в корне rootfs файл init :
touch init
И пишем в него:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo -e "\nBadEmbed Generation\n"
exec /bin/sh
Делаем его исполняемым:
chmod +x init
Создаем сам initramfs:
find . -print0 | cpio --null -ov --format=newc > rootfs.cpio
gzip ./rootfs.cpio
Собираем ядро
make x86_64_defconfig
make kvmconfig
make -j2
Сжатый образ ядра — /arch/x86_64/boot/bzImage .
Копируем bzImage и rootfs.cpio.gz в отдельную директорию, заходим в нее и
Запускаем qemu
qemu-system-x86_64 \
-kernel ./bzImage \
-initrd ./initramfs-busybox-x86.cpio.gz \
-nographic -append "console=ttyS0"
Дополнение
Initrd встроенный в ядро
Кроме того, вы можете скомпилировать initrd вместе с ядром. Для этого надо при конфигурировании ядра указать путь к rootfs (см. ниже):
make menuconfig
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
(/path_to_rootfs/rootfs)
А в /path_to_rootfs/rootfs у вас должен находится сам rootfs ( /bin, /dev /dev/sda /dev/console и т.д. — см. описание выше). Не забываем создать и init скрипт.
Тогда после компиляции ядра, qemu можно запускать, не указывая initrd:
qemu-system-x86_64 \
-kernel ./bzImage \
-nographic -append "console=ttyS0"
Переключение с Initrd на rootfs на диске
Сначала создадим диск, на который поместим rootfs:
dd if=/dev/zero of=hdd bs=1M count=$((32))
mkfs.ext3 hdd
sudo mount ./hdd /mnt/
cd /mnt
Создаем rootfs тут (в /mnt), также как и было описано выше ( /bin, /dev /dev/sda /dev/console и т.д. — см. описание выше). Не забываем создать и init скрипт.
Далее
cd /
sudo umount /mnt
Теперь у нас на образе диска hdd находится rootfs.
Для запуска qemu c диском используем сл. команду:
qemu-system-x86_64 \
-kernel bzImage \
-initrd rootfs.cpio.gz \
-hda ./hdd \
-nographic -append "console=ttyS0"
Когда ядро загрузится с initrd, для переключения к rootfs на диске, выполним следующие команды:
mount /dev/sda /mnt/root
exec switch_root /mnt/root /bin/sh
Загрузка без Initrd
Т.к. у на rootfs есть уже на диске, то грузиться с initrd не обязательно. Для того чтобы сразу грузить rootfs с диска, надо ядру (в загрузчике) передать параметр root.
В qemu это делается через append:
qemu-system-x86_64 \
-kernel bzImage \
-hda ./hdd
-append root=/dev/sda1
Note: для компиляции под 32-bit intel используем:
- Busybox — в build options выставить в CFLAGS флаги -m32 -march=i386, в LDFLAGS флаг -m32
- Linux kernel — вместо x86_64_defconfig используем i386_defconfig
- qemu — для запуска используем команду qemu-system-i386
Смотрим:
http://mgalgs.github.io/2012/03/23/how-to-build-a-custom-linux-kernel-for-qemu.html
http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html
https://wiki.gentoo.org/wiki/Custom_Initramfs
https://badembed.ru/qemu-busybox-linux-kernel-chast-2-dobavlenie-grub/