跳转至内容

QEMU

来自 ArchWiki

根据 QEMU 简介页面

QEMU 是一个通用且开源的机器模拟器和虚拟化程序。
当用作机器模拟器时,QEMU 可以运行为特定机器(例如 ARM 板)编写的操作系统和程序,在不同的机器(例如您的 x86 PC)上运行。通过使用动态翻译,它实现了非常好的性能。

QEMU 可以使用 Xen 或 KVM 等其他虚拟机监控程序来利用 CPU 扩展(HVM)进行虚拟化。当用作虚拟化程序时,QEMU 通过在主机 CPU 上直接执行客户机代码来实现接近原生的性能。

安装

安装 qemu-full 包(或者 qemu-base 用于无 GUI 的版本,以及 qemu-desktop 用于默认仅支持 x86_64 仿真的版本),以及以下可选包以满足您的需求

或者,qemu-user-static 是一个用户模式和静态变体。

QEMU 变体

QEMU 以几种适合不同用例的变体提供。

作为第一个分类,QEMU 提供全系统仿真和用户模式仿真两种模式。

全系统仿真
在此模式下,QEMU 模拟一个完整的系统,包括一个或多个处理器和各种外围设备。它更准确但速度较慢,并且不需要模拟的操作系统是 Linux。
用于全系统仿真的 QEMU 命令的名称为 qemu-system-target_architecture,例如 qemu-system-x86_64 用于模拟 x86_64 CPU,qemu-system-i386 用于 Intel 32 位 x86 CPU,qemu-system-arm 用于 ARM (32 位)qemu-system-aarch64 用于 ARM64,依此类推。
如果目标架构与主机 CPU 匹配,此模式仍可受益于 KVM 或 Xen 等虚拟机监控程序的显著加速。
用户模式仿真
在此模式下,QEMU 能够通过利用主机系统资源来调用为(潜在)不同架构编译的 Linux 可执行文件。可能存在兼容性问题,例如某些功能可能未实现,动态链接的可执行文件无法立即运行(参见 #Chrooting into arm/arm64 environment from x86_64 来解决此问题),并且仅支持 Linux(尽管 Wine 可以用于运行 Windows 可执行文件)。
用于用户模式仿真的 QEMU 命令的名称为 qemu-target_architecture,例如 qemu-x86_64 用于模拟 64 位 CPU。

QEMU 提供动态链接和静态链接的变体。

动态链接(默认)
qemu-* 命令依赖于主机操作系统库,因此可执行文件更小。
静态链接
qemu-* 命令可以复制到任何相同架构的 Linux 系统。

在 Arch Linux 的情况下,全系统仿真提供为

非无头(默认)
此变体启用了需要额外依赖项(如 SDL 或 GTK)的 GUI 功能。
Headless
这是一个更精简的变体,不需要 GUI(例如,适用于服务器)。

请注意,无头和非无头版本安装的命令名称相同(例如 qemu-system-x86_64),因此不能同时安装两者。

Arch Linux 中可用软件包的详细信息

  • qemu-desktop 包提供了全系统仿真的 x86_64 架构模拟器(qemu-system-x86_64)。qemu-emulators-full 包提供了 x86_64 用户模式变体(qemu-x86_64),并且对于其他支持的架构,它同时包含全系统和用户模式变体(例如 qemu-system-armqemu-arm)。
  • 这些包的无头版本(仅适用于全系统仿真)是 qemu-base(仅限 x86_64)和 qemu-emulators-full(其他架构)。
  • 全系统仿真可以通过包含在单独包中的某些 QEMU 模块进行扩展:qemu-block-glusterqemu-block-iscsiqemu-guest-agent
  • qemu-user-static 为 QEMU 支持的所有目标架构提供用户模式和静态变体。安装的 QEMU 命令的名称为 qemu-target_architecture-static,例如,对于 Intel 64 位 CPU 为 qemu-x86_64-static
注意 目前,Arch 不提供全系统模式和静态链接变体(官方或通过 AUR),因为这通常是不需要的。

QEMU 的图形前端

与 VirtualBox 和 VMware 等其他虚拟化程序不同,QEMU 不提供 GUI 来管理虚拟机(除了运行虚拟机时出现的窗口),也不提供创建具有保存设置的持久虚拟机的方法。除非您创建了一个自定义脚本来启动虚拟机,否则每次启动都必须在命令行上指定运行虚拟机的所有参数。

Libvirt 提供了一种方便的方式来管理 QEMU 虚拟机。请参阅 libvirt 客户端列表 以获取可用的前端。

创建新的虚拟化系统

创建硬盘映像

本文或本章节的准确性存在争议。

原因: 如果我正确理解了 man 手册页,原始格式仅在文件系统不支持“洞”或明确要求预分配时才分配全部大小。请参阅 qemu-img(1) § NOTES。(在 Talk:QEMU 中讨论)
提示 有关 QEMU 映像的更多信息,请参阅 Wikibooks:QEMU/Images

要运行 QEMU,您需要一个硬盘映像,除非您从 CD-ROM 或网络启动实时系统(并且不是为了将操作系统安装到硬盘映像)。硬盘映像是一个文件,其中存储了模拟硬盘的内容。

硬盘映像可以是*原始*格式,它在字节层面与客户机看到的一致,并且始终在主机上使用客户机硬盘驱动器的全部容量。这种方法 I/O 开销最小,但可能会浪费大量空间,因为客户机上未使用的空间不能在主机上使用。

或者,硬盘映像可以是*qcow2*等格式,它仅在客户机操作系统实际写入其虚拟硬盘上的这些扇区时才分配空间给映像文件。映像对客户机操作系统显示为完整大小,即使它在主机系统上可能只占用很小的空间。此映像格式还支持 QEMU 快照功能(有关详细信息,请参阅 #Creating and managing snapshots via the monitor console)。然而,与*原始*格式相比,使用此格式可能会影响性能。

QEMU 提供 qemu-img 命令来创建硬盘映像。例如,要创建一个 4 GiB 的*原始*格式映像

$ qemu-img create -f raw image_file 4G

您可以使用 -f qcow2 来创建*qcow2*磁盘。

注意 您也可以通过使用 ddfallocate(1) 创建所需大小的文件来简单地创建*原始*映像。
警告 如果您将硬盘映像存储在 Btrfs 文件系统上,则在创建任何映像之前,应考虑禁用该目录的 Copy-on-Write。在创建映像时,可以在 qcow2 格式的选项 nocow 中指定。
$ qemu-img create -f qcow2 image_file -o nocow=on 4G

覆盖存储映像

您可以创建一次存储映像(“backing”映像),然后让 QEMU 在覆盖映像中保留对此映像的更改。这允许您恢复此存储映像的先前状态。您可以通过在希望恢复的时间创建一个新的覆盖映像,基于原始 backing 映像来恢复。

要创建覆盖映像,请发出类似如下的命令

$ qemu-img create -o backing_file=img1.raw,backing_fmt=raw -f qcow2 img1.cow

之后,您可以像往常一样运行您的 QEMU 虚拟机(参见 #Running a virtualized system)。

$ qemu-system-x86_64 img1.cow

backing 映像将保持不变,对此存储的更改将记录在覆盖映像文件中。

当 backing 映像的路径发生变化时,需要进行修复。

警告 backing 映像的绝对文件系统路径存储在(二进制)覆盖映像文件中。更改 backing 映像的路径需要一些努力。

确保 backing 映像的原始路径仍然指向此映像。如果需要,可以在原始路径上创建一个指向新路径的符号链接。然后发出类似如下的命令

$ qemu-img rebase -b /new/img1.raw /new/img1.cow

您可以自行选择执行“不安全”的 rebase,在此过程中不检查 backing 映像的旧路径。

$ qemu-img rebase -u -b /new/img1.raw /new/img1.cow

调整映像大小

警告 调整包含 NTFS 引导文件系统的映像的大小可能会导致安装在其上的操作系统无法启动。建议先创建备份。

qemu-img 可执行文件具有 resize 选项,该选项可以轻松调整硬盘映像的大小。它适用于*原始*和*qcow2*格式。例如,要增加 10 GiB 的映像空间,请运行

$ qemu-img resize disk_image +10G

增大磁盘映像后,您必须在虚拟机内部使用文件系统和分区工具来实际开始使用新空间。

缩小映像

缩小磁盘映像时,您必须首先使用虚拟机内部的文件系统和分区工具来减小分配的文件系统和分区大小,然后相应地缩小磁盘映像。对于 Windows 客户机,这可以在“创建和格式化硬盘分区”控制面板中执行。

警告 在未减小客户机分区大小的情况下缩小磁盘映像将导致数据丢失。

然后,要减小 10 GiB 的映像空间,请运行

$ qemu-img resize --shrink disk_image -10G

转换映像

您可以使用 qemu-img convert 将映像转换为其他格式。此示例演示了如何将*原始*映像转换为*qcow2*

$ qemu-img convert -f raw -O qcow2 input.img output.qcow2

这不会删除原始输入文件。

准备安装介质

要将操作系统安装到您的磁盘映像中,您需要操作系统的安装介质(例如,光盘、USB 驱动器或 ISO 映像)。不应挂载安装介质,因为 QEMU 会直接访问介质。

提示 如果使用光盘,最好先将介质转储到文件中,因为这样可以提高性能,并且您不必直接访问设备(也就是说,您可以以普通用户身份运行 QEMU,而无需更改介质设备文件的访问权限)。例如,如果 CD-ROM 设备节点名为 /dev/cdrom,则可以使用以下命令将其转储到文件中
$ dd if=/dev/cdrom of=cd_image.iso bs=4k

安装操作系统

这是您第一次需要启动模拟器。要将操作系统安装到磁盘映像,您必须将磁盘映像和安装介质都连接到虚拟机,并使其从安装介质启动。

例如,对于 i386 客户机,要从可启动 ISO 文件作为 CD-ROM 和原始磁盘映像进行安装

$ qemu-system-x86_64 -cdrom iso_image -boot order=d -drive file=disk_image,format=raw

有关加载其他介质类型(如软盘、磁盘映像或物理驱动器)的信息,请参阅 qemu(1),有关其他有用选项,请参阅 #Running a virtualized system

操作系统安装完成后,可以直接启动 QEMU 映像(参见 #Running a virtualized system)。

注意 默认情况下,分配给机器的内存只有 128 MiB。可以使用 -m 开关调整内存量,例如 -m 512M-m 2G
提示
  • 一些用户可能更喜欢使用启动菜单而不是指定 -boot order=x-boot menu=on,至少在配置和实验期间。
  • 当在无头模式下运行 QEMU 时,它默认会启动一个本地 VNC 服务器,端口为 5900。您可以使用 TigerVNC 连接到客户机操作系统:vncviewer :5900
  • 如果您需要在安装过程中替换软盘或 CD,可以使用 QEMU 机器监视器(在虚拟机窗口中按 Ctrl+Alt+2)来移除和连接存储设备到虚拟机。键入 info block 查看块设备,并使用 change 命令交换设备。按 Ctrl+Alt+1 返回虚拟机。

预制虚拟机映像

在许多情况下,手动安装自己的操作系统并非必要或期望,例如在云环境中。幸运的是,许多预制映像可从不同提供商处下载。

对于 Arch Linux,官方的 arch-boxes 项目提供每周映像发布

Fedora 和 Debian 也有类似的映像可供使用,例如 Fedora

运行虚拟化系统

qemu-system-* 二进制文件(例如 qemu-system-i386qemu-system-x86_64,取决于客户机的架构)用于运行虚拟化的客户机。用法如下:

$ qemu-system-x86_64 options disk_image

所有 qemu-system-* 二进制文件的选项都相同,请参阅 qemu(1) 以获取所有选项的文档。

通常,如果一个选项有许多可能的值,您可以使用

$ qemu-system-x86_64 option help

来列出所有可能的值。如果它支持属性,您可以使用

$ qemu-system-x86_64 option value,help

来列出所有可用属性。

例如:

$ qemu-system-x86_64 -machine help
$ qemu-system-x86_64 -machine q35,help
$ qemu-system-x86_64 -device help
$ qemu-system-x86_64 -device qxl,help

您可以使用这些方法以及 qemu(1) 文档来理解以下部分中使用的选项。

默认情况下,QEMU 会在一个窗口中显示虚拟机的视频输出。需要注意的一点是:当您点击 QEMU 窗口内部时,鼠标指针会被捕获。要释放它,请按 Ctrl+Alt+g

警告 QEMU 绝不应该以 root 用户身份运行。如果您必须在脚本中以 root 用户身份启动它,您应该使用 -runas 选项来让 QEMU 放弃 root 权限。

启用 KVM

KVM(Kernel-based Virtual Machine)全虚拟化必须得到您的 Linux 内核和硬件的支持,并且必须加载必要的 内核模块。有关更多信息,请参阅 KVM

要在 KVM 模式下启动 QEMU,请在附加的启动选项中添加 -accel kvm。要检查正在运行的虚拟机是否启用了 KVM,请进入 #QEMU monitor 并输入 info kvm

  • -machine 选项的参数 accel=kvm 等同于 -enable-kvm-accel kvm 选项。
  • CPU 模型 host 需要 KVM。
  • 如果您使用 GUI 工具启动虚拟机,并且遇到非常差的性能,您应该检查 KVM 支持是否正确,因为 QEMU 可能会回退到软件仿真。
  • KVM 需要启用才能正确启动 Windows 7 或 Windows 8 而不出现“蓝屏”。

启用 IOMMU (Intel VT-d/AMD-Vi) 支持

首先启用 IOMMU,请参阅 PCI passthrough via OVMF#Setting up IOMMU

添加 -device intel-iommu 来创建 IOMMU 设备

$ qemu-system-x86_64 -enable-kvm -machine q35 -device intel-iommu -cpu host ..
注意 在基于 Intel CPU 的系统上,使用 -device intel-iommu 在 QEMU 客户机中创建 IOMMU 设备将导致 PCI 直通失败并出现类似以下的错误:
Device at bus pcie.0 addr 09.0 requires iommu notifier which is currently not supported by intel-iommu emulation
虽然仍然需要内核参数 intel_iommu=on 来重新映射 IO(例如 使用 vfio-pci 进行 PCI 直通),但如果需要 PCI 直通,则不应设置 -device intel-iommu

以 UEFI 模式启动

QEMU 使用的默认固件是 SeaBIOS,它是一个 Legacy BIOS 实现。QEMU 使用 /usr/share/qemu/bios-256k.bin(由 seabios 包提供)作为默认的只读(ROM)映像。您可以使用 -bios 参数选择另一个固件文件。但是,UEFI 需要可写内存才能正常工作,因此您需要模拟 PC System Flash

OVMF 是一个 TianoCore 项目,用于为虚拟机启用 UEFI 支持。可以使用 edk2-ovmf 包进行安装

有两种方法可以使用 OVMF 作为固件。第一种是复制 /usr/share/edk2/x64/OVMF.4m.fd,使其可写,并将其用作 pflash 驱动器。

-drive if=pflash,format=raw,file=/copy/of/OVMF.4m.fd

所有对 UEFI 设置的更改将直接保存到此文件中。

另一种更优选的方法是将 OVMF 分为两个文件。第一个是只读的,存储固件可执行文件,第二个将用作可写的变量存储。优点是您可以直接使用固件文件而无需复制,因此它将由 pacman 自动更新。

/usr/share/edk2/x64/OVMF_CODE.4m.fd 用作第一个只读 pflash 驱动器。复制 /usr/share/edk2/x64/OVMF_VARS.4m.fd,使其可写,并将其用作第二个可写 pflash 驱动器。

-drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd \
-drive if=pflash,format=raw,file=/copy/of/OVMF_VARS.4m.fd

启用安全启动

要启用安全启动,您必须使用安装了安全启动密钥的 OVMF 固件文件,而上游项目不提供此文件[1]

与某些其他 Linux 发行版不同,Arch Linux 目前不提供预先注册了安全启动已启用的固件文件;有关更多信息,请参阅 archlinux/packaging/packages/edk2#1。尽管固件文件 /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd 存在并且似乎支持安全启动,但它实际上不支持。使用它将导致虚拟机无法启动,直到您将其替换为另一个固件文件(或您之前的固件)才能再次启动。

一个简单的解决方法是使用 Fedora 的 edk2-ovmf 包(它已经自带安全启动)。

  • 安装 edk2-ovmf-fedoraAUR
  • 使用 /usr/share/edk2/ovmf/OVMF_CODE.secboot.fd/usr/share/edk2/ovmf/OVMF_CODE_4M.secboot.qcow2 作为您的固件文件。
  • 如果您需要 NVRAM(Windows 10 和 11 机器可选),请使用 /usr/share/edk2/ovmf/OVMF_VARS.secboot.fd/usr/share/edk2/ovmf/OVMF_VARS_4M.secboot.qcow2 作为您的模板。
  • 确保 QEMU 使用 q35 芯片组机器类型(-machine q35)。

这样,您的虚拟机上的安全启动就启用了!

或者,您可以提供自己的 OVMF 文件,并使用自己的密钥手动注册它们。有关如何执行此操作,请参阅 KVM#安全启动

提示此论坛帖子 中描述了一种更繁琐(尽管与上游略有兼容)的解决方法,用于手动将密钥注册到纯 OVMF_VARS 文件中。

可信平台模块仿真

QEMU 可以仿真 可信平台模块,这对于 Windows 11 等某些系统是必需的(它需要 TPM 2.0)。

安装 swtpm 包,它提供了一个软件 TPM 实现。创建一个用于存储 TPM 数据的目录(将使用 /path/to/mytpm 作为示例)。运行此命令来启动模拟器:

$ swtpm socket --tpm2 --tpmstate dir=/path/to/mytpm --ctrl type=unixio,path=/path/to/mytpm/swtpm-sock

/path/to/mytpm/swtpm-sock 将由 swtpm 创建:这是一个 QEMU 将连接的 UNIX 套接字。您可以将其放在任何目录中。

默认情况下,swtpm 启动 TPM 版本 1.2 模拟器。--tpm2 选项启用 TPM 2.0 仿真。

最后,将以下选项添加到 QEMU:

-chardev socket,id=chrtpm,path=/path/to/mytpm/swtpm-sock \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis,tpmdev=tpm0

TPM 将在虚拟机内部可用。关闭虚拟机后,swtpm 将自动终止。

有关更多信息,请参阅 QEMU 文档

如果客户机操作系统仍不识别 TPM 设备,请尝试调整 CPU 模型和拓扑 选项。这可能会导致问题。

主机和客户机之间的通信

网络

可以通过任何可以传输文件的网络协议(例如 NFSSMBNBD、HTTP、FTPSSH)在主机和客户机操作系统之间共享数据,前提是您已正确设置网络并启用了相应的服务。

默认的基于 SLIRP 的用户模式网络允许客户机通过 IP 地址 10.0.2.2 访问主机操作系统。您在主机操作系统上运行的任何服务器,例如 SSH 服务器或 SMB 服务器,都可以在此 IP 地址上访问。因此,在客户机上,您可以挂载通过 SMBNFS 导出的目录,或者访问主机的 HTTP 服务器等。主机操作系统无法访问客户机操作系统上运行的服务器,但这可以通过其他网络配置实现(请参阅 #使用 QEMU 进行 Tap 网络)。

QEMU 的端口转发

注意 QEMU 的端口转发仅支持 IPv4。尚未实现 IPv6 端口转发,最新的补丁是在 2018 年提出的 [2]。如果您需要完整的 IPv6 支持,请查看 #passt

QEMU 可以将主机端口转发到客户机,以实现例如从主机连接到客户机上运行的 SSH 服务器。

例如,要将主机上的端口 60022 绑定到客户机上的端口 22 (SSH),请使用类似以下命令启动 QEMU:

$ qemu-system-x86_64 disk_image -nic user,hostfwd=tcp::60022-:22

确保 sshd 在客户机上运行,然后使用以下命令连接:

$ ssh guest-user@127.0.0.1 -p 60022

您可以使用 SSHFS 将客户机的文件系统挂载到主机上,以实现共享的读写访问。

要转发多个端口,只需在 -nic 参数中重复 hostfwd,例如对于 VNC 端口:

$ qemu-system-x86_64 disk_image -nic user,hostfwd=tcp::60022-:22,hostfwd=tcp::5900-:5900

通过 vsock 访问 SSH

连接到 VM 的一种安全便捷的方式是使用 vsock(7) 上的 SSH。您的 VM 需要基于 systemd 才能开箱即用地工作。

首先,使用特殊设备启动 QEMU:

-device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=555

cid 需要由用户选择一个有效的 32 位数字(参见 vsock(7))。当 systemd 检测到 VM 已使用 vhost-vsock 设备启动时,它将通过 systemd-ssh-generator 自动启动 SSH 服务器。

然后,您可以这样连接到 VM:

$ ssh user@vsock/555

这是因为 /etc/ssh/ssh_config.d/20-systemd-ssh-proxy.conf 告诉您的 SSH 客户端使用 systemd-ssh-proxy 来允许 SSH 使用 vsock。

此外,使用 systemd.system-credentials(7),我们可以为 root 用户注入一个授权密钥文件,这在尝试运行下载的镜像时非常方便。可以这样做:

-smbios type=11,value=io.systemd.credential.binary:ssh.authorized_keys.root=c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSU9sVFE4ejlpeWxoMTMreCtFVFJ1R1JEaHpIVVRnaCt2ekJLOGY3TEl5eTQ=

公钥行必须以 base64 编码的字符串形式提供。可以这样做:

echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOlTQ8z9iylh13+x+ETRuGRDhzHUTgh+vzBK8f7LIyy4" | base64

通过 -smbios type=11,value=io.systemd... 相同的机制可以用来注入各种其他将被 systemd 处理的特殊变量。另请参阅 systemd 文档:系统和服务凭据

QEMU 的内置 SMB 服务器

QEMU 的文档称其拥有一个“内置”SMB 服务器,但实际上它只是在主机上启动 Samba,并使用位于 /tmp/qemu-smb.random_string 的自动生成的 smb.conf 文件,并将其默认可供客户机在不同的 IP 地址(默认为 10.0.2.4)上访问。这仅适用于用户网络,并且在您不想在主机上启动正常 Samba 服务时很有用,客户机也可以访问该服务(如果您已在其上设置了共享)。

Samba 必须安装在主机上。要启用此功能,请使用类似以下命令启动 QEMU:

$ qemu-system-x86_64 -nic user,id=nic0,smb=shared_dir_path disk_image

其中 shared_dir_path 是您要在客户机和主机之间共享的目录。

然后,在客户机中,您将能够通过共享名“qemu”在主机 10.0.2.4 上访问共享目录。例如,在 Windows Explorer 中,您将转到 \\10.0.2.4\qemu

  • 如果您多次使用共享选项,例如 -net user,smb=shared_dir_path1 -net user,smb=shared_dir_path2-net user,smb=shared_dir_path1,smb=shared_dir_path2,则只会共享最后定义的那个。
  • 如果您无法访问共享文件夹,并且客户机系统是 Windows,请检查 NetBIOS 协议是否已启用,并且防火墙没有阻止 NetBIOS 协议使用的 端口
  • 如果您无法访问共享文件夹,并且客户机系统是 Windows 10 Enterprise 或 Education 或 Windows Server 2016,请启用客户机访问
  • 如果您使用 #使用 QEMU 进行 Tap 网络,请使用 -device virtio-net,netdev=vmnic -netdev user,id=vmnic,smb=shared_dir_path 来获得 SMB。

共享多个目录

共享多个目录(或在虚拟机运行时添加或删除它们)的一种方法是共享一个空目录并创建/删除符号链接。为了使此方法生效,可以使用以下脚本修改正在运行的 SMB 服务器的配置,该脚本还允许执行客户机上没有设置为可执行文件的文件:

#!/bin/sh
eval $(ps h -C smbd -o pid,args | grep /tmp/qemu-smb | gawk '{print "pid="$1";conf="$6}')
echo "[global]
allow insecure wide links = yes
[qemu]
follow symlinks = yes
wide links = yes
acl allow execute always = yes" >> "$conf"
# in case the change is not detected automatically:
smbcontrol --configfile="$conf" "$pid" reload-config

此脚本可以在客户机第一次连接到网络驱动器后,应用于 qemu 启动的正在运行的服务器。此方法的另一种选择是向配置文件添加其他共享,如下所示:

echo "[myshare]
path=another_path
read only=no
guest ok=yes
force user=username" >> $conf

此共享将在客户机上显示为 \\10.0.2.4\myshare

使用 9pfs VirtFS 进行主机文件共享

注意 9pfs 相当慢,因为它不是专门为高性能本地 VM 使用而开发的。建议用户查看 #使用 virtiofsd 进行主机文件共享,后者是专门为 VM 性能而设计的。

请参阅 QEMU 文档

使用 virtiofsd 进行主机文件共享

virtiofsdvirtiofsd 包提供。它是一种现代、高性能的方式,可以方便地在主机和客户机之间共享文件。有关可用选项的完整列表,请参阅 在线文档/usr/share/doc/virtiofsd/README.md

您可以选择以 root 用户或普通用户身份运行 virtiofsd

以普通用户身份运行 virtiofsd

首先,请确保将要执行 virtiofsd 的用户在 subuid(5)subgid(5) 中有配置条目。另请参阅 Podman 文章中的相关部分

然后,启动 virtiofsd

$ unshare -r --map-auto -- /usr/lib/virtiofsd --socket-path=/tmp/vm-share.sock --shared-dir /tmp/vm-share --sandbox chroot
  • unshare -r 会导致后面的命令在一个新的用户命名空间中启动,当前用户在新命令中被映射为 root。这一点很重要,因为 virtiofsd 从其自身角度来看期望以 root 身份运行。
  • /tmp/vm-share.sock 是一个套接字文件。
  • /tmp/vm-share 是主机和客户机虚拟机之间的共享目录。

以 root 用户身份运行 virtiofsd

将运行 QEMU 的用户添加到 kvm 用户组,因为它需要访问 virtiofsd 套接字。您可能需要注销才能使更改生效。

以 root 用户身份启动 virtiofsd

# /usr/lib/virtiofsd --socket-path /tmp/vm-share.sock --socket-group kvm --shared-dir /tmp/vm-share

其中

  • /tmp/vm-share.sock 是一个套接字文件。
  • /tmp/vm-share 是主机和客户机虚拟机之间的共享目录。

启动 QEMU

在启动虚拟机时添加以下配置选项:

-m 4G
-object memory-backend-memfd,id=mem,size=4G,share=on
-numa node,memdev=mem
-chardev socket,id=char0,path=/tmp/vm-share.sock
-device vhost-user-fs-pci,chardev=char0,tag=myfs

其中

  • size=4G 必须与 -m 4G 选项指定的内存大小匹配。
  • /tmp/vm-share.sock 指向之前启动的套接字文件。
  • myfs 是您稍后在客户机中用于挂载共享的标识符。

直接启动 rootfs

您也可以通过 virtiofsd 直接启动 rootfs。除了上述参数外,还添加:

-kernel /path/to/vmlinux
-initrd /path/to/initramfs
-append 'rootfstype=virtiofs root=myfs rootflags=rw,noatime'

在 Linux 客户机中使用共享

登录到客户机作为 root 用户后,您只需在一个现代发行版上挂载共享即可:

# mount -t virtiofs myfs /mnt

现在,此目录应该在主机和客户机之间共享。

在 Windows 客户机中使用共享

请参阅 相关的 Windows 部分

在主机上挂载客户机的分区

将驱动器映像挂载到主机系统上可能很有用,这是将文件传输进出客户机的一种方式。这应该在虚拟机未运行时进行。

在主机上挂载驱动器的过程取决于 QEMU 映像的类型,即 rawqcow2。我们将在 #挂载 raw 映像中的分区#挂载 qcow2 映像中的分区 中详细介绍这两种格式的驱动器挂载步骤。有关完整文档,请参阅 Wikibooks:QEMU/Images#Mounting an image on the host

警告 在再次运行虚拟机之前,您必须卸载分区。否则,很可能发生数据损坏。

挂载 raw 映像中的分区

可以通过将它们设置为回环设备来挂载原始磁盘映像文件中的分区。

手动指定字节偏移量

挂载磁盘映像分区的一种方法是使用类似以下命令的命令将磁盘映像挂载到特定偏移量:

# mount -o loop,offset=32256 disk_image mountpoint

offset=32256 选项实际上会传递给 losetup 程序,以设置一个从文件偏移量 32256 字节开始并持续到文件末尾的回环设备。然后挂载此回环设备。您还可以使用 sizelimit 选项指定分区的确切大小,但这通常是不必要的。

根据您的磁盘映像,所需的が分区可能不是从偏移量 32256 开始。运行 fdisk -l disk_image 来查看映像中的分区。fdisk 以 512 字节扇区为单位给出起始和结束偏移量,因此乘以 512 即可获得传递给 mount 的正确偏移量。

通过回环模块自动检测分区

Linux 回环驱动程序实际上支持回环设备中的分区,但默认情况下它是禁用的。要启用它,请执行以下操作:

  • 移除所有回环设备(卸载所有挂载的映像等)。
  • 卸载 loop 内核模块,并使用 max_part=15 参数加载它。此外,回环设备的最大数量可以通过 max_loop 参数控制。
提示 您可以在 /etc/modprobe.d 中放置一个条目,以便每次加载 loop 模块时都设置 max_part=15,或者您可以在内核命令行上放置 loop.max_part=15,具体取决于 loop.ko 模块是内置于您的内核中还是外部加载。

将映像设置为回环设备:

# losetup -f -P disk_image

然后,如果创建的设备是 /dev/loop0,将自动创建额外的设备 /dev/loop0pX,其中 X 是分区的编号。这些分区回环设备可以直接挂载。例如:

# mount /dev/loop0p1 mountpoint

要使用 udisksctl 挂载磁盘映像,请参阅 Udisks#挂载回环设备

使用 kpartx

来自 multipath-tools 包的 kpartx 可以读取设备上的分区表,并为每个分区创建一个新设备。例如:

# kpartx -a disk_image

这将设置回环设备并在 /dev/mapper/ 中创建必要的分区设备。

挂载 qcow2 映像中的分区

我们将使用 qemu-nbd,它允许我们使用 NBD(网络块设备)协议来共享磁盘映像。

首先,我们需要加载 nbd 模块:

# modprobe nbd max_part=16

然后,我们可以共享磁盘并创建设备条目:

# qemu-nbd -c /dev/nbd0 /path/to/image.qcow2

发现分区

# partprobe /dev/nbd0

可以使用 fdisk 获取有关 nbd0 中不同分区的相关信息:

# fdisk -l /dev/nbd0
Disk /dev/nbd0: 25.2 GiB, 27074281472 bytes, 52879456 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa6a4d542

Device      Boot   Start      End  Sectors  Size Id Type
/dev/nbd0p1 *       2048  1026047  1024000  500M  7 HPFS/NTFS/exFAT
/dev/nbd0p2      1026048 52877311 51851264 24.7G  7 HPFS/NTFS/exFAT

然后挂载驱动器映像的任何分区,例如分区 2:

# mount /dev/nbd0p2 mountpoint

使用后,重要的是卸载映像并执行相反的步骤,即卸载分区并断开 nbd 设备连接:

# umount mountpoint
# qemu-nbd -d /dev/nbd0

网络

本文或本节需要在语言、wiki 语法或风格方面进行改进。请参阅 Help:Style 获取参考。

原因:网络拓扑(#仅主机网络#内部网络 部分和分散在其他部分的信息)不应与各种虚拟接口实现一起描述,例如 #用户模式网络#使用 QEMU 进行 Tap 网络QEMU/高级网络#使用 VDE2 进行网络。(请在 Talk:QEMU 中讨论)

与用户模式网络或 vde 相比,使用 tap 设备和网桥进行虚拟网络通信的性能应该更好,因为 tap 设备和网桥是在内核中实现的。

此外,通过为虚拟机分配 virtio 网络设备而不是默认的 e1000 NIC 仿真,可以提高网络性能。有关更多信息,请参阅 #使用 virtio 驱动程序

通过向 QEMU 提供 -net nic 参数,它将默认为主机分配一个链路级地址为 52:54:00:12:34:56 的虚拟机的网络接口。但是,在使用具有多个虚拟机的桥接网络时,每个虚拟机在 tap 设备的主机侧都必须具有唯一的链路级(MAC)地址。否则,桥接将无法正常工作,因为它将接收来自具有相同链路级地址的多个源的数据包。即使 tap 设备本身具有唯一的链路级地址,也会出现此问题,因为在数据包通过 tap 设备时,源链路级地址不会被重写。

确保每个虚拟机都有一个唯一的链路级地址,但它应始终以 52:54: 开头。使用以下选项,将 X 替换为任意十六进制数字:

$ qemu-system-x86_64 -net nic,macaddr=52:54:XX:XX:XX:XX -net vde disk_image

生成唯一的链路级地址有多种方法:

  • 手动为每个 NIC 指定唯一的链路级地址。好处是 DHCP 服务器每次运行虚拟机时都会分配相同的 IP 地址,但对于大量虚拟机来说是不可用的。
  • 每次运行虚拟机时生成随机链路级地址。冲突的概率实际上为零,但缺点是 DHCP 服务器每次都会分配不同的 IP 地址。您可以在脚本中使用以下命令生成 macaddr 变量中的随机链路级地址:
printf -v macaddr "52:54:%02x:%02x:%02x:%02x" $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff)) $(( $RANDOM & 0xff ))
qemu-system-x86_64 -net nic,macaddr="$macaddr" -net vde disk_image
  • 使用以下脚本 qemu-mac-hasher.py 通过哈希函数从虚拟机名称生成链路级地址。鉴于虚拟机名称是唯一的,此方法结合了上述方法的优点:它在每次运行脚本时生成相同的链路级地址,同时保持了几乎为零的冲突概率。
qemu-mac-hasher.py
#!/usr/bin/env python
# usage: qemu-mac-hasher.py <VMName>

import sys
import zlib

crc = str(hex(zlib.crc32(sys.argv[1].encode("utf-8")))).replace("x", "")[-8:]
print("52:54:%s%s:%s%s:%s%s:%s%s" % tuple(crc))

在脚本中,您可以使用例如:

vm_name="VM Name"
qemu-system-x86_64 -name "$vm_name" -net nic,macaddr=$(qemu-mac-hasher.py "$vm_name") -net vde disk_image

用户模式网络

SLIRP

默认情况下,在没有任何 -netdev 参数的情况下,QEMU 将使用 基于 SLIRP 的 用户模式网络,并带有内置 DHCP 服务器。当您的虚拟机运行其 DHCP 客户端时,它们将被分配一个 IP 地址,并且它们可以通过 QEMU 进行的 IP 伪装来访问物理主机的网络。

注意 ICMPv6 将无法工作,因为它尚未实现支持:Slirp: external icmpv6 not supported yetPing IPv6 地址将不起作用。

此默认配置允许您的虚拟机轻松访问 Internet,前提是主机已连接到 Internet,但虚拟机在外部网络上不可直接见,并且如果您同时启动多个虚拟机,它们也无法相互通信。

QEMU 的用户模式网络可以提供更多功能,例如内置 TFTP 或 SMB 服务器,将主机端口重定向到客户机(例如,允许 SSH 连接到客户机),或者将客户机连接到 VLAN,以便它们可以相互通信。有关更多详细信息,请参阅 QEMU 关于 -net user 标志的文档。

但是,基于 SLIRP 的用户模式网络在效用和性能方面都有局限性。更高级的网络配置需要使用 tap 设备或其他方法。

提示
  • 要将 virtio 驱动程序与用户模式网络一起使用,选项是:-nic user,model=virtio-net-pci
  • 您可以通过添加 restrict=y 来将用户模式网络与主机和外部世界隔离开来,例如:-net user,restrict=y

passt

用户可以选择使用 基于 passt 的 用户模式网络。与 SLIRP 相比,passt 具有多项优势,例如更好的性能、完整的 IPv6 支持(包括 ICMPv6)、更高的安全性以及更多的控制。

要开始使用,请安装 passt。有两种方法可以启动它:通过基于套接字的通信,或者通过共享的 vhost-user。后者方法性能更好。

对于基于套接字的方式,首先启动 passt

$ passt -f

然后,为您的 QEMU 命令添加这些参数:

-device virtio-net-pci,netdev=s
-netdev stream,id=s,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket

对于 vhost-user 方式,使用 --vhost-user 启动 passt

$ passt -f --vhost-user

然后,为您的 QEMU 命令添加这些参数:

-m 4G
-chardev socket,id=chr0,path=/tmp/passt_1.socket
-netdev vhost-user,id=netdev0,chardev=chr0
-device virtio-net,netdev=netdev0
-object memory-backend-memfd,id=memfd0,share=on,size=4G
-numa node,memdev=memfd0

请注意,-m 4Gsize=4G 的内存大小必须完全匹配。

使用 QEMU 进行 Tap 网络

Tap 设备 是 Linux 内核的一项功能,它允许您创建看起来像真实网络接口的虚拟网络接口。发送到 tap 接口的数据包将被传递给绑定到该接口的用户空间程序,例如 QEMU。

QEMU 可以为虚拟机使用 tap 网络,以便发送到 tap 接口的数据包将被发送到虚拟机,并显示为来自虚拟机中的网络接口(通常是 Ethernet 接口)。反之,虚拟机通过其网络接口发送的所有内容都将出现在 tap 接口上。

Tap 设备支持 Linux 网桥驱动程序,因此可以将 tap 设备彼此桥接,或者可能与 eth0 等其他主机接口桥接。如果您希望虚拟机能够相互通信,或者希望 LAN 上的其他计算机能够与虚拟机通信,那么这是可取的。

警告 如果您将 tap 设备与 eth0 等主机接口桥接在一起,您的虚拟机将直接出现在外部网络上,这将使它们面临可能的攻击。根据您的虚拟机可以访问的资源,您可能需要采取通常用于保护计算机的 所有预防措施 来保护您的虚拟机。如果风险过大,虚拟机资源很少,或者您设置了多个虚拟机,一个更好的解决方案可能是使用 仅主机网络 并设置 NAT。在这种情况下,您只需要为主机上的一个防火墙,而不是为每个客户机使用多个防火墙。

如用户模式网络部分所示,tap 设备比用户模式提供更高的网络性能。如果客户机操作系统支持 virtio 网络驱动程序,那么网络性能也会大大提高。假设使用 tap0 设备,客户机上使用了 virtio 驱动程序,并且没有使用脚本来帮助启动/停止网络,那么 QEMU 命令的一部分应该是这样的:

-device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no

但是,如果您已经在使用带有 virtio 网络驱动程序的 tap 设备,则可以通过启用 vhost 来进一步提高网络性能,例如:

-device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no,vhost=on

有关更多信息,请参阅 [3]

仅主机网络

如果为网桥分配了 IP 地址并且允许流向它的流量,但没有真实接口(例如 eth0)连接到网桥,那么虚拟机将能够相互通信以及与主机系统通信。但是,如果您不在物理主机上设置 IP 伪装,它们将无法与外部网络上的任何内容通信。这种配置在 VirtualBox 等其他虚拟化软件中被称为 仅主机网络

提示
  • 如果您想设置 IP 伪装,例如为虚拟机设置 NAT,请参阅 Internet 共享#启用 NAT 页面。
  • 有关创建网桥的信息,请参阅 网络桥接
  • 您可能希望在网桥接口上运行一个 DHCP 服务器来为虚拟网络提供服务。例如,要使用 172.20.0.1/16 子网,并将 dnsmasq 作为 DHCP 服务器:
# ip addr add 172.20.0.1/16 dev br0
# ip link set br0 up
# dnsmasq -C /dev/null --interface=br0 --bind-interfaces --dhcp-range=172.20.0.2,172.20.255.254

内部网络

如果您不为网桥分配 IP 地址,那么虚拟机将能够相互通信,但不能与物理主机或外部网络通信。这种配置在 VirtualBox 等其他虚拟化软件中被称为 内部网络。您需要为虚拟机分配静态 IP 地址,或者在其中一个虚拟机上运行 DHCP 服务器。

使用 qemu-bridge-helper 进行桥接网络

此方法不需要启动脚本,并且可以轻松适应多个 tap 和多个网桥。它使用 /usr/lib/qemu/qemu-bridge-helper 二进制文件,该文件允许在现有网桥上创建 tap 设备。

提示

首先,创建一个包含 QEMU 将使用的所有网桥名称的配置文件:

/etc/qemu/bridge.conf
allow br0
allow br1
...

确保 /etc/qemu/ 具有 755 权限。如果不是这种情况,可能会出现 QEMU 问题GNS3 问题

现在启动虚拟机;最基本的用法是使用默认网络助手和默认网桥 br0 运行 QEMU:

$ qemu-system-x86_64 -nic bridge [...]

使用网桥 br1 和 virtio 驱动程序:

$ qemu-system-x86_64 -nic bridge,br=br1,model=virtio-net-pci [...]

高级网络配置

如果您需要更多地控制您的虚拟机网络,或者您的特定需求在前面的部分中未涵盖,请参阅 QEMU/高级网络

简写配置

如果您经常使用 QEMU 进行各种网络选项的配置,您可能已经创建了大量的 -netdev-device 参数对,这会很重复。您可以使用 -nic 参数来组合 -netdev-device,例如,这些参数:

-netdev tap,id=network0,ifname=tap0,script=no,downscript=no,vhost=on -device virtio-net-pci,netdev=network0

变成:

-nic tap,script=no,downscript=no,vhost=on,model=virtio-net-pci

注意缺少网络 ID,并且设备是使用 model= 创建的。-nic 参数的前半部分是 -netdev 参数,而后半部分(model= 之后)与设备相关。使用相同的参数(例如 smb=)。要完全禁用网络,请使用 -nic none

有关您可以使用哪些参数的更多信息,请参阅 QEMU 网络文档

显卡

QEMU 可以使用 -display curses 命令行选项来仿真标准的文本模式显卡。这允许您直接在文本终端中输入文本并查看文本输出。或者,-nographic 也具有类似的功能。

QEMU 可以仿真几种类型的 VGA 卡。卡类型通过 -vga type 命令行选项传入,可以是 stdqxlvmwarevirtiocirrusnone

std

使用 -vga std,您可以在不需要客户机驱动程序的情况下获得高达 2560 x 1600 像素的分辨率。这是 QEMU 2.2 以来的默认设置。

qxl

QXL 是一款具有 2D 支持的半虚拟化图形驱动程序。要使用它,请传入 -vga qxl 选项并在客户机中安装驱动程序。使用 QXL 时,您可能希望使用 #SPICE 以获得更好的图形性能。

在 Linux 客户机上,必须加载 qxlbochs_drm 内核模块才能获得不错的性能。

QXL 设备的默认 VGA 内存大小为 16M,足以驱动高达 QHD (2560x1440) 的分辨率。要启用更高的分辨率,请增加 vga_memmb

vmware

尽管它有点错误,但它的性能优于 std 和 cirrus。对于 Arch Linux 客户机,请安装 VMware 驱动程序 xf86-video-vmwareAURxf86-input-vmmouse

virtio

virtio-vga / virtio-gpu 是一款基于 virgl 的半虚拟化 3D 图形驱动程序。它已经成熟,目前仅支持使用编译了 gallium-drivers=virgl 选项的 mesa 的 Linux 客户机。

要在客户机系统中启用 3D 加速,请使用 -device virtio-vga-gl 选择此 vga,并为 SDL 和 GTK 显示输出分别启用 -display sdl,gl=on-display gtk,gl=on 中的显示设备上的 OpenGL 上下文。可以通过查看客户机中的内核日志来确认配置成功:

# dmesg | grep drm 
[drm] pci: virtio-vga detected
[drm] virgl 3d acceleration enabled

要在客户机中启用 Vulkan 支持,请使用 -device virtio-vga-gl,hostmem=2G,blob=true,venus=true 等选项,并在客户机系统中安装 vulkan-virtio [4]

cirrus

cirrus 图形适配器是 2.2 版本之前的默认显卡。在现代系统上不应使用它。

none

这就像一台根本没有 VGA 卡的 PC。您甚至无法使用 -vnc 选项访问它。此外,这与 -nographic 选项不同,后者允许 QEMU 模拟 VGA 卡,但禁用 SDL 显示。

SPICE

SPICE 项目旨在提供一个完整的开源解决方案,以无缝的方式远程访问虚拟机。

在主机上启用 SPICE 支持

以下是使用 SPICE 作为远程桌面协议启动的示例,包括对从主机复制和粘贴的支持:

$ qemu-system-x86_64 -vga qxl -device virtio-serial-pci -spice port=5930,disable-ticketing=on -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 -chardev spicevmc,id=spicechannel0,name=vdagent

这些参数的含义如下:

  1. -device virtio-serial-pci 添加一个 virtio-serial 设备。
  2. -spice port=5930,disable-ticketing=on 为 spice 通道设置侦听的 TCP 端口 5930,并允许客户端无需身份验证即可连接。
    提示 使用 Unix 套接字而不是 TCP 端口不涉及使用主机系统的网络堆栈。它并不意味着数据包被封装和解封装以使用网络和相关协议。套接字仅通过硬盘上的 inode 进行标识。因此,它被认为对性能更好。改用 -spice unix=on,addr=/tmp/vm_spice.socket,disable-ticketing=on
  3. -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 为 virtio-serial 设备上的 spice vdagent 打开一个端口,
  4. -chardev spicevmc,id=spicechannel0,name=vdagent 为该端口添加一个 spicevmc chardev。virtserialport 设备的 chardev= 选项必须与 chardev 选项给定的 id= 选项(此示例中为 spicechannel0)匹配。同样重要的是端口名称是 com.redhat.spice.0,因为这是 vdagent 在客户机中查找的命名空间。最后,指定 name=vdagent,以便 spice 知道此通道的用途。

使用 SPICE 客户端连接到客户机

连接到客户机需要一个 SPICE 客户端。在 Arch Linux 中,有以下可用客户端:

  • virt-viewer — SPICE 协议开发者推荐的 SPICE 客户端,是 virt-manager 项目的一个子集。
https://virt-manager.org/ || virt-viewer
  • spice-gtk — SPICE GTK 客户端,是 SPICE 项目的一个子集。作为小部件嵌入到其他应用程序中。
https://www.spice-space.org/ || spice-gtk

有关在智能手机或其他平台上运行的客户端,请参阅 spice-space 下载页面的“其他客户端”部分:spice-space download

手动运行 SPICE 客户端

连接到监听 Unix 套接字的客户机的一种方法是使用 $ remote-viewer spice+unix:///tmp/vm_spice.socket$ spicy --uri="spice+unix:///tmp/vm_spice.socket" 来手动运行 SPICE 客户端,具体取决于所需的客户端。由于处于 SPICE 模式的 QEMU 的行为类似于远程桌面服务器,因此更方便的做法是使用 -daemonize 参数以守护进程模式运行 QEMU。

提示 要通过 SSH 隧道连接到客户机,可以使用以下类型的命令
$ ssh -fL 5999:localhost:5930 my.domain.org sleep 10; spicy -h 127.0.0.1 -p 5999

此示例将 spicy 连接到本地端口 5999,该端口通过 SSH 转发到位于 my.domain.org,端口 5930 的客户机 SPICE 服务器。注意 -f 选项,它请求 ssh 在后台执行 sleep 10 命令。这样,ssh 会话在客户端激活时运行,并在客户端结束后自动关闭。

使用 QEMU 运行 SPICE 客户端

如果显示设置为 SPICE 并带有 -display spice-app 参数,QEMU 可以自动启动一个带有适当套接字的 SPICE 客户端。这将使用系统默认的 SPICE 客户端作为查看器,具体取决于您的 mimeapps.list 文件。

在客户机上启用 SPICE 支持

对于 **Arch Linux 客户机**,为了改进对多个监视器或剪贴板共享的支持,应安装以下软件包

  • spice-vdagent:Xorg SPICE 代理客户端,支持客户端与 X 会话之间的复制和粘贴等功能。(请参阅此 issue,在修复之前,请使用解决方法使其在非 GNOME 桌面上正常工作。)
  • xf86-video-qxl:Xorg QXL 视频驱动程序
  • wl-clipboard:Wayland 剪贴板支持
  • x-resizeAUR:GNOME 以外的桌面环境在 SPICE 客户端窗口调整大小时不会自动响应。此软件包使用 udev 规则和 xrandr 为所有基于 X11 的桌面环境和窗口管理器实现自动调整大小。

对于 **其他操作系统** 下的客户机,请参阅 spice-space 下载页面的“客户机”部分:spice-space download

使用 SPICE 进行密码身份验证

如果您想启用 SPICE 的密码身份验证,需要从 -spice 参数中删除 disable-ticketing,并添加 password=yourpassword。例如

$ qemu-system-x86_64 -vga qxl -spice port=5900,password=yourpassword -device virtio-serial-pci -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 -chardev spicevmc,id=spicechannel0,name=vdagent

您的 SPICE 客户端现在应该会提示输入密码才能连接到 SPICE 服务器。

使用 SPICE 进行 TLS 加密通信

您还可以配置 TLS 加密以与 SPICE 服务器通信。首先,您需要有一个包含以下文件的目录(文件名必须与所示完全一致)

  • ca-cert.pem:CA 主证书。
  • server-cert.pem:使用 ca-cert.pem 签名的服务器证书。
  • server-key.pem:服务器私钥。

Spice 用户手册 中展示了使用您自己生成的 CA 为服务器生成自签名证书的示例。

之后,您可以像上面解释的那样运行带有 SPICE 的 QEMU,但使用以下 -spice 参数:-spice tls-port=5901,password=yourpassword,x509-dir=/path/to/pki_certs,其中 /path/to/pki_certs 是包含前面显示的三个必需文件的目录路径。

现在可以使用 virt-viewer 连接到服务器

$ remote-viewer spice://hostname?tls-port=5901 --spice-ca-file=/path/to/ca-cert.pem --spice-host-subject="C=XX,L=city,O=organization,CN=hostname" --spice-secure-channels=all

请记住,--spice-host-subject 参数需要根据您的 server-cert.pem 主题进行设置。您还需要将 ca-cert.pem 复制到每个客户端以验证服务器证书。

提示 您可以使用以下命令获取正确格式的服务器证书主题行(条目之间用逗号分隔),以便用于 --spice-host-subject
$ openssl x509 -noout -subject -in server-cert.pem | cut -d' ' -f2- | sed 's/\///' | sed 's/\//,/g'

等效的 spice-gtk 命令是

$ spicy -h hostname -s 5901 --spice-ca-file=ca-cert.pem --spice-host-subject="C=XX,L=city,O=organization,CN=hostname" --spice-secure-channels=all

VNC

可以通过添加 -vnc :X 选项让 QEMU 将 VGA 显示重定向到 VNC 会话。将 X 替换为显示编号(0 将监听 5900,1 将监听 5901...)。

$ qemu-system-x86_64 -vnc :0

在“#在启动时启动 QEMU 虚拟机”部分也提供了一个示例。

警告 默认的 VNC 服务器设置不使用任何形式的身份验证。任何用户都可以从任何主机连接。

基本密码身份验证

可以通过使用 password 选项轻松设置访问密码。必须在 QEMU 监视器中指定密码,并且只有在提供密码后才能连接。

$ qemu-system-x86_64 -vnc :0,password -monitor stdio

在 QEMU 监视器中,密码使用 change vnc password 命令设置,然后指定密码。

以下命令直接使用密码运行 vnc

$ printf "change vnc password\n%s\n" MYPASSWORD | qemu-system-x86_64 -vnc :0,password -monitor stdio
注意 密码限制为 8 个字符,可以通过暴力破解攻击猜测。强烈建议在公共网络上进行更复杂的保护。

音频

创建音频后端

-audiodev 标志设置主机上的音频后端驱动程序及其选项。

列出可用的音频后端驱动程序

$ qemu-system-x86_64 -audiodev help

它们的可选设置在 qemu(1) man 页中有所详述。

至少需要选择一个音频后端并设置一个 ID,例如,对于 PulseAudio

-audiodev pa,id=snd0

使用音频后端

Intel HD Audio

对于 Intel HD Audio 仿真,请同时添加控制器和编解码器设备。要列出可用的 Intel HDA Audio 设备

$ qemu-system-x86_64 -device help | grep hda

添加音频控制器

-device ich9-intel-hda

同时,添加音频编解码器并将其映射到主机音频后端 ID

-device hda-output,audiodev=snd0

Intel 82801AA AC97

对于 AC97 仿真,只需添加声卡设备并将其映射到主机音频后端 ID

-device AC97,audiodev=snd0
  • 如果未提供 audiodev 后端,QEMU 会查找并自动添加它,这仅适用于单个 audiodev。例如 -device intel-hda -device hda-duplex 将在客户机中使用默认 audiodev 后端仿真 intel-hda
  • 客户机计算机的视频显卡仿真驱动程序也可能导致声音质量问题。逐一测试以使其正常工作。您可以使用 qemu-system-x86_64 -h | grep vga 列出可能的选项。

VirtIO 声卡

VirtIO 声卡自 QEMU 8.2.0 起也可用。用法是

-device virtio-sound-pci,audiodev=my_audiodev -audiodev alsa,id=my_audiodev

更多信息可在 QEMU 文档中找到。

使用 virtio 驱动程序

QEMU 为客户机提供了使用 virtio 驱动程序的半虚拟化块和网络设备的能力,这提供了更好的性能和更低的开销。

  • virtio 块设备需要 -drive 选项来传递磁盘映像,并带参数 if=virtio
$ qemu-system-x86_64 -drive file=disk_image,if=virtio
  • 网络也几乎一样
$ qemu-system-x86_64 -nic user,model=virtio-net-pci
注意 只有当客户机具有 virtio 设备驱动程序时,此功能才有效。Linux 具有该驱动程序,Arch Linux 中也包含了所需的驱动程序,但不能保证 virtio 设备能与其它操作系统一起工作。

准备 Arch Linux 客户机

要在安装 Arch Linux 客户机后使用 virtio 设备,必须在客户机中加载以下模块:virtiovirtio_pcivirtio_blkvirtio_netvirtio_ring。对于 32 位客户机,不需要特定的“virtio”模块。

如果您想从 virtio 磁盘启动,初始内存磁盘必须包含必要的模块。默认情况下,这由 mkinitcpioautodetect hook 处理。否则,请在 /etc/mkinitcpio.conf 中使用 MODULES 数组包含必要的模块并重建初始内存磁盘。

/etc/mkinitcpio.conf
MODULES=(virtio virtio_blk virtio_pci virtio_net)

virtio 磁盘的识别前缀为 v(例如 vdavdb 等);因此,在从 virtio 磁盘启动时,必须在至少 /etc/fstab/boot/grub/grub.cfg 中进行更改。

提示 如果在 /etc/fstab 和引导加载程序中都使用 UUID 引用磁盘,则无需进行任何操作。

有关 KVM 的半虚拟化,可以在 此处找到更多信息。

您可能还想安装 qemu-guest-agent 来实现对 QMP 命令的支持,这将增强 hypervisor 的管理能力。

内存气球化

为了让客户机的内存占用从主机角度来看可以收缩,它需要向主机报告客户机不再需要的页面。内核有一个称为 Free Page Reporting 的 API,因为它内置于内核中,所以只需像这样启动 QEMU 即可

$ qemu-system-x86_64 ... -device virtio-balloon,free-page-reporting=on

之后,您应该会看到客户机内存增加,然后在其中运行工作负载后再次收缩。

然而,虽然此参数确实可以处理在页面释放时从主机角度收缩客户机内存使用的情况,但它无法自动利用客户机用于缓存的内存。这是一个重要的考虑因素,因为客户机最终可能会将其所有未使用的内存用于缓存,从而使 free-page-reporting=on 无效。请阅读下一节以解决此问题。

使用 virtio pmem 绕过客户机的页面缓存

您可能希望依赖主机页面缓存而不是客户机页面缓存,以实现更有效的内存使用。结合 KSM,这可以使您的虚拟机非常节省内存,只复制少量页面。

实现此目的的一种方法是使用 文件映射的 virtio pmem 设备。将此配置添加到您的 QEMU

-object memory-backend-file,id=mem1,share,mem-path=./virtio_pmem.img,size=32G
-device virtio-pmem-pci,memdev=mem1,id=nv1
-m 64G,maxmem=96G

其中 virtio_pmem.img 是主机上的一个本地文件,将作为我们客户机内部的内存后端。-m 部分在这里很重要:设置 maxmem 参数,使其等于 regular memory + memory-backend-file size。在此示例中:64G + 32G = 96G

使用这些选项启动客户机。在客户机内部,您会在 /dev/pmem0 找到一个新设备,我们需要用 支持 DAX 的文件系统(如 ext4,btrfs 不支持)对其进行格式化。

# mkfs.ext4 /dev/pmem0
mount /dev/pmem0 /mnt -o dax=always

然后,您写入 /mnt 的任何文件都将绕过客户机的页面缓存。

也可以通过这种方式使整个根文件系统支持 DAX。

准备 Windows 客户机

Windows 的 Virtio 驱动程序

Windows 不自带 virtio 驱动程序。Fedora 会定期构建最新且稳定的驱动程序版本,下载驱动程序的详细信息可以在 GitHub 上的 virtio-win 中找到。在接下来的部分中,我们将主要使用此处提供的稳定 ISO 文件:virtio-win.iso。或者,使用 virtio-winAUR

块设备驱动程序

新安装的 Windows

在安装过程中需要加载驱动程序,其过程是将 virtio 驱动程序的 ISO 镜像与主磁盘设备和 Windows ISO 安装介质一起加载到 cdrom 设备中。

$ qemu-system-x86_64 ... \
-drive file=disk_image,index=0,media=disk,if=virtio \
-drive file=windows.iso,index=2,media=cdrom \
-drive file=virtio-win.iso,index=3,media=cdrom \
...

在安装过程中,有时 Windows 安装程序会询问“您想将 Windows 安装在哪里?”,并会显示“未找到磁盘”的警告。请按照下面的示例说明进行操作(基于 Windows Server 2012 R2 Update)。

  • 选择“加载驱动程序”选项。
  • 取消勾选“隐藏与本计算机硬件不兼容的驱动程序”复选框。
  • 单击浏览按钮,打开 virtio ISO 的 CDROM,通常命名为“virtio-win-XX”。
  • 现在浏览到 E:\viostor\[your-os]\amd64,选择它,然后确认。

此时应该会在列表中看到您的 virtio 磁盘,准备好进行选择、格式化和安装。

更改现有的 Windows 虚拟机以使用 virtio

要修改现有的 Windows 客户机以从 virtio 磁盘启动,需要客户机在启动时加载 virtio 驱动程序。因此,我们需要教会 Windows 在启动时加载 virtio 驱动程序,然后才能以 virtio 模式启动磁盘映像。

为此,首先创建一个以 virtio 模式附加的新磁盘映像,并触发驱动程序搜索。

$ qemu-img create -f qcow2 dummy.qcow2 1G

运行原始 Windows 客户机,启动磁盘仍处于 IDE 模式,假磁盘处于 virtio 模式,并加载驱动程序 ISO 映像。

$ qemu-system-x86_64 -m 4G -drive file=disk_image,if=ide -drive file=dummy.qcow2,if=virtio -cdrom virtio-win.iso

Windows 将检测到假磁盘并查找合适的驱动程序。如果失败,请转到“设备管理器”,找到带有感叹号图标的 SCSI 驱动器(应已展开),单击“更新驱动程序”,然后选择虚拟 CD-ROM。不要导航到 CD-ROM 中的驱动程序文件夹,只需选择 CD-ROM 驱动器,Windows 将自动找到正确的驱动程序(已在 Windows 7 SP1 上测试)。

请求 Windows 在下次启动时以安全模式启动。这可以通过 Windows 中的 msconfig.exe 工具来完成。在安全模式下,所有驱动程序将在启动时加载,包括新的 virtio 驱动程序。一旦 Windows 知道 virtio 驱动程序在启动时是必需的,它就会记住它以供将来启动使用。

指示以安全模式启动后,您可以关闭虚拟机并重新启动它,此时启动磁盘将以 virtio 模式附加。

$ qemu-system-x86_64 -m 4G -drive file=disk_image,if=virtio

您应该会以加载了 virtio 驱动程序的状态进入安全模式,现在您可以返回 msconfig.exe 禁用安全模式启动并重新启动 Windows。

注意 如果使用 if=virtio 参数时遇到蓝屏死机,则很可能意味着 virtio 磁盘驱动程序未安装或未在启动时加载,请以安全模式重新启动并检查驱动程序配置。

网络驱动程序

使用 virtio 网络驱动程序要容易一些,只需添加 -nic 参数。

$ qemu-system-x86_64 -m 4G -drive file=windows_disk_image,if=virtio -nic user,model=virtio-net-pci -cdrom virtio-win.iso

Windows 将检测到网络适配器并尝试为其查找驱动程序。如果失败,请转到“设备管理器”,找到带有感叹号图标的网络适配器(应已展开),单击“更新驱动程序”,然后选择虚拟 CD-ROM。不要忘记选择“搜索子目录”复选框。

气球驱动程序

如果您想跟踪客户机的内存状态(例如通过 virsh 命令 dommemstat)或在运行时更改客户机的内存大小(您仍然无法更改内存大小,但可以通过膨胀气球驱动程序来限制内存使用),则需要安装客户机气球驱动程序。

为此,您需要转到“设备管理器”,在“系统设备”中找到“PCI 标准 RAM 控制器”(或“其他设备”中的未识别 PCI 控制器),然后选择“更新驱动程序”。在打开的窗口中,您需要选择“浏览我的计算机...”并选择 CD-ROM(不要忘记“包含子文件夹”复选框)。安装后重新启动。这将安装驱动程序,您将能够膨胀气球(例如通过 hmp 命令 balloon memory_size,这将导致气球尽可能多地占用内存,以便将客户机的可用内存大小缩小到 memory_size)。但是,您仍然无法跟踪客户机内存状态。为了做到这一点,您需要正确安装“Balloon”服务。为此,请以管理员身份打开命令行,转到 CD-ROM 的“Balloon”目录,然后根据您的系统和体系结构进一步深入。一旦进入 amd64x86)目录,运行 blnsrv.exe -i,它将执行安装。之后,virsh 命令 dommemstat 应该输出所有支持的值。

使用 virtiofsd 共享

在继续本节之前,请确保您已按照“使用 virtiofsd 设置主机文件共享”部分的说明进行操作。

首先,请遵循 上游说明。配置完成后,Windows 将自动映射 Z: 驱动器,其中包含共享目录的内容。

如果您的 Windows 11 客户机系统已正确配置,它将具有

  • VirtioFSSService Windows 服务,
  • WinFsp.Launcher Windows 服务,
  • Windows“设备管理器”中“系统设备”下的 VirtIO FS 设备驱动程序。

如果上述内容已安装但仍未列出 Z: 驱动器,请尝试在 Windows“添加/删除程序”中修复“Virtio-win-guest-tools”。

准备 FreeBSD 客户机

如果您使用的是 FreeBSD 8.3 或更高版本直到 10.0-CURRENT(这些版本已包含在内核中),请安装 emulators/virtio-kmod 端口。安装后,将以下内容添加到您的 /boot/loader.conf 文件中

virtio_load="YES"
virtio_pci_load="YES"
virtio_blk_load="YES"
if_vtnet_load="YES"
virtio_balloon_load="YES"

然后通过执行以下操作修改您的 /etc/fstab

# sed -ibak "s/ada/vtbd/g" /etc/fstab

并验证 /etc/fstab 是否一致。如果出现任何问题,只需引导到救援 CD 并将 /etc/fstab.bak 复制回 /etc/fstab

QEMU 监视器

在 QEMU 运行时,会提供一个监视器控制台,以便提供多种与正在运行的虚拟机进行交互的方式。QEMU 监视器提供了有趣的功能,例如获取有关当前虚拟机的信息、热插拔设备、创建虚拟机当前状态的快照等。要查看所有命令的列表,请在 QEMU 监视器控制台中运行 help?,或者查阅 官方 QEMU 文档的相应部分。

访问监视器控制台

图形视图

当使用 std 默认图形选项时,可以通过按 Ctrl+Alt+2 或在 QEMU 窗口中单击“视图 > compatmonitor0”来访问 QEMU 监视器。要返回虚拟机图形视图,请按 Ctrl+Alt+1 或单击“视图 > VGA”。

然而,访问监视器的标准方法并不总是方便,并且并非在 QEMU 支持的所有图形输出中都有效。

Telnet

要启用 telnet,请使用 -monitor telnet:127.0.0.1:port,server,nowait 参数运行 QEMU。虚拟机启动后,您可以通过 telnet 访问监视器

$ telnet 127.0.0.1 port
注意 如果指定 127.0.0.1 作为监听 IP,则只能从运行 QEMU 的同一台主机连接到监视器。如果要从远程主机连接,必须指示 QEMU 监听 0.0.0.0,如下所示:-monitor telnet:0.0.0.0:port,server,nowait。请记住,在这种情况下建议配置 防火墙,或者确保您的本地网络完全可信,因为此连接完全未经身份验证且未加密。

UNIX 套接字

使用 -monitor unix:socketfile,server,nowait 参数运行 QEMU。然后您可以使用 socatnmapopenbsd-netcat 进行连接。

例如,如果 QEMU 通过以下方式运行

$ qemu-system-x86_64 -monitor unix:/tmp/monitor.sock,server,nowait [...]

可以使用以下方式连接到监视器

$ socat - UNIX-CONNECT:/tmp/monitor.sock

或使用

$ nc -U /tmp/monitor.sock

或者使用 nmap

$ ncat -U /tmp/monitor.sock

TCP

您可以通过 -monitor tcp:127.0.0.1:port,server,nowait 参数将监视器暴露于 TCP。然后使用 openbsd-netcat 运行

$ nc 127.0.0.1 port
注意 为了能够从运行 QEMU 的同一主机以外的其他设备连接到 TCP 套接字,您需要监听 0.0.0.0,如 telnet 情况中所述。在此情况下也适用相同的安全警告。

标准 I/O

通过使用 -monitor stdio 参数运行 QEMU,可以自动从运行 QEMU 的同一终端访问监视器。

通过监视器控制台向虚拟机发送键盘按键

由于某些配置下主机可能会拦截某些组合键,因此在虚拟机上执行这些组合键可能会很困难(一个显着的例子是 Ctrl+Alt+F* 组合键,它们会更改活动 tty)。为了避免此问题,可以通过监视器控制台发送有问题的组合键。切换到监视器并使用 sendkey 命令将必要的按键转发到虚拟机。例如

(qemu) sendkey ctrl-alt-f2

通过监视器控制台创建和管理快照

注意 此功能**仅**在虚拟机磁盘映像为 qcow2 格式时才有效。它不适用于 raw 映像。

有时希望保存虚拟机的当前状态,并能够随时将虚拟机状态恢复到先前保存的快照。QEMU 监视器控制台为用户提供了创建快照、管理快照以及将机器状态恢复到已保存快照的必要工具。

  • 使用 savevm name 来创建带有标签 name 的快照。
  • 使用 loadvm name 将虚拟机恢复到快照 name 的状态。
  • 使用 delvm name 删除标签为 name 的快照。
  • 使用 info snapshots 查看已保存快照的列表。快照通过自动递增的 ID 号和文本标签(由用户在创建快照时设置)进行标识。

以不可变模式运行虚拟机

只需使用 -snapshot 参数运行 QEMU,即可在冻结状态下运行虚拟机,以便在虚拟机断电时丢弃所有更改。当客户机写入磁盘映像时,更改将保存在 /tmp 中的临时文件中,并在 QEMU 停止时丢弃。

但是,如果机器处于冻结模式运行,仍然可以将更改保存到磁盘映像(如果之后需要),方法是使用监视器控制台并运行以下命令

(qemu) commit all

如果在冻结模式下创建快照,它们将在 QEMU 退出后被丢弃,除非更改已显式提交到磁盘。

通过监视器控制台进行暂停和电源选项

QEMU 可以通过一些监视器命令来模拟物理机的一些操作

  • system_powerdown 将向虚拟机发送 ACPI 关机请求。此效果类似于物理机的电源按钮。
  • system_reset 将重置虚拟机,类似于物理机的重置按钮。此操作可能导致数据丢失和文件系统损坏,因为虚拟机未干净地重启。
  • stop 将暂停虚拟机。
  • cont 将恢复先前暂停的虚拟机。

截取虚拟机屏幕截图

可以通过在监视器控制台中运行以下命令以 PPM 格式获取虚拟机图形显示的屏幕截图

(qemu) screendump file.ppm

QEMU 机器协议

QEMU 机器协议 (QMP) 是一个基于 JSON 的协议,它允许应用程序控制 QEMU 实例。与 #QEMU 监视器类似,它提供了与运行中的机器交互的方式,并且 JSON 协议允许以编程方式进行操作。所有 QMP 命令的描述可以在 qmp-commands 中找到。

启动 QMP

通常通过 QMP 协议控制客户机的常用方法是在启动机器时使用 -qmp 选项打开一个 TCP 套接字。这里以 TCP 端口 4444 为例

$ qemu-system-x86_64 [...] -qmp tcp:localhost:4444,server,nowait

然后,与 QMP 代理通信的一种方法是使用 netcat

nc localhost 4444
{"QMP": {"version": {"qemu": {"micro": 0, "minor": 1, "major": 3}, "package": ""}, "capabilities": []} } 

此时,唯一可以识别的命令是 qmp_capabilities,这样 QMP 就可以进入命令模式。键入

{"execute": "qmp_capabilities"}

现在,QMP 准备好接收命令了,要获取已识别命令的列表,请使用

{"execute": "query-commands"}

实时合并子映像到父映像

可以通过发出 block-commit 命令将正在运行的快照合并到其父级。在其最简单的形式下,以下行会将子级提交到其父级

{"execute": "block-commit", "arguments": {"device": "devicename"}}

接收到此命令后,处理程序会查找基础映像,将其从只读模式转换为读写模式,然后运行提交作业。

一旦 block-commit 操作完成,将发出 BLOCK_JOB_READY 事件,表明同步已完成。然后可以通过发出 block-job-complete 命令来优雅地完成作业。

{"execute": "block-job-complete", "arguments": {"device": "devicename"}}

在发出此命令之前,commit 操作将保持活动状态。成功完成后,基础映像仍处于读写模式,并成为新的活动层。另一方面,子映像将失效,由用户负责清理。

提示 可以通过执行 query-block 命令并解析结果来检索设备及其名称的列表。设备名称在 device 字段中,例如本示例中硬盘的 ide0-hd0
{"execute": "query-block"}
{"return": [{"io-status": "ok", "device": "ide0-hd0", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"backing-image": {"virtual-size": 27074281472, "filename": "parent.qcow2", ... } 

实时创建新快照

要从运行中的映像创建新快照,请运行命令

{"execute": "blockdev-snapshot-sync", "arguments": {"device": "devicename","snapshot-file": "new_snapshot_name.qcow2"}}

这将创建一个名为 new_snapshot_name.qcow2 的覆盖文件,然后该文件成为新的活动层。

技巧与提示

提高虚拟机性能

有许多技术可以用来提高虚拟机的性能。例如

  • 应用 #启用 KVM 以实现完全虚拟化。
  • 使用 -cpu host 选项使 QEMU 模拟主机的确切 CPU,而不是更通用的 CPU。
  • 特别是对于 Windows 客户机,请启用 Hyper-V 增强功能-cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time。有关更多信息和标志,请参阅 QEMU 文档
  • 可以使用 -smp cores=x,threads=y,sockets=1,maxcpus=z 选项将多个核心分配给客户机。threads 参数用于分配 SMT 核心。为 QEMU、hypervisor 和主机系统留出一个物理核心以不受干扰地运行将非常有益。
  • 确保为虚拟机分配了足够的内存。默认情况下,QEMU 只为每个虚拟机分配 128 MiB 内存。使用 -m 选项分配更多内存。例如,-m 1024 运行一个具有 1024 MiB 内存的虚拟机。
  • 如果客户机操作系统中的驱动程序支持,请为网络和/或块设备使用 virtio,请参阅 #使用 virtio 驱动程序
  • 使用 TAP 设备而不是用户模式网络,请参阅 #QEMU 的 TAP 网络
  • 如果客户机操作系统正在对其磁盘进行大量写入,则您可能会从主机文件系统的某些挂载选项中受益。例如,您可以挂载一个 ext4 文件系统 并带上 barrier=0 选项。您应该阅读您更改的任何选项的文档,因为有时文件系统的性能增强选项会以数据完整性为代价。
  • 如果您有原始磁盘或分区,您可能希望禁用缓存
    $ qemu-system-x86_64 -drive file=/dev/disk,if=virtio,cache=none
  • 使用原生的 Linux AIO
    $ qemu-system-x86_64 -drive file=disk_image,if=virtio,aio=native,cache.direct=on
  • 如果您同时运行多个虚拟机,并且它们都安装了相同的操作系统,您可以通过启用 内核同页合并 (Kernel SamePage Merging) 来节省内存。请参阅 #启用 KSM
  • 在某些情况下,可以通过在客户机操作系统中运行内存气球驱动程序来从正在运行的虚拟机中回收内存。请参阅 #内存气球
  • 可以使用 ICH-9 AHCI 控制器的仿真层(尽管它可能不稳定)。AHCI 仿真支持 NCQ,因此可以同时有多个读写请求挂起。
    $ qemu-system-x86_64 -drive id=disk,file=disk_image,if=none -device ich9-ahci,id=ahci -device ide-drive,drive=disk,bus=ahci.0

有关更多信息,请参阅 https://www.linux-kvm.org/page/Tuning_KVM

将任何实际分区用作硬盘映像的单个主分区

有时,您可能希望在 QEMU 中使用您的某个系统分区。使用原始分区进行虚拟机将提高性能,因为读写操作不会通过物理主机上的文件系统层。这样的分区还提供了一种在主机和客户机之间共享数据的方式。

在 Arch Linux 中,原始分区的设备文件默认归 rootdisk 组所有。如果您希望非 root 用户能够读写原始分区,您必须将分区的设备文件的所有者更改为该用户,将该用户添加到 disk 组,或者使用 ACL 进行更精细的访问控制。

警告
  • 虽然可能,但**不建议**允许虚拟机修改主机系统上的关键数据,例如根分区。
  • 您**不得**同时在主机和客户机上以读写模式挂载一个文件系统。否则,将会导致数据损坏。

完成此操作后,您可以将该分区作为虚拟磁盘附加到 QEMU 虚拟机。

但是,如果您想让*整个*虚拟机都包含在一个分区中,事情会变得更复杂。在这种情况下,将没有实际的磁盘映像文件来引导虚拟机,因为您无法将引导加载程序安装到一个本身格式化为文件系统而不是分区设备(带有 MBR)的分区上。这样的虚拟机可以通过以下任一方式启动:#手动指定内核和 initramfs#模拟带 MBR 的虚拟磁盘#使用设备映射器#使用线性 RAID#使用网络块设备

手动指定内核和 initramfs

QEMU 支持直接加载 Linux 内核初始 RAM 文件系统,从而绕过 GRUB 等引导加载程序。然后,它可以使用包含根文件系统的物理分区作为虚拟磁盘启动,该分区不会显示为已分区。这可以通过发出类似以下的命令来完成:

注意 在此示例中,使用的是*主机*映像,而不是客户机映像。如果您想使用客户机的映像,请将 /dev/sda3 以只读方式挂载(以保护文件系统免受主机影响)并指定 /full/path/to/images,或者使用客户机中的某些 kexec 工具来重新加载客户机内核(会延长启动时间)。
$ qemu-system-x86_64 -kernel /boot/vmlinuz-linux -initrd /boot/initramfs-linux.img -append root=/dev/sda /dev/sda3

在上例中,用于客户机根文件系统的物理分区是主机上的 /dev/sda3,但在客户机中它显示为 /dev/sda

当然,您可以指定任何您想要的内核和 initramfs,而不仅仅是 Arch Linux 附带的。

当有多个 内核参数需要传递给 -append 选项时,它们需要使用单引号或双引号进行引用。例如:

... -append 'root=/dev/sda1 console=ttyS0'

模拟带 MBR 的虚拟磁盘

一种更复杂的方式是让虚拟机使用物理分区,同时将该分区格式化为文件系统,而不是让客户机像对待磁盘一样对分区进行分区,而是为其模拟一个 MBR,以便它可以使用 GRUB 等引导加载程序进行引导。

对于以下内容,假设您有一个普通的、未挂载的 /dev/hdaN 分区,上面有一个您希望作为 QEMU 磁盘映像一部分的文件系统。诀窍是动态地将主引导记录 (MBR) 前置到您希望嵌入 QEMU 原始磁盘映像中的实际分区。更一般地说,该分区可以是更大模拟磁盘的任何部分,特别是模拟原始物理磁盘但仅向虚拟机公开 /dev/hdaN 的块设备。

此类虚拟磁盘可以由包含对 MBR 副本和分区的引用的 VMDK 文件表示,但 QEMU 不支持此 VMDK 格式。例如,一个虚拟磁盘 由...创建

$ VBoxManage internalcommands createrawvmdk -filename /path/to/file.vmdk -rawdisk /dev/hda

将被 QEMU 拒绝并显示错误消息:

Unsupported image type 'partitionedDevice'

请注意,VBoxManage 会创建两个文件:file.vmdkfile-pt.vmdk,后者是 MBR 的副本,而文本文件 file.vmdk 指向它。在目标分区或 MBR 之外的读取操作将返回零,而写入的数据将被丢弃。

使用设备映射器

一种类似于使用 VMDK 描述符文件的方法是使用 设备映射器将附加到 MBR 文件的环回设备前置到目标分区。如果我们不需要我们的虚拟磁盘与原始磁盘大小相同,我们首先创建一个文件来保存 MBR:

$ dd if=/dev/zero of=/path/to/mbr count=2048

这里,创建一个 1 MiB(2048 * 512 字节)的文件,以符合现代磁盘分区工具使用的分区对齐策略。为了与旧的分区软件兼容,可能需要 63 个扇区而不是 2048 个。MBR 只需要一个 512 字节的块,额外的可用空间可用于 BIOS 引导分区,在混合分区方案中,可用于 GUID 分区表。然后,我们将一个环回设备附加到 MBR 文件:

# losetup --show -f /path/to/mbr
/dev/loop0

在此示例中,结果设备是 /dev/loop0。现在使用设备映射器将 MBR 和分区连接起来:

# echo "0 2048 linear /dev/loop0 0
2048 `blockdev --getsz /dev/hdaN` linear /dev/hdaN 0" | dmsetup create qemu

生成的 /dev/mapper/qemu 就是我们将用作 QEMU 原始磁盘映像的内容。还需要额外的步骤来创建分区表(请参阅描述线性 RAID 用法的章节以获取示例)和虚拟磁盘上的引导加载程序代码(将存储在 /path/to/mbr 中)。

以下设置是一个示例,其中 /dev/hdaN 在虚拟磁盘上的位置与在物理磁盘上的位置相同,而磁盘的其余部分将被隐藏,MBR 除外,它将作为副本提供:

# dd if=/dev/hda count=1 of=/path/to/mbr
# loop=`losetup --show -f /path/to/mbr`
# start=`blockdev --report /dev/hdaN | tail -1 | awk '{print $5}'`
# size=`blockdev --getsz /dev/hdaN`
# disksize=`blockdev --getsz /dev/hda`
# echo "0 1 linear $loop 0
1 $((start-1)) zero
$start $size linear /dev/hdaN 0
$((start+size)) $((disksize-start-size)) zero" | dmsetup create qemu

标准输入到 dmsetup 的表格式与 VBoxManage 生成的 VMDK 描述符文件中的表格式相似,也可以使用 dmsetup create qemu --table table_file 从文件中加载。对于虚拟机,只能访问 /dev/hdaN,而硬盘的其余部分读取为零并丢弃写入的数据,但第一个扇区除外。我们可以使用 dmsetup table qemu 打印 /dev/mapper/qemu 的表(使用 udevadm info -rq name /sys/dev/block/major:minormajor:minor 翻译为相应的 /dev/blockdevice 名称)。使用 dmsetup remove qemulosetup -d $loop 来删除创建的设备。

此示例有用的情况是现有的 Windows XP 安装在多重引导配置中,可能还有一个混合分区方案(在物理硬件上,Windows XP 可能是唯一使用 MBR 分区表的操作系统,而安装在同一台计算机上的更新的操作系统可以使用 GUID 分区表)。Windows XP 支持硬件配置文件,因此相同的安装可以交替地用于不同的硬件配置(在这种情况下是裸机与虚拟),而 Windows 只需为每个配置文件安装一次新检测到的硬件的驱动程序。请注意,在此示例中,复制的 MBR 中的引导加载程序代码需要更新,以便直接从 /dev/hdaN 加载 Windows XP,而不是尝试启动原始系统上存在的、支持多重引导的引导加载程序(如 GRUB)。或者,可以像 MBR 一样,将包含引导加载程序安装的分区副本包含在虚拟磁盘中。

使用线性 RAID

您还可以使用线性模式的软件 RAID(您需要 linear.ko 内核驱动程序)和环回设备来完成此操作:

首先,创建一个小的文件来保存 MBR:

$ dd if=/dev/zero of=/path/to/mbr count=32

这里创建了一个 16 KiB(32 * 512 字节)的文件。不要让它太小(即使 MBR 只需要一个 512 字节的块),这一点很重要,因为它的尺寸越小,软件 RAID 设备的块大小就必须越小,这可能会影响性能。然后,设置一个指向 MBR 文件的环回设备:

# losetup -f /path/to/mbr

假设结果设备是 /dev/loop0,因为我们还没有使用其他环回设备。下一步是使用软件 RAID 创建“合并”的 MBR + /dev/hdaN 磁盘映像:

# modprobe linear
# mdadm --build --verbose /dev/md0 --chunk=16 --level=linear --raid-devices=2 /dev/loop0 /dev/hdaN

生成的 /dev/md0 就是您将用作 QEMU 原始磁盘映像的内容(不要忘记设置权限,以便模拟器可以访问它)。最后(也是有点棘手)一步是设置磁盘配置(磁盘几何和分区表),以便 MBR 中的主分区起始点与 /dev/md0 中的 /dev/hdaN 的起始点匹配(在此示例中偏移量为 16 * 512 = 16384 字节)。使用主机上的 fdisk 来执行此操作,而不是在模拟器中:QEMU 的默认原始磁盘检测例程通常会导致非 kibibyte 可舍入的偏移量(如上一节中的 31.5 KiB),而软件 RAID 代码无法管理这些偏移量。因此,从主机:

# fdisk /dev/md0

X 进入专家菜单。设置每磁道扇区数,使一个柱面大小与您的 MBR 文件大小匹配。对于两个磁头和 512 字节的扇区大小,每磁道扇区数应为 16,因此我们得到大小为 2x16x512=16k 的柱面。

现在,按 R 返回主菜单。

P 并检查柱面大小现在是否为 16k。

现在,创建一个对应于 /dev/hdaN 的单个主分区。它应从柱面 2 开始,并在磁盘末尾结束(请注意,柱面数量现在与您进入 fdisk 时不同)。

最后,将结果*写入*文件:您已完成。现在您拥有一个可以从主机直接挂载的分区,也是 QEMU 磁盘映像的一部分。

$ qemu-system-x86_64 -hdc /dev/md0 [...]

当然,您可以安全地在此磁盘映像上使用任何引导加载程序,前提是原始 /dev/hdaN 分区包含必要的工具。

使用网络块设备

通过 网络块设备,Linux 可以使用远程服务器作为其块设备之一。您可以使用 nbd-server(来自 nbd 包)为 QEMU 创建 MBR 包装器。

假设您已经按照上述方式设置了 MBR 包装器文件,请将其重命名为 wrapper.img.0。然后在同一目录中创建一个名为 wrapper.img.1 的符号链接,指向您的分区。然后将以下脚本放在同一目录中:

#!/bin/sh
dir="$(realpath "$(dirname "$0")")"
cat >wrapper.conf <<EOF
[generic]
allowlist = true
listenaddr = 127.713705
port = 10809

[wrap]
exportname = $dir/wrapper.img
multifile = true
EOF

nbd-server \
    -C wrapper.conf \
    -p wrapper.pid \
    "$@"

.0.1 后缀是必需的;其余部分可以更改。运行上述脚本后(您可能需要以 root 身份运行它,以确保 nbd-server 能够访问该分区),您可以使用以下命令启动 QEMU:

qemu-system-x86_64 -drive file=nbd:127.713705:10809:exportname=wrap [...]

在启动时运行 QEMU 虚拟机

使用 libvirt

如果虚拟机已通过 libvirt 设置,则可以使用 virsh autostart 或通过 virt-manager GUI 配置它,以便在主机启动时启动,只需前往虚拟机的“启动选项”并选择“在主机启动时启动虚拟机”。

使用systemd服务

要使 QEMU 虚拟机在启动时运行,您可以使用以下 systemd 单元和配置。

/etc/systemd/system/qemu@.service
[Unit]
Description=QEMU virtual machine

[Service]
Environment="haltcmd=kill -INT $MAINPID"
EnvironmentFile=/etc/conf.d/qemu.d/%i
ExecStart=/usr/bin/qemu-system-x86_64 -name %i -enable-kvm -m 512 -nographic $args
ExecStop=/usr/bin/bash -c ${haltcmd}
ExecStop=/usr/bin/bash -c 'while nc localhost 7100; do sleep 1; done'

[Install]
WantedBy=multi-user.target
注意 此服务将等待控制台端口被释放,这意味着虚拟机已关闭,以进行优雅地结束。

然后创建每个 VM 的配置文件,命名为 /etc/conf.d/qemu.d/vm_name,并设置 argshaltcmd 变量。示例配置:

/etc/conf.d/qemu.d/one
args="-hda /dev/vg0/vm1 -serial telnet:localhost:7000,server,nowait,nodelay \
 -monitor telnet:localhost:7100,server,nowait,nodelay -vnc :0"

haltcmd="echo 'system_powerdown' | nc localhost 7100" # or netcat/ncat
/etc/conf.d/qemu.d/two
args="-hda /srv/kvm/vm2 -serial telnet:localhost:7001,server,nowait,nodelay -vnc :1"

haltcmd="ssh powermanager@vm2 sudo poweroff"

变量的描述如下:

  • args - 将使用的 QEMU 命令行参数。
  • haltcmd - 安全关闭虚拟机的命令。在第一个示例中,QEMU 监视器通过 telnet 使用 -monitor telnet:.. 公开,并通过发送 system_powerdown 到监视器来通过 ACPI 关闭虚拟机,使用 nc 命令。在其他示例中,使用了 SSH。

要设置将在启动时启动的虚拟机,请*启用* qemu@vm_name.service systemd 单元。

鼠标集成

要防止在单击客户机操作系统窗口时鼠标被捕获,请添加 -usb -device usb-tablet 选项。这意味着 QEMU 能够报告鼠标位置,而无需捕获鼠标。激活时,这也将覆盖 PS/2 鼠标仿真。例如:

$ qemu-system-x86_64 -hda disk_image -m 512 -usb -device usb-tablet

如果这不起作用,请尝试使用 -vga qxl 参数,还可以查看 QEMU/Troubleshooting#鼠标光标抖动或不稳定中的说明。

传递主机 USB 设备

可以从客户机访问连接到主机 USB 端口的物理设备。第一步是识别设备连接的位置,这可以通过运行 lsusb 命令找到。例如:

$ lsusb
...
Bus 003 Device 007: ID 0781:5406 SanDisk Corp. Cruzer Micro U3

上面加粗的输出将有助于分别识别 host_bushost_addrvendor_idproduct_id

在 qemu 中,目标是通过 -device usb-ehci,id=ehci-device qemu-xhci,id=xhci 选项来模拟 EHCI (USB 2) 或 XHCI (USB 1.1 USB 2 USB 3) 控制器,然后使用 -device usb-host,.. 选项将物理设备连接到它。在本节的其余部分,我们将 controller_id 视为 ehcixhci

然后,有两种方法可以使用 qemu 连接到主机的 USB:

  1. 识别设备并连接到它在主机上的任何总线和地址,通用语法是:
    -device usb-host,bus=controller_id.0,vendorid=0xvendor_id,productid=0xproduct_id
    应用于上面示例中的设备,它变为:
    -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,vendorid=0x0781,productid=0x5406
    您还可以添加 ...,port=port_number 设置到前面的选项,以指定设备应连接到虚拟控制器中的哪个物理端口,这在您想向虚拟机添加多个 USB 设备时很有用。另一种选择是使用自 QEMU 5.1.0 起可用的 usb-host 的新 hostdevice 属性,语法是:
    -device qemu-xhci,id=xhci -device usb-host,hostdevice=/dev/bus/usb/003/007
  2. 连接到给定 USB 总线和地址上的任何连接,语法是:
    -device usb-host,bus=controller_id.0,hostbus=host_bus,host_addr=host_addr
    应用于上面示例中的总线和地址,它变为:
    -device usb-ehci,id=ehci -device usb-host,bus=ehci.0,hostbus=3,hostaddr=7

有关更多信息,请参阅 QEMU/USB 仿真

注意 如果在运行 QEMU 时遇到权限错误,请参阅 udev#udev 规则简介以获取如何设置设备权限的信息。

通过 SPICE 进行 USB 重定向

当使用 #SPICE 时,可以将 USB 设备从客户端重定向到虚拟机,而无需在 QEMU 命令中指定它们。可以配置为重定向设备提供的 USB 插槽数量(插槽数量将决定可以同时重定向的设备的最大数量)。与前面提到的 -usbdevice 方法相比,使用 SPICE 进行重定向的主要优点是可以在虚拟机启动后热插拔 USB 设备,而无需停止虚拟机即可移除 USB 设备或添加新设备。这种 USB 重定向方法还允许我们将 USB 设备通过网络从客户端重定向到服务器。总之,这是在 QEMU 虚拟机中使用 USB 设备的最灵活的方法。

我们需要为每个所需的 USB 重定向插槽添加一个 EHCI/UHCI 控制器,以及每个插槽一个 SPICE 重定向通道。例如,将以下参数添加到您用于以 SPICE 模式启动虚拟机的 QEMU 命令中,将使虚拟机启动时有三个可用于重定向的 USB 插槽:

-device ich9-usb-ehci1,id=usb \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,multifunction=on \
-device ich9-usb-uhci2,masterbus=usb.0,firstport=2 \
-device ich9-usb-uhci3,masterbus=usb.0,firstport=4 \
-chardev spicevmc,name=usbredir,id=usbredirchardev1 -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \
-chardev spicevmc,name=usbredir,id=usbredirchardev2 -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \
-chardev spicevmc,name=usbredir,id=usbredirchardev3 -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3

有关更多信息,请参阅 SPICE/usbredir

来自 spice-gtkspicy输入 > 选择要重定向的 USB 设备)和来自 virt-viewerremote-viewer文件 > USB 设备选择)都支持此功能。请确保您已在虚拟机中安装了必要的 SPICE 客户机工具,以使此功能按预期工作(有关更多信息,请参阅 #SPICE 部分)。

警告 请记住,当 USB 设备从客户端重定向时,在重定向停止之前,它将无法从客户端操作系统本身使用。特别重要的是永远不要重定向输入设备(即鼠标和键盘),因为这样将难以访问 SPICE 客户端菜单来恢复情况,因为客户端在重定向到虚拟机后将不再响应输入设备。

通过 udev 自动 USB 转发

通常,必须在虚拟机启动时才能转发已连接的设备。如果该设备断开连接,它将不再被转发。

您可以使用 udev 规则在设备上线时自动附加设备。在磁盘上的某个位置创建一个 hostdev 条目。将其*所有者更改*为 root,以防止其他用户修改它。

/usr/local/hostdev-mydevice.xml
<hostdev mode='subsystem' type='usb'>
  <source>
    <vendor id='0x03f0'/>
    <product id='0x4217'/>
  </source>
</hostdev>

然后创建一个 udev 规则来附加/分离设备:

/usr/lib/udev/rules.d/90-libvirt-mydevice
ACTION=="add", \
    SUBSYSTEM=="usb", \
    ENV{ID_VENDOR_ID}=="03f0", \
    ENV{ID_MODEL_ID}=="4217", \
    RUN+="/usr/bin/virsh attach-device GUESTNAME /usr/local/hostdev-mydevice.xml"
ACTION=="remove", \
    SUBSYSTEM=="usb", \
    ENV{ID_VENDOR_ID}=="03f0", \
    ENV{ID_MODEL_ID}=="4217", \
    RUN+="/usr/bin/virsh detach-device GUESTNAME /usr/local/hostdev-mydevice.xml"

来源和进一步阅读.

启用 KSM

内核同页合并 (Kernel Samepage Merging, KSM) 是 Linux 内核的一项功能,它允许应用程序向内核注册,以便将其页面与同样注册要合并其页面的其他进程合并。KSM 机制允许虚拟机之间共享页面。在一个许多客户机操作系统相似的环境中,这可以带来显著的内存节省。

注意 虽然 KSM 可能会减少内存使用量,但它可能会增加 CPU 使用量。同时请注意,可能会出现一些安全问题,请参阅 Wikipedia:Kernel same-page merging

要启用 KSM:

# echo 1 > /sys/kernel/mm/ksm/run

要使其永久生效,请使用 systemd 的临时文件

/etc/tmpfiles.d/ksm.conf
w /sys/kernel/mm/ksm/run - - - - 1

如果 KSM 正在运行,并且有页面需要合并(即,至少有两个相似的虚拟机正在运行),那么 /sys/kernel/mm/ksm/pages_shared 应该非零。有关更多信息,请参阅 https://docs.linuxkernel.org.cn/admin-guide/mm/ksm.html

提示 要查看 KSM 性能如何的一个简单方法是简单地打印该目录中所有文件的内容:
$ grep -r . /sys/kernel/mm/ksm/

多显示器支持

Linux QXL 驱动程序默认支持四个屏幕(虚拟屏幕)。这可以通过 qxl.heads=N 内核参数进行更改。

QXL 设备的默认 VGA 内存大小为 16M(VRAM 大小为 64M)。如果您想启用两个 1920x1200 的显示器,这就不够了,因为这需要 2 × 1920 × 4(颜色深度)× 1200 = 17.6 MiB 的 VGA 内存。这可以通过将 -vga qxl 替换为 -vga none -device qxl-vga,vgamem_mb=32 来更改。如果您将 vgamem_mb 增加到 64M 以上,那么您还必须增加 vram_size_mb 选项。

自定义显示分辨率

可以使用 -device VGA,edid=on,xres=1280,yres=720 设置自定义显示分辨率(请参阅 EDID显示分辨率)。

复制和粘贴

SPICE

一种在主机和客户机之间共享剪贴板的方法是启用 SPICE 远程桌面协议,并使用 SPICE 客户端访问。需要按照 #SPICE 中描述的步骤进行。这样运行的客户机将支持与主机的复制粘贴。

qemu-vdagent

QEMU 提供了 spice vdagent chardev 的自己的实现,称为 qemu-vdagent。它与 spice-vdagent 客户机服务交互,允许客户机和主机共享剪贴板。

要使用 QEMU 的 GTK 显示访问此共享剪贴板,您需要使用 --enable-gtk-clipboard 配置参数将 QEMU 从源代码编译。替换已安装的 qemu-ui-gtk 包就足够了。

添加以下 QEMU 命令行参数:

-device virtio-serial,packed=on,ioeventfd=on
-device virtserialport,name=com.redhat.spice.0,chardev=vdagent0
-chardev qemu-vdagent,id=vdagent0,name=vdagent,clipboard=on,mouse=off

这些参数在转换为 libvirt 格式时也有效。

注意 虽然 spicevmc chardev 会自动启动客户机的 spice-vdagent 服务,但 qemu-vdagent chardev 可能不会。

在 Linux 客户机上,您可能需要手动*启动* spice-vdagent.service 用户单元。在 Windows 客户机上,将 spice-agent 的启动类型设置为自动。

Windows 特定注意事项

QEMU 可以运行从 Windows 95 到 Windows 11 的任何版本 Windows。

可以在 QEMU 中运行 Windows PE

快速启动

注意 修改电源设置需要管理员帐户。

对于 Windows 8(或更高版本)的客户机,最好在控制面板的“电源选项”中禁用“启用快速启动(推荐)”,如以下 论坛页面所述,因为它会导致客户机在每次间隔一次启动时挂起。

为正确应用对 -smp 选项的更改,也可能需要禁用快速启动。

远程桌面协议

如果您使用 MS Windows 客户机,您可能希望使用 RDP 连接到您的客户机虚拟机。如果您使用的是 VLAN 或与客户机不在同一网络,请使用:

$ qemu-system-x86_64 -nographic -nic user,hostfwd=tcp::5555-:3389

然后使用 rdesktopfreerdp 连接到客户机。例如:

$ xfreerdp -g 2048x1152 localhost:5555 -z -x lan

时间标准

默认情况下,Windows 假定固件时钟设置为本地时间,但在使用 QEMU 时通常不是这样。要解决此问题,您可以在安装后*配置 Windows 以使用 UTC*,或者通过将 -rtc base=localtime 添加到命令行来将虚拟时钟设置为 localtime。

克隆安装在物理设备上的 Linux 系统

安装在物理设备上的 Linux 系统可以被克隆并在 QEMU 虚拟机中运行。请参阅 Clone Linux system from hardware for QEMU virtual machine

从 x86_64 chroot 到 arm/arm64 环境

有时直接在磁盘映像上工作比在真正的 ARM 设备上更容易。这可以通过挂载包含*根*分区的 SD 卡/存储并 chroot 到其中来实现。

ARM chroot 的另一个用例是在 x86_64 机器上构建 ARM 软件包。在这里,chroot 环境可以从 Arch Linux ARM 的映像 tarball 创建——请参阅 [5] 了解此方法的详细说明。

无论哪种方式,在 chroot 中都应该能够运行 pacman 并安装更多软件包,编译大型库等。由于可执行文件是为 ARM 架构设计的,因此需要 QEMU 进行到 x86 的翻译。

在 x86_64 机器/主机上安装 qemu-user-static,并在 qemu-user-static-binfmt 中注册 qemu 二进制文件到 binfmt 服务。

qemu-user-static 用于允许执行编译自其他架构的程序。这类似于 qemu-emulators-full 提供的功能,但 for chroot 需要“静态”变体。示例:

qemu-arm-static path_to_sdcard/usr/bin/ls
qemu-aarch64-static path_to_sdcard/usr/bin/ls

这两行分别执行为 32 位 ARM 和 64 位 ARM 编译的 ls 命令。请注意,这在没有 chroot 的情况下将无法工作,因为它会查找主机系统中不存在的库。

qemu-user-static-binfmt 允许自动将 ARM 可执行文件加上 qemu-arm-staticqemu-aarch64-static 的前缀。

确保 ARM 可执行文件支持已激活:

$ ls /proc/sys/fs/binfmt_misc
qemu-aarch64  qemu-arm	  qemu-cris  qemu-microblaze  qemu-mipsel  qemu-ppc64	    qemu-riscv64  qemu-sh4    qemu-sparc	qemu-sparc64  status
qemu-alpha    qemu-armeb  qemu-m68k  qemu-mips	      qemu-ppc	   qemu-ppc64abi32  qemu-s390x	  qemu-sh4eb  qemu-sparc32plus	register

每个可执行文件都必须列出。

如果未激活,请*重新启动* systemd-binfmt.service

将 SD 卡挂载到 /mnt/sdcard(设备名称可能不同)。

# mount --mkdir /dev/mmcblk0p2 /mnt/sdcard

如果需要,挂载引导分区(再次,使用合适的设备名称):

# mount /dev/mmcblk0p1 /mnt/sdcard/boot

最后,按照 Change root#Using chroot 中所述,*chroot* 到 SD 卡根目录:

# chroot /mnt/sdcard /bin/bash

或者,您可以使用来自 arch-install-scriptsarch-chroot,因为它将提供一种更简单的获取网络支持的方式:

# arch-chroot /mnt/sdcard /bin/bash

您还可以使用 systemd-nspawn 来 chroot 到 ARM 环境:

# systemd-nspawn -D /mnt/sdcard -M myARMMachine --bind-ro=/etc/resolv.conf

--bind-ro=/etc/resolv.conf 是可选的,它将在 chroot 内部提供有效的网络 DNS。

chroot 中的 sudo

如果您在 chroot 中安装了 sudo 并收到以下错误:

sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?

那么您可能需要修改 binfmt 标志,例如对于 aarch64

# cp /usr/lib/binfmt.d/qemu-aarch64-static.conf /etc/binfmt.d/
# vi /etc/binfmt.d/qemu-aarch64-static.conf

并在该文件的末尾添加一个 C

:qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-aarch64-static:FPC

然后*重新启动* systemd-binfmt.service 并检查更改是否已生效(注意 flags 行上的 C):

# cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: POCF
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff

有关更多信息,请参阅 内核 binfmt 文档的“flags”部分。

不捕获鼠标输入

本文或本节需要在语言、wiki 语法或风格方面进行改进。请参阅 Help:Style 获取参考。

原因:未解释该选项的实际作用。是引起还是避免了副作用?(在 Talk:QEMU 中讨论)

平板模式具有不捕获 QEMU 窗口鼠标输入的副作用

-usb -device usb-tablet

它适用于多个 -vga 后端,其中之一是 virtio。

故障排除

请参阅 QEMU/Troubleshooting

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.