首页 > 解决方案 > QEMU 串行标准输出在 archlinux 客户机上发散

问题描述

我正在尝试在 QEMU 中引导一些新下载的 ISO 的安装自动化。我创建了一个干净的 img 来安装并启动 QEMU,如下所示:

$ qemu-img create -f qcow2 out/main.img 15G
$ qemu-system-x86_64
  -m 8G \
  -serial stdio \
  -cdrom out/linux.iso \
  -drive file=out/main.img,if=virtio \
  -netdev user,id=net0 \
  -device e1000,netdev=net0

我可以看到 Arch 启动了。起初,显示器和终端是同步的,但在 GRUB 启动屏幕之后它们很快就不同了。

grub 上的 qemu 显示/终端 qemu 显示有活动会话,而终端没有

我不确定我缺少什么来让它工作。我看到有些人建议添加-append "root=/dev/sda console=ttyS0"到您的 QEMU 参数中,但是(据我所知)虽然它需要您从 ISO 中提取内核和 initram(这应该很容易安装和复制/粘贴正确的文件)但它也希望您已经安装了系统/dev/sda(这是我试图引导的)。

此时我不知道接下来要搜索什么,如何在当前终端中获取完整的终端会话,而不仅仅是在我的显示器中?

标签: serial-portqemuarchlinux

解决方案


在这种情况下,就像@Peter Maydell评论的那样;这不是 QEMU 问题。QEMU 正在做它应该做的事,但 Arch 不得不被告知使用串行控制台作为它的主要通信方式。

如何做到这一点的两个示例

通过控制台 bash
pipe_dir="$(mktemp -d)"
mkfifo "${pipe_dir}/pipe.in" "${pipe_dir}/pipe.out"
function cleanup {
    rm -rfv "${pipe_dir}"
}
trap cleanup EXIT

qemu-system-x86_64 \
  -m 8G \
  -display none \
  -serial stdio \
  -drive file=./out/linux.iso,index=0,media=cdrom \
  -drive file=./out/main.img,if=virtio &

sleep 2s
printf "\t" > "${pipe_dir}/pipe.in"
sleep 2s
printf " console=ttyS0,115200" > "${pipe_dir}/pipe.in"
sleep 2s
echo  > "${pipe_dir}/pipe.in"

# Whatever other interactions you want go here...

wait
期望通过控制台
set timeout -1
spawn qemu-system-x86_64 \
  -m 8G \
  -display none \
  -serial stdio \
  -drive file=./out/linux.iso,index=0,media=cdrom \
  -drive file=./out/main.img,if=virtio

sleep 1
send \t
sleep 1
send " console=ttyS0,115200"
sleep 1
send \n

理论上这应该没问题,但实际上我仍然很难与控制台交互并发送字符以正确登录。我确信我的用户错误可能比没有更多。

一个更好的解决方案(再次与 Arch 而不是 QEMU 的上下文相关)是使用包含我的 SSH 公钥的 cloud-init 脚本。与 VM 的交互稳定、可靠且易于重现。

使用 cloud-init/ssh 进行 bash
$ touch ./out/meta-data
$ cat > ./out/user-data <<EOF
#cloud-config
users:
  - name: root
    ssh_authorized_keys:
        - $(cat ${HOME}/.ssh/id_ed25519.pub)
EOF
$ xorriso -as genisoimage -output ./out/cloud-init.iso \
    -volid CIDATA -joliet -rock ./out/meta-data ./out/user-data
$ qemu-system-x86_64 \
    -m 8G \
    -drive file=./out/linux.iso,index=0,media=cdrom \
    -drive file=./out/cloud-init.iso,index=1,media=cdrom \
    -drive file=./out/main.img,if=virtio \
    -net user,hostfwd=tcp::10022-:22 \
    -net nic &

$ function qemu-ssh {
    ssh -q -o ConnectTimeout=5 -o StrictHostKeyChecking=no -o "UserKnownHostsFile /dev/null" -p 10022 root@localhost ${@}
  }

$ printf 'Waiting for SSH to go live (this will take a while)...'
$ until qemu-ssh exit; do
    printf '.'
  done

# This convenience function starts an interactive
# session when supplied with no additional arguments
# but your automation can go here
$ qemu-ssh 

推荐阅读