Estou tentando emular um Raspberry Pi (+OS) com o Qemu. Eu gostaria que o sistema operacional executasse um firstrun.sh
script na inicialização para configurar várias coisas.
É assim que começo o qemu:
qemu-system-aarch64 \
-M raspi3b \
-cpu cortex-a53 \
-m 1G \
-kernel kernel8.img \
-dtb bcm2710-rpi-3-b-plus.dtb \
-drive "file=2023-05-03-raspios-bullseye-arm64-lite.img,format=raw,index=0,media=disk" \
-append "rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2 rootdelay=1 systemd.run=/boot/firstrun.sh systemd.run_success_action=none debug systemd.unit=kernel-command-line.target" \
-usb \
-device usb-mouse \
-device usb-kbd \
-device usb-net,netdev=net0 \
-nographic \
-serial mon:stdio \
-netdev user,id=net0,hostfwd=tcp::7777-:22
No entanto, ao configurar o Qemu/o Kernel para executar um script systemd systemd.run=/boot/firstrun.sh
, ele trava e não continua inicializando.
As últimas linhas que são impressas são:
[ OK ] Finished Command from Kernel Command Line.
[ OK ] Reached target Command from Kernel Command Line
Este é um script de primeira execução mínimo:
#!/bin/bash
set +e
echo "This is the firstrun script"
rm -f /boot/firstrun.sh
sed -i 's| systemd.run.*||g' /boot/cmdline.txt
exit 0
Para reproduzir completamente, estas são as etapas:
# Download image
wget https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2023-05-03/2023-05-03-raspios-bullseye-arm64-lite.img.xz
xz --extract 2023-05-03-raspios-bullseye-arm64-lite.img.xz
# Setup image - extract kernel.img and copy firstrun script
mount_dir=/mnt/raspberrypi
free_loopdev="$(sudo losetup -f)"
sudo kpartx -a -v 2023-05-03-raspios-bullseye-arm64-lite.img
loop_mapper=/dev/mapper/$(basename "${free_loopdev}")
sudo mkdir -p "${mount_dir}"
sudo mount "${loop_mapper}p2" "${mount_dir}"
sudo mount "${loop_mapper}p1" "${mount_dir}/boot"
cp "${mount_dir}/boot/kernel8.img" .
cp "${mount_dir}/boot/bcm2710-rpi-3-b-plus.dtb" .
sudo cp firstrun.sh "${mount_dir}/boot"
# Run Qemu with Image
cmdline="rw earlyprintk loglevel=8 console=ttyAMA0,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk0p2 rootdelay=1 systemd.run=/boot/firstrun.sh systemd.run_success_action=none debug systemd.unit=kernel-command-line.target"
qemu-img resize -f raw "2023-05-03-raspios-bullseye-arm64-lite.img" 4G
qemu-system-aarch64 \
-M raspi3b \
-cpu cortex-a53 \
-m 1G \
-kernel kernel8.img \
-dtb bcm2710-rpi-3-b-plus.dtb \
-drive "file=2023-05-03-raspios-bullseye-arm64-lite.img,format=raw,index=0,media=disk" \
-append "${cmdline}" \
-usb \
-device usb-mouse \
-device usb-kbd \
-device usb-net,netdev=net0 \
-nographic \
-serial mon:stdio \
-netdev user,id=net0,hostfwd=tcp::7777-:22
Se eu omitir o firstrun.sh
script, o processo de inicialização funcionará bem.
Por que o processo de inicialização não continua ao executar firstrun.sh?
Ao definir
systemd.run
, você está definindo implicitamentesystemd.unit=kernel-command-line.target
(na verdade, em sua linha de comando, você está definindo explicitamente , mas isso não é necessário). A configuraçãosystemd.unit
está efetivamente dizendo ao systemd, "faça isso em vez de executar uma inicialização normal".É por isso que as coisas parecem "travar" - seu script de primeira execução é executado corretamente e, no que diz respeito ao systemd, nada mais precisa acontecer.
A solução mais simples é provavelmente terminar seu
firstrun.sh
script com:Isso continuará com uma inicialização regular após a conclusão do script de primeira execução.
Dado um
firstrun.sh
script como este:Posso efetuar login com êxito como
root
no console quando o sistema terminar de inicializar. Ssh está ativo na porta do host 7777.Não relacionado à sua pergunta, mas você pode evitar o uso
kpartx
usando o-P
argumento paralosetup
:E você pode evitar mexer com dispositivos de loop e
sudo
completamente usandoguestfish
para manipular a imagem. Eu faria algo assim para (a) criar um clone copy-on-write da imagem original e, em seguida, (b) configurá-lo: