qemu и эмуляция ARM

QEMU позволяет запускать программы, собранные для архитектур, отличающихся от архитектуры хост-машины, как известно. Чуть менее известно то, что с его помощью можно запустить эмулятор всей ЭВМ целиком и установить в него целую операционную систему иной архитектуры. И если с запуском x86_64 никаких проблем не возникнет (а на обычных PC по факту это просто виртуализация, а не эмуляция), то при попытке запустить эмулятор для ARM может обнаружиться, что систему туда так просто не установить: у эмулятора ARM нет ничего похожего на BIOS, который любезно организует старт установки с виртуального дисковода или флешки, а после установки – будет передавать загрузку в grub или его аналоги.

Попробуем организовать эмулятор для ARMv7 при помощи QEMU 4.20 и установим какой-нибудь Linux.

Для начала нам понадобится скачать так называемый netboot образ системы для armhf, состоящий из двух компонент: vmlinuz и initrd.gz. После ряда экспериментов выяснилось, что современные инсталляторы Ubuntu по умолчанию непригодны для этих целей, так что возьмем Debian Buster[1].

Подготовим файл образа “диска”, в который будем устанавливать систему:

qemu-img create -f qcow2 debian.qcow2 8G

В ряде инструкций рекомендуется подготовить сеть, подняв на хост-машине tap-интерфейс, что позволит иметь возможность достучаться с хост-машины в гостевую, но для упрощения ситуации запустим сеть в usermode – она работает достаточно быстро и для ряда задач её хватит.

Собираем файлы в одном месте и запускаем эмулятор со следующими параметрами:

qemu-system-arm -smp 4 -m 1024 -M virt \
   -kernel vmlinuz \
   -initrd initrd.gz \
   -append "root=/dev/ram" \
   -netdev user,id=n1
   -device virtio-net-device,netdev=n1 \
   -drive if=none,file=debian.img,format=qcow2,id=hd \
   -device virtio-blk-device,drive=hd \
   -no-reboot

Параметры:

  • smp – количество ядер;
  • m – объем памяти;
  • M – тип машины, virt – абстрактно-виртуальный ARM;
  • netdev – тип сети, user – самый простой вариант, не требующий настройки хост-машины;
  • device virtio-net-device – устройство “сетевой карты”, и выбирать следует именно это, а не упомянутое в различных инструкциях, т.к. иначе с огромной вероятностью вы наткнетесь на сообщение о том, что инсталлятор системы не обнаружил никаких сетевых устройств в системе;
  • drive if=none,file=debian.img,format=qcow2 – образ жесткого диска;
  • device virtio-blk-device – устройство “жесткого диска”, аналогично сети, этот вариант обнаруживается установщиком, многие другие – нет;
  • no-reboot – перезапуск системы приведет к остановке эмулятора.

Если запускаем qemu-system-arm в консоли без графического интерфейса, то дописываем “-nographic”.

Устанавливаем Debian как обычно. На количестве ядер не следует экономить, т.к. в процессе установки есть этапы, которые, по всей видимости, могут неплохо параллелиться, а однопоточная производительность эмулятора далека от производительности хост-машины: в среднем на установку системы уходило около часа на четырехъядерном Intel Xeon 3.5 GHz.

Ближе к концу установки инсталлятор ругнется на невозможность установки grub – так и должно быть в этом эмуляторе.

Далее, когда инсталлятор сообщит о завершении, выберите “Go back” и из главного меню установщика выберите пункт про вход в консоль. В консоли целевой диск, куда производилась установка, будет доступен по пути /target. Поскольку у эмулятора нет загрузчика, нам понадобится вытащить уже из установленной системы соответствующие ей vmlinuz и initrd.img. Для этого можно сделать chroot /target и, используя набор стандартных утилит – например, scp – откопировать файлы, находящиеся в /target/boot (а после chroot так просто в /boot) куда-нибудь вовне эмулятора. Если установленных утилит не хватает, то уже в chroot-е можно легко использовать apt и apt-get для установки недостающего. После копирования выходим из консоли и в меню инсталлятора выбираем пункт завершения установки. Когда установщик выполнит перезагрузку, эмулятор просто выключится согласно опции no-reboot.

Конечно, в качестве альтернативы можно вынуть vmlinuz и initrd из установленной системы и при помощи средств конвертации и распаковки qcow2 файлов – таких инструкций в интернете уйма. В этом случае прежде, чем что-то сделать с образом диска, не забывайте остановить эмулятор, чтобы не повредить образ.

Причина же, по которой изначально не удалось использовать современные образы Ubuntu, состоит в том, что в них после установки по малопонятной причине не генерируется файл initrd.img – в директории /target/boot есть битые симлинки на него, тогда как сам initrd отсутствует. [Update: Способ исправления был найден в комментариях на gist.github.com[2]]

Итак, после описанных действий у вас должен оказаться на руках образ debian.img с установленной ОС и файлы vmlinuz и initrd.img, взятые из этого же образа. Старые vmlinuz и initrd.gz с netboot-инсталлятором можно удалить – они больше не понадобятся. Теперь для запуска системы нужно переписать аргументы qemu-system-arm на следующие:

qemu-system-arm -smp 4 -m 1024 -M virt \
   -kernel vmlinuz \
   -initrd initrd.img \
   -append "root=/dev/vda2" \
   -netdev user,id=n1
   -device virtio-net-device,netdev=n1 \
   -drive if=none,file=debian.img,format=qcow2,id=hd \
   -device virtio-blk-device,drive=hd \
   -no-reboot

Вот, в общем-то, и всё.

Для того, чтобы зайти извне в такую гостевую машину по SSH, можно заменить -netdev user,id=n1 на -netdev user,hostfwd=tcp::10022-:22,id=n1, и тогда при подключении к порту 10022 на хост-машине соединение будет перенаправлено на 22 порт гостевой машины. Либо воспользоваться ssh-туннелем, подняв из гостевой машины подключение к удаленному ssh-серверу с дополнительным параметром -R 10022:localhost:22 – в этом случае порт 10022 на удаленном сервере будет перенаправлен на порт 22 гостевой машины.

Теперь можно пробовать собирать программы нативным компилятором нужной архитектуры, а не кросс-компиляцией. Ну или зачем там вы ещё запускали этот эмулятор.

This entry was posted in Софт and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>