跳转至内容

QEMU

来自 ArchWiki

根据 QEMU 简介页面

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

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

安装

安装 qemu-full 软件包(或不带 GUI 的 qemu-base 版本,以及默认仅支持 x86_64 仿真的 qemu-desktop 版本),并根据您的需要安装以下可选软件包:

或者,qemu-user-static 作为一个用户模式和静态变体存在。

QEMU 变体

QEMU 提供了几种适用于不同使用场景的变体。

首先,QEMU 提供全系统和用户模式仿真两种模式。

全系统仿真
在此模式下,QEMU 仿真一个完整的系统,包括一个或多个处理器以及各种外设。它更精确但速度较慢,并且不要求被仿真操作系统必须是 Linux。
用于全系统仿真的 QEMU 命令命名为 qemu-system-目标架构,例如,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 可执行文件。可能会出现兼容性问题,例如,某些功能可能未实现,动态链接的可执行文件无法直接运行(请参阅 #从 x86_64 进入 arm/arm64 环境的 Chroot 来解决此问题),并且仅支持 Linux(尽管 Wine 可用于运行 Windows 可执行文件)。
用于用户模式仿真的 QEMU 命令命名为 qemu-目标架构,例如,qemu-x86_64 用于仿真 64 位 CPU。

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

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

在 Arch Linux 中,全系统仿真提供以下形式:

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

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

Arch Linux 中可用的软件包详情

  • qemu-desktop 软件包提供了用于全系统仿真(qemu-system-x86_64)的 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-目标架构-static,例如,用于 Intel 64 位 CPU 的 qemu-x86_64-static
注意 目前,Arch 既不官方也不通过 AUR 提供全系统模式和静态链接变体,因为这通常不需要。

QEMU 的图形前端

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

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

创建新的虚拟化系统

创建硬盘镜像

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

原因:如果我对 man 手册页的理解没错,当文件系统不支持“洞”或明确被告知预分配时,raw 格式才会分配全部大小。参见 qemu-img(1) § NOTES。(在 Talk:QEMU 中讨论)
提示 有关 QEMU 镜像的更多信息,请参阅 Wikibooks:QEMU/Images

要运行 QEMU,您需要一个硬盘镜像,除非您正在从 CD-ROM 或网络启动一个 Live 系统(并且不将操作系统安装到硬盘镜像)。硬盘镜像是一个存储仿真硬盘内容的文件

硬盘镜像可以是 raw 格式,这意味着它与客户机看到的内容在字节上完全相同,并且将始终占用主机上客户机硬盘的全部容量。此方法提供的 I/O 开销最小,但可能会浪费大量空间,因为客户机上未使用的空间无法在主机上使用。

或者,硬盘镜像可以是 qcow2 等格式,它只在客户机操作系统实际写入其虚拟硬盘上的那些扇区时才为镜像文件分配空间。即使镜像在主机系统上只占用很少的空间,它在客户机操作系统中也显示为完整大小。此镜像格式还支持 QEMU 快照功能(有关详细信息,请参阅 #通过监视器控制台创建和管理快照)。但是,使用此格式而不是 raw 可能会影响性能。

QEMU 提供了 qemu-img 命令来创建硬盘镜像。例如,要以 raw 格式创建 4 GiB 的镜像:

$ qemu-img create -f raw image_file 4G

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

注意 您也可以使用 ddfallocate(1) 创建所需大小的文件来简单地创建一个 raw 镜像。
警告 如果您将硬盘镜像存储在 Btrfs 文件系统上,您应该在创建任何镜像之前考虑禁用该目录的 写入时复制(CoW)。在创建镜像时,可以为 qcow2 格式指定 nocow 选项。
$ qemu-img create -f qcow2 image_file -o nocow=on 4G

叠加存储镜像

您可以创建一次存储镜像(“后端”镜像),并让 QEMU 将此镜像的更改保存在叠加镜像中。这允许您将存储镜像恢复到以前的状态。您可以通过在希望恢复时,基于原始后端镜像创建一个新的叠加镜像来实现恢复。

要创建叠加镜像,请发出类似以下命令:

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

之后,您可以像往常一样运行您的 QEMU 虚拟机(请参阅 #运行虚拟化系统)。

$ qemu-system-x86_64 img1.cow

后端镜像将保持不变,对该存储的更改将记录在叠加镜像文件中。

当后端镜像的路径发生变化时,需要进行修复。

警告 后端镜像的绝对文件系统路径存储在(二进制)叠加镜像文件中。更改后端镜像的路径需要一些努力。

确保原始后端镜像的路径仍然指向此镜像。如有必要,请在原始路径处创建指向新路径的符号链接。然后发出类似以下命令:

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

您可以酌情执行“不安全”的重定位,其中不检查后端镜像的旧路径:

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

调整镜像大小

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

qemu-img 可执行文件具有 resize 选项,可以轻松调整硬盘镜像的大小。它适用于 rawqcow2 格式。例如,要将镜像空间增加 10 GiB,请运行:

$ qemu-img resize disk_image +10G

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

缩小镜像

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

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

然后,要将镜像空间减小 10 GiB,请运行:

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

转换镜像

您可以使用 qemu-img convert 将镜像转换为其他格式。此示例展示了如何将 raw 镜像转换为 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 和 raw 磁盘镜像安装:

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

有关加载其他介质类型(例如软盘、磁盘镜像或物理驱动器)的更多信息,请参阅 qemu(1),有关其他有用选项,请参阅 #运行虚拟化系统

操作系统安装完成后,QEMU 镜像可以直接启动(请参阅 #运行虚拟化系统)。

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

预制虚拟机镜像

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

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

FedoraDebian 也提供了类似的镜像。

运行虚拟化系统

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 身份启动它,您应该使用 -run-with user=用户 选项使 QEMU 放弃 root 权限。

启用 KVM

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

要在 KVM 模式下启动 QEMU,请在附加启动选项中添加 -accel kvm。要检查运行中的虚拟机是否启用了 KVM,请进入 #QEMU 监视器 并输入 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#设置 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
虽然重新映射 IO(例如 使用 vfio-pci 的 PCI 直通)仍然需要添加内核参数 intel_iommu=on,但如果需要 PCI 直通,则不应设置 -device intel-iommu

在 UEFI 模式下启动

QEMU 使用的默认固件是 SeaBIOS,它是一个传统 BIOS 实现。QEMU 使用 /usr/share/qemu/bios-256k.bin(由 seabios 软件包提供)作为默认的只读 (ROM) 镜像。您可以使用 -bios 参数选择另一个固件文件。然而,UEFI 需要可写内存才能正常工作,因此您需要仿真 PC 系统闪存

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 文件中手动注册密钥的解决方法,请参阅 [2]

可信平台模块仿真

QEMU 可以仿真 可信平台模块,某些系统(例如需要 TPM 2.0 的 Windows 11)需要它。

安装 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 创建:这是一个 UNIX 套接字,QEMU 将连接到它。您可以将其放在任何目录中。

默认情况下,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 模型和拓扑选项。这可能会导致问题。

如果您想安装 Windows 11 25H2,并且安装程序声称它不识别 TPM 2.0 设备,即使您已使用 --tpm2 命令行参数启动了 swtpm,您可能使用了错误的 edk2-ovmf 安全启动 UEFI 文件组合。请确保您使用 4M 变体。

 -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2-ovmf-fedora/edk2/ovmf/OVMF_CODE_4M.secboot.fd \
 -drive if=pflash,format=raw,file=/usr/share/edk2-ovmf-fedora/edk2/ovmf/OVMF_VARS_4M.secboot.fd

另请确保将 qcow2 文件转换为 fd (raw) 格式,因为它们不随软件包提供。

 qemu-image convert -f qcow2 -O raw infile.qcow2 outfile.fd

主机与客户机之间的通信

网络

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

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

QEMU 的端口转发

注意 QEMU 的端口转发仅支持 IPv4。IPv6 端口转发尚未实现,最后一次补丁提案是在 2018 年[3]。如果您需要完整的 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

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

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

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

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

然后您可以像这样连接到虚拟机:

$ 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.随机字符串 的自动生成的 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 资源管理器中,您将转到 \\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 企业版、教育版或 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 相当慢,因为它并非专为高性能本地虚拟机使用而开发。建议用户转而研究 #使用 virtiofsd 进行主机文件共享,后者是专门为虚拟机性能而设计的。

请参阅 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#在主机上挂载镜像

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

从 raw 镜像挂载分区

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

手动指定字节偏移量

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

# mount -o loop,offset=32256 disk_image mountpoint

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

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

使用 loop 模块自动检测分区

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

  • 移除所有回环设备(卸载所有已挂载的镜像等)。
  • 卸载 loop 内核模块,并使用 max_part=15 参数重新加载。此外,回环设备的最大数量可以通过 max_loop 参数控制。
提示 您可以在 /etc/modprobe.d 中添加条目以每次加载带有 max_part=15 参数的 loop 模块,或者您可以在内核命令行上放置 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 (network block device) 协议共享磁盘镜像。

首先,我们需要加载 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 中讨论)

使用 tap 设备和网桥的虚拟网络性能应优于用户模式网络或 vde,因为 tap 设备和网桥是在内核中实现的。

此外,通过为虚拟机分配 virtio 网络设备而不是默认的 e1000 网卡仿真,可以提高网络性能。有关更多信息,请参阅 #使用 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

生成唯一的链路层地址可以通过以下几种方式完成:

  • 手动为每个网卡指定唯一的链路层地址。优点是 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 的用户模式网络。passt 相比 SLIRP 具有多项优势,例如更好的性能、完整的 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 接口的数据包将被发送到虚拟机,并显示为来自虚拟机中的网络接口(通常是以太网接口)。反之,虚拟机通过其网络接口发送的所有内容都将出现在 tap 接口上。

Linux 桥接驱动程序支持 Tap 设备,因此可以将 Tap 设备与彼此以及可能与其他主机接口(例如 eth0)桥接在一起。如果您希望虚拟机能够相互通信,或者希望局域网上的其他机器能够与虚拟机通信,这是可取的。

警告 如果您将 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

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

仅主机网络

如果网桥被赋予一个 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

尽管它有点bug,但它的性能优于 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,并分别通过 -display sdl,gl=on-display gtk,gl=on 在显示设备中启用 OpenGL 上下文,以用于 SDL 和 GTK 显示输出。可以通过查看客户机中的内核日志来确认配置是否成功。

# 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 [5]

自 QEMU 11.0 起,DRM 原生上下文也可用。用法是 -device virtio-gpu-gl,hostmem=8G,blob=on,drm_native_context=on

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 设置 TCP 端口 5930 用于 spice 通道监听,并允许客户端无需认证即可连接。
    提示 使用 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 字符设备。重要的是,virtserialport 设备的 chardev= 选项必须与 chardev 选项的 id= 选项匹配(本例中为 spicechannel0)。端口名称为 com.redhat.spice.0 也很重要,因为那是 vdagent 在访客机中查找的命名空间。最后,指定 name=vdagent 以便 Spice 知道此通道的用途。

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

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

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

对于在智能手机或其他平台上运行的客户端,请参阅 spice-space 下载“其他客户端” 部分。

手动运行 SPICE 客户端

连接到监听 Unix 套接字 /tmp/vm_spice.socket 的访客机的一种方法是根据所需的客户端,手动运行 SPICE 客户端,使用 $ remote-viewer spice+unix:///tmp/vm_spice.socket$ spicy --uri="spice+unix:///tmp/vm_spice.socket"。由于 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 客户端

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

在访客机上启用 SPICE 支持

对于 Arch Linux 访客机,为了改进多显示器支持或剪贴板共享,应安装以下软件包:

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

对于运行在其他操作系统下的访客机,请参阅 spice-space 下载 中的 “访客机” 部分。

SPICE 密码认证

如果您想在 SPICE 中启用密码认证,您需要从 -spice 参数中移除 disable-ticketing,并添加 password=您的密码。例如:

$ 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 的示例。

之后,您可以按照上述说明运行 QEMU 和 SPICE,但使用以下 -spice 参数:-spice tls-port=5901,password=您的密码,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

#Starting QEMU virtual machines on boot 部分也提供了示例。

警告 默认的 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

它们的 optional 设置在 qemu(1) 手册页中详细说明。

最起码,需要选择一个音频后端并设置一个 ID,例如 PulseAudio

-audiodev pa,id=snd0

使用音频后端

Intel HD 音频

对于 Intel HD 音频模拟,请同时添加控制器和编解码器设备。要列出可用的 Intel HDA 音频设备:

$ 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 磁盘启动,初始 ramdisk 必须包含必要的模块。默认情况下,这由 mkinitcpioautodetect 钩子处理。否则,请使用 /etc/mkinitcpio.conf 中的 MODULES 数组来包含必要的模块并重建初始 ramdisk。

/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 命令的支持,从而增强虚拟机管理程序的管理能力。

内存气球

为了让访客机的内存占用从主机的角度来看能够缩小,访客机需要向主机报告哪些页面不再需要。内核为此提供了一个名为 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 参数,使其等于 常规内存 + 内存后端文件大小。在本例中: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 新安装

驱动程序需要在安装期间加载,过程是在 CD-ROM 设备中加载包含 virtio 驱动程序的 ISO 镜像,以及主磁盘设备和 Windows ISO 安装介质。

$ 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 with Update)。

  • 选择 “加载驱动程序” 选项。
  • 取消选中 “隐藏与此计算机硬件不兼容的驱动程序” 复选框。
  • 单击“浏览”按钮,打开 virtio ISO 的 CD-ROM,通常命名为“virtio-win-XX”。
  • 现在浏览到 E:\viostor\[您的操作系统]\amd64,选择它并确认。

您现在应该会在此处看到列出的 virtio 磁盘,可以进行选择、格式化和安装。

将现有 Windows 虚拟机更改为使用 virtio

修改现有 Windows 访客机以从 virtio 磁盘启动,需要访客机在启动时加载 virtio 驱动程序。因此,在能够以 virtio 模式启动磁盘镜像之前,我们需要教 Windows 在启动时加载 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 目录,并根据您的系统和架构深入到子目录。一旦进入 amd64 (x86) 目录,运行 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 窗口中单击 “View > compatmonitor0” 来访问 QEMU 监视器。要返回虚拟机图形视图,请按 Ctrl+Alt+1 或单击 “View > VGA”

然而,访问监视器的标准方法并非总是方便,并且并非适用于 QEMU 支持的所有图形输出。

Telnet

要启用 telnet,请使用 -monitor telnet:127.0.0.1:端口,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:端口,server,nowait。请记住,在这种情况下建议配置防火墙,或确保您的本地网络完全可信,因为此连接完全未经认证且未加密。

UNIX 套接字

使用 -monitor unix:套接字文件,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:端口,server,nowait 通过 TCP 公开监视器。然后通过运行 openbsd-netcat 进行连接:

$ nc 127.0.0.1 port
注意 为了能够从运行 QEMU 的同一主机之外的其他设备连接到 TCP 套接字,您需要像 telnet 情况中解释的那样监听 0.0.0.0。在这种情况下,同样适用相同的安全警告。

标准 I/O

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

使用监视器控制台向虚拟机发送键盘按键

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

(qemu) sendkey ctrl-alt-f2

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

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

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

  • 使用 savevm 名称 来创建带有标签 名称 的快照。
  • 使用 loadvm 名称 将虚拟机恢复到快照 名称 的状态。
  • 使用 delvm 名称 删除标记为 名称 的快照。
  • 使用 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"}}

在发出此类命令之前,提交 操作仍处于活动状态。成功完成后,基础镜像保持读写模式并成为新的活动层。另一方面,子镜像变得无效,用户有责任清理它。

提示 可以通过执行命令 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"}}

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

技巧与提示

提高虚拟机性能

您可以使用多种技术来提高虚拟机的性能。例如:

  • 应用 #启用 KVM 进行完全虚拟化。
  • 使用 -cpu host 选项使 QEMU 模拟主机的精确 CPU,而不是更通用的 CPU。
  • 特别是对于 Windows 访客机,启用 Hyper-V enlightenments-cpu host,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time。有关更多信息和标志,请参阅 QEMU 文档
  • 可以使用 -smp cores=x,threads=y,sockets=1,maxcpus=z 选项为访客机分配多个核心。threads 参数用于分配 SMT 核心。为 QEMU、虚拟机管理程序和主机系统保留一个物理核心,使其不受阻碍地运行是非常有益的。
  • 确保您已为虚拟机分配足够的内存。默认情况下,QEMU 只为每个虚拟机分配 128 MiB 内存。使用 -m 选项分配更多内存。例如,-m 1024 运行一个具有 1024 MiB 内存的虚拟机。
  • 如果访客操作系统中的驱动程序支持,请为网络和/或块设备使用 virtio,请参阅 #使用 virtio 驱动程序
  • 使用 TAP 设备而不是用户模式网络,请参阅 #使用 QEMU 进行 Tap 网络
  • 如果访客操作系统正在对其磁盘进行大量写入,您可能会受益于主机文件系统上的某些挂载选项。例如,您可以挂载一个带有 barrier=0 选项的 ext4 文件系统。您应该阅读您更改的任何选项的文档,因为有时文件系统的性能增强选项会以数据完整性为代价。
  • 如果您有裸磁盘或分区,您可能需要禁用缓存:
    $ 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
  • 如果您同时运行多个安装了相同操作系统的虚拟机,可以通过启用 内核同页合并 来节省内存。请参阅 #启用 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 中,裸分区的设备文件默认由 root 用户和 disk 组拥有。如果您希望非 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 的块设备。

这种类型的虚拟磁盘可以通过 VMDK 文件表示,该文件包含对 MBR 和分区的引用(或副本),但 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 表文件 从文件中加载。对于虚拟机,只有 /dev/hdaN 可访问,而硬盘的其余部分读取为零并丢弃写入的数据,除了第一个扇区。我们可以使用 dmsetup table qemu 打印 /dev/mapper/qemu 的表(使用 udevadm info -rq name /sys/dev/block/主设备号:次设备号主设备号:次设备号 转换为相应的 /dev/块设备 名称)。使用 dmsetup remove qemulosetup -d $loop 删除创建的设备。

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

使用线性 RAID

您还可以使用线性模式的软件 RAID 和回环设备来完成此操作。

首先,您创建一些小文件来保存 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 的默认裸磁盘检测例程通常会导致非千字节可舍入的偏移量(例如,如上一节所述的 31.5 KiB),这些偏移量无法由软件 RAID 代码管理。因此,从主机:

# fdisk /dev/md0

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

现在,按 R 返回主菜单。

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

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

最后,将结果“w”写入文件:您已完成。您现在有一个可以直接从主机挂载的分区,以及 QEMU 磁盘镜像的一部分。

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

当然,您可以使用 QEMU 安全地在此磁盘镜像上设置任何引导加载程序,前提是原始的 /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
注意 此服务将等待控制台端口释放,这意味着虚拟机已关闭,以优雅地结束。

然后创建每个虚拟机的配置文件,命名为 /etc/conf.d/qemu.d/虚拟机名称,并设置变量 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:.. 暴露,并通过使用 nc 命令向监视器发送 system_powerdown,通过 ACPI 关闭虚拟机电源。在另一个示例中,使用了 SSH。

要设置哪些虚拟机将在启动时启动,请启用 qemu@虚拟机名称.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/故障排除#鼠标光标抖动或不稳定 中的说明。

直通主机 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_idehcixhci

然后,有两种方法可以用 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=端口号 设置添加到上一个选项中,以指定设备应连接到虚拟控制器的哪个物理端口,这在需要向虚拟机添加多个 USB 设备时很有用。另一个选项是使用 usb-host 的新 hostdevice 属性,该属性从 QEMU 5.1.0 开始可用,语法是:
    -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 条目。chown 它给 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

内核同页合并 (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 软件包即可。

  • 已提交功能请求 FS#79716,以在官方软件包中启用此功能。
  • 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 将虚拟时钟设置为本地时间。

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

安装在物理设备上的 Linux 系统可以克隆以在 QEMU 虚拟机上运行。请参阅 从硬件克隆 Linux 系统以用于 QEMU 虚拟机

从 x86_64 chroot 进入 arm/arm64 环境

有时,直接在磁盘镜像上工作比在真实的基于 ARM 的设备上工作更容易。这可以通过挂载包含 root 分区的 SD 卡/存储并 chroot 进入它来实现。

ARM chroot 的另一个用例是在 x86_64 机器上构建 ARM 软件包。在这种情况下,chroot 环境可以从 Arch Linux ARM 的镜像 tarball 创建——有关此方法的详细描述,请参阅 [6]

无论哪种方式,从 chroot 中应该可以运行 pacman 并安装更多软件包,编译大型库等。由于可执行文件适用于 ARM 架构,因此需要由 QEMU 执行到 x86 的转换。

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

qemu-user-static 用于允许执行来自其他架构的编译程序。这类似于 qemu-emulators-full 提供的内容,但 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#使用 chroot 中描述的方式,chroot 进入 SD 卡根目录。

# chroot /mnt/sdcard /bin/bash

或者,您可以使用 arch-install-scripts 中的 arch-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/故障排除

参见

© . 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.