How to emulate Raspberry Pi Raspbian with QEMU?
I’m trying to emulate a Raspberry Pi with the Raspian OS using QEMU. I’ve tried several approaches described on the internet but without any success. I figured out that I need to patch a Linux Kernel fitting the desired OS. In my case I chose Rasbian Lite with Kernel 4.4:
wget https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2016-05-31/2016-05-27-raspbian-jessie-lite.zip unzip 2016-05-27-raspbian-jessie-lite.zip rm 2016-05-27-raspbian-jessie-lite.zip
wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.4.16.tar.gz tar -xzf linux-4.4.16.tar.gz rm linux-4.4.16.tar.gz
export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabi- cd linux-4.4.16 make vexpress_defconfig make all cd ..
Now I can copy the boot image, that is a compressed kernel image that auto-extracts in RAM, to my workspace:
cp linux-4.4.16/arch/arm/boot/zImage zImage
qemu-system-arm -kernel zImage -M vexpress-a9 -m 1024 -cpu cortex-a9 -no-reboot -serial stdio -hda 016-05-27-raspbian-jessie-lite.img -append "root=/dev/sda2 rootfstype=ext4"
But all I see is a black filled QEMU-window. 🙁 I think that the problem is to get the right Kernel. Copying some of the Kernels from the Internet never led to success because they are not fit for the OS. How can I build/patch a Kernel fitting the OS (without downloading an existing one) and how to run QEMU properly? Thanks in advance
Alex
2nd approach
qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2" -hda 2016-05-27-raspbian-jessie-lite.img
This brings me the following output: And it makes sense to me because the Kernel is 3.10.25 and older than Raspbian Jessie with Kernel 4.4.16. With the qemu-kernel from https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/kernel-qemu-4.4.12-jessie
qemu-system-arm -kernel kernel-qemu-4.4.12-jessie -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 rootfstype=ext4 rw" -hda 2016-05-27-raspbian-jessie-lite.img
I got this similar result: A new try with a new kernel-qemu 4.4.16:
- Copy build-kernel-qemu from https://github.com/dhruvvyas90/qemu-rpi-kernel/tree/master/tools and add the following line to checkout the version for Kernel 4.4.16:
git checkout b05965f284db3e086022f4e318e46cb5bffb1376
qemu-system-arm -kernel kernel-qemu -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 rootfstype=ext4 rw" -hda 2016-05-27-raspbian-jessie-lite.img
Получаем виртуальный raspberry pi с помощью QEMU. Часть 2
В прошлой части был запущен эмулятор с консольным дистрибутивом. В этой части я расскажу, как запускал эмулятор с рабочим столом.
Материала накопилось на целый туториал, потому что QEMU версии 6.2 отказался работать. Изучив материал «Реализации машины в QEMU» я принялся собирать последнюю версию эмулятора из исходных кодов. Это оказалось на удивление легко и быстро. Все действия я провожу на Ubuntu 22.
Действия будут производиться в двух консолях, в консоли Ubuntu и в консоли виртуальной машины. Если не указано иное, действие производится в консоли Ubuntu.
Работать будем в папке myQEMU. Обозначим полный путь к ней через переменную MyBaseDir
mkdir myQEMU MyBaseDir="$PWD/$_" cd "$MyBaseDir"
Сборка QEMU из исходных кодов
Устанавливаем зависимости. Затем скачиваем исходный код, конфигурируем, собираем
git clone https://github.com/qemu/qemu.git mkdir build_QEMU && cd $_ ../qemu/configure --target-list=aarch64-softmmu make -j16 cd "$MyBaseDir"
Проверим как собралось.
«$MyBaseDir»/build_QEMU/qemu-system-aarch64 -M ?
Видим в длинном списке заветную строчку, радуемся
raspi3b Raspberry Pi 3B (revision 1.2)
В моём случае собралась версия с таким номером
QEMU emulator version 8.0.50 (v8.0.0-918-g6972ef1440)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
Использование QEMU
Скачаем последнюю доступную на текущий момент версию Raspberry Pi OS. Скачивать будем через торрент, чтобы не грузить лишний раз сеть производителя. Собственно для этих целей я использую утилиту aria2.
export IMAGE_FILE="2023-05-03-raspios-bullseye-arm64.img" aria2c --seed-time=0 "https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2023-05-03/$IMAGE_FILE.xz.torrent"
После того как скачали сжатый образ, распакуем его и удалим сжатый (чтобы места не занимал).
Так как нам надо переопределить опции запуска ядра, нужно вытащить его из образа дебиана. Для этого примонтируем в нашу систему образ дебиана
TMP=$(mktemp -d) LOOP=$(sudo losetup --show -fP "$") echo "Script use folder "$TMP sudo mount $p2 $TMP sudo mount $p1 $TMP/boot/
Далее назначим логин pi и пароль password
sudo bash -c "cat $TMP/boot/userconf pi:\\\$6\\\$jc2UtTCtwjTQ1Ytt\\\$W62IeROzUmoYrBRDD5uhHCRj/LQKA9YDoX1qEJAmT7A9c./micgLlexIaIRRgIZR32krnv1wYbbW046lYwgpO0 EOF"
Возможно старожилы помнят, что у расбиана был дефолтный логин-пароль. Так вот, начиная с версии 11, дефолтного нет. Совсем нет.
Далее необходимо сделать размер нашего образа кратным степени двойки. Тут на ваше усмотрение, мне достаточно 8 GiB. В притык делать не стоит, а то не сможете программы устанавливать и так далее.
"$MyBaseDir"/build_QEMU/qemu-img resize -f raw "$IMAGE_FILE" 8G
Далее произведем запуск эмулятора QEMU.
"$MyBaseDir"/build_QEMU/qemu-system-aarch64 \ -m 1024 \ -M raspi3b \ -kernel $TMP/boot/kernel8.img \ -dtb "$TMP/boot/bcm2710-rpi-3-b-plus.dtb" \ -drive file="$IMAGE_FILE",if=sd,format=raw \ -append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4" \ -device usb-net,netdev=net0 \ -netdev user,id=net0,hostfwd=tcp::5555-:22 \ -device usb-mouse -device usb-tablet -device usb-kbd
Опции -device usb-mouse и -device usb-kbd отвечают за проброс мышки и клавиатуры соответственно. По поводу мышки. Без важной опции -device usb-tablet у меня работала правая кнопка мыши, но не работало перемещение курсора по рабочему столу.
Кстати конфигурации QEMU для различных архитектур можно посмотреть в buildroot/board/qemu/ в файлах readme.txt или в питоновском скрипте runqemu от Yocto (пример).
Консоль виртуальной машины находится здесь (serial0). Далее будем вводить команды в неё.
Включим ssh. Теперь можно будет обращаться к нашей виртуальной машине по ssh.
sudo systemctl start ssh
sudo raspi-config nonint do_ssh 1
А если на конце написать 0 — то это stop.
Далее с помощью resize2fs займём всё свободное место диска (в нашем случае 8 GiB), для этого воспользуемся всем известным стандартным скриптом Raspberry Pi OS по имени raspi-config. Чтобы не копаться вручную в меню, вот так можно вызвать этот скрипт в неинтерактивном виде
sudo raspi-config nonint do_expand_rootfs
Работа в консоли виртуальной машины закончена. В рамках данной статьи к этой консоли обращаться более не будем. Сейчас необходимо вернуться в консоль Ubuntu и действия выполнять в ней.
Перейдём в нашу рабочую папку.
Подготовим авторизацию по ключу к нашей машине, чтобы не входить по логин-пароль каждый раз. Ключи (закрытый и публичный) будем хранить в своей папке
Генерация ssh key
(Если ключ уже существует по данному пути, этот код его перезапишет)
ssh-keygen -f ssh_key/my_ssh_key -N "" -C myKeyForQEMU /dev/null 2>&1
Поместим ключ на виртуальную машину (тут единожды придётся ввести пароль)
ssh-copy-id -p 5555 -i ssh_key/my_ssh_key.pub pi@127.0.0.1
Кстати, вместо явного указания IP адреса 127.0.0.1 во всех местах можно писать слово localhost.
Зададим права на публичный ключ (иначе Ubuntu не даст им пользоваться)
chmod 600 ssh_key/my_ssh_key.pub
Подключимся к нашей виртуальной машине.
ssh pi@127.0.0.1 -p 5555 -i ssh_key/my_ssh_key
Когда вы закончите настраивать системы, выключите виртуальную машину
Отмонтируйте образ от вашей хост-машины
sudo umount -f $TMP/boot/ sudo umount -f $TMP
и перенесите файл IMAGE_FILE на карту памяти реального одноплатника. И все ваши действия окажутся там уже выполненными.
Кстати, если вы хотите поместить весь процесс настройки дебиана в один мега-скрипт, то процедуру отмонтирования лучше сделать так.
Заметка «Нативная компиляция внутри эмулятора» тут и там.