使用具有 systemd.run firstrun.sh 脚本的 qemu-system-aarch64 运行 Raspberry 映像会卡住

使用具有 systemd.run firstrun.sh 脚本的 qemu-system-aarch64 运行 Raspberry 映像会卡住

我正在尝试使用 Qemu 模拟 Raspberry Pi (+OS)。我希望操作系统firstrun.sh在启动时执行脚本来配置各种内容。

这就是我启动 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

然而,当配置 Qemu/内核来执行 systemd 脚本时systemd.run=/boot/firstrun.sh,它会卡住并且无法继续启动。

最后打印的行是:

[  OK  ] Finished Command from Kernel Command Line.
[  OK  ] Reached target Command from Kernel Command Line

这是一个最小的首次运行脚本:

#!/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

要完全重现,请执行以下步骤:

# 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

如果我省略firstrun.sh脚本,启动过程就可以正常工作。

为什么执行firstrun.sh时引导进程不会继续?

答案1

通过设置systemd.run,您正在隐式设置systemd.unit=kernel-command-line.target(事实上,在您的命令行中您正在设置明确地,但这不是必要的)。设置systemd.unit有效地告诉 systemd,“这样做代替执行正常启动”。

这就是为什么事情看起来“卡住”了——你的第一次运行脚本正确执行,并且就 systemd 而言,不需要发生任何其他事情。

最简单的解决方案可能是以firstrun.sh以下方式结束脚本:

systemctl start --no-block multi-user.target

首次运行脚本完成后,这将继续正常启动。


给定一个firstrun.sh这样的脚本:

#!/bin/sh

set -x

echo "enable ssh"
systemctl enable --now ssh

echo "set root password"
echo 'root:secret' | chpasswd

echo "continue boot"
systemctl start --no-block multi-user.target

root当系统完成启动后,我可以在控制台上成功登录。主机端口 7777 上的 SSH 处于活动状态。


与您的问题无关,但您可以kpartx通过使用-P以下参数来避免使用losetup

loopdev="$(sudo losetup -fP --show)"
sudo mkdir -p "${mount_dir}"
sudo mount "${loopdev}p2" "${mount_dir}"
sudo mount "${loopdev}p1" "${mount_dir}/boot"

您可以避免使用循环设备并sudo完全通过使用guestfish来操作图像。我会做这样的事情来(a)创建原始图像的写时复制克隆,然后(b)配置它:

#!/bin/bash

BASEIMAGE=2023-05-03-raspios-bullseye-arm64-lite.img

# Download image
if ! [ -f "$BASEIMAGE" ]; then
  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
fi

echo "creating work image"
rm -f raspi-work.qcow2
qemu-img create -b "$BASEIMAGE" -F raw -f qcow2 raspi-work.qcow2 4G

echo "copying files"
guestfish -a raspi-work.qcow2 -m /dev/sda2:/ -m /dev/sda1:/boot <<EOF
copy-out /boot/kernel8.img .
copy-out /boot/bcm2710-rpi-3-b-plus.dtb .
copy-in firstrun.sh /boot/
EOF

# ...remainder of script here...

相关内容