> For the complete documentation index, see [llms.txt](https://handbook.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://handbook.bsdcn.org/di-25-zhang-xu-ni-hua/25.6.-qemu.md).

# 25.6.使用 FreeBSD 上的 QEMU 虚拟化

[QEMU](https://www.qemu.org/) 是一款通用的机器仿真和虚拟化工具，完全开源，由一个庞大且活跃的社区开发，支持 FreeBSD、OpenBSD 和 NetBSD 以及其他操作系统。

根据 [QEMU 文档](https://www.qemu.org/docs/master/)：

* QEMU 可以通过多种方式使用。最常见的是系统仿真模式，在该模式下，QEMU 提供了一个完整机器的虚拟模型（包括 CPU、内存和仿真设备），用于运行虚拟机操作系统。在这种模式下，CPU 可以完全仿真，也可以与如 `KVM`、`Xen` 或 `Hypervisor.Framework` 等虚拟化管理程序合作，使虚拟机直接在宿主 CPU 上运行。
* 第二种使用方式是用户模式仿真，在该模式下，QEMU 可以在一种 CPU 上启动为另一种 CPU 编译的进程。在此模式下，CPU 始终为仿真状态。
* QEMU 还提供了多个独立的命令行工具，例如 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 磁盘镜像工具，让用户能创建、转换和修改磁盘镜像。

QEMU 可以仿真多种体系结构，包括 `Arm™`、`i386`、`x86_64`、`MIPS™`、`s390X`、`SPARC™`（Sparc™ 和 Sparc64™）等。有关 QEMU 系统仿真目标的完整列表，请参阅 [QEMU 系统仿真目标](https://www.qemu.org/docs/master/system/targets.html#system-targets-ref)，该列表会定期更新。

本节介绍了如何在 FreeBSD 上使用 QEMU 实现系统仿真和用户模式仿真，并提供了 QEMU 命令和命令行工具的使用示例。

## 25.6.1. 安装 QEMU 软件

QEMU 可以通过 FreeBSD 的软件包或 Port [emulators/qemu](https://cgit.freebsd.org/ports/tree/emulators/qemu/) 安装。推荐的安装方法是使用软件包构建，因为它包含了大多数用户需要的合理选项和默认设置。

```sh
# pkg install qemu
```

安装软件包时会包含一些依赖项。安装完成后，创建一个指向宿主版本的 QEMU 链接，通常情况下如果宿主系统是 Intel™ 或 AMD™ 64 位系统，命令为：

```sh
# ln -s /usr/local/bin/qemu-system-x86_64 /usr/local/bin/qemu
```

作为非 root 用户运行以下命令来测试安装：

```sh
% qemu
```

这将打开一个窗口，QEMU 会尝试从硬盘、软盘、DVD/CD 和 PXE 引导。由于尚未设置任何引导镜像，因此命令会产生一些错误并以“No bootable device”结束，如 [图 1](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 所示。不过，这表明 QEMU 软件已正确安装。

![没有可引导镜像的 QEMU](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd01.png)

**图 1. 没有可引导镜像的 QEMU**

## 25.6.2. 虚拟机安装

> **注意**
>
> QEMU 处于非常活跃的开发中，其功能和命令选项可能在不同版本间发生变化。本节所举示例基于 QEMU 9.0.1 版本（2024 年夏季）。若有疑问，请始终查阅 [QEMU 文档](https://www.qemu.org/docs/master/)，特别是 [关于 QEMU](https://www.qemu.org/docs/master/about/index.html) 页面，该页面包含支持的构建平台、仿真、已弃用功能和已移除功能的链接。

按照以下步骤创建两个名为“**left**”和“**right**”的虚拟机。大多数命令可以在没有 root 权限的情况下执行。

1. 创建一个测试环境来与 QEMU 一起使用：

   ```sh
   % mkdir -p ~/QEMU  ~/QEMU/SCRIPTS  ~/QEMU/ISO  ~/QEMU/VM
   ```

   **SCRIPTS** 目录用于存放启动脚本和实用工具。**ISO** 目录用于存放客户机 ISO 引导镜像。**VM** 目录是虚拟机镜像（`VMs`）的存放位置。
2. 将最新的 FreeBSD 下载到 **\~/QEMU/ISO** 目录中：

   ```sh
   % cd ~/QEMU/ISO
   % fetch https://download.freebsd.org/releases/ISO-IMAGES/14.1/FreeBSD-14.1-RELEASE-amd64-bootonly.iso
   ```

   下载完成后，创建一个简短的链接。该简短链接将在下面的启动脚本中使用。

   ```sh
   % ln -s FreeBSD-14.1-RELEASE-amd64-bootonly.iso  fbsd.iso
   ```
3. 切换到虚拟机存放位置（**\~/QEMU/VM**）。运行 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 来为“left”虚拟机创建磁盘镜像：

   ```sh
   % cd ~/QEMU/VM
   % qemu-img create -f raw  left.img   15G
   ```

   QEMU `raw` 格式旨在提供最佳性能。该格式简单且没有开销，特别适用于高性能或高吞吐量的场景。此格式适用于对性能要求最大化且不需要额外功能（如快照）的情况。以下脚本中使用了此格式来创建“left”虚拟机的磁盘镜像。

   另一种格式是 `qcow2`，它使用 QEMU 的“写时复制”技术来管理磁盘空间。这种技术不需要完整的 15G 磁盘，而是直接由虚拟机管理一个简版磁盘，随着虚拟机写入，磁盘大小会动态增长。此格式支持快照、压缩和加密。此格式适用于开发、测试及需要这些高级功能的场景。下面的“right”虚拟机脚本使用了此格式。

   再次运行 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 来为“right”虚拟机创建一个 `qcow2` 格式的磁盘镜像：

   ```sh
   % qemu-img create -f qcow2 -o preallocation=full,cluster_size=512K,lazy_refcounts=on right.qcow2 20G
   ```

   要查看实际文件大小，可以使用：

   ```sh
   % du -Ah right.qcow2
   ```
4. 使用以下命令为两个虚拟机配置网络。在此示例中，宿主网络接口是 `em0`。如果有必要，请修改为宿主系统的接口。每次宿主机重启后必须执行这些命令，以便 QEMU 客户机虚拟机能通信。

   ```sh
   # ifconfig tap0 create
   # ifconfig tap1 create
   # sysctl net.link.tap.up_on_open=1
   net.link.tap.up_on_open: 0 -> 1
   # sysctl net.link.tap.user_open=1
   net.link.tap.user_open: 0 -> 1
   # ifconfig bridge0 create
   # ifconfig bridge0 addm tap0 addm tap1 addm em0
   # ifconfig bridge0 up
   ```

   上述命令创建了两个 [tap(4)](https://man.freebsd.org/cgi/man.cgi?query=tap\&sektion=4\&format=html) 设备（`tap0`、`tap1`）和一个 [if\_bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=if_bridge\&sektion=4\&format=html) 设备（`bridge0`）。接着，它们将 `tap` 设备和本地宿主接口（`em0`）添加到桥接中，并设置了两个 [sysctl(8)](https://man.freebsd.org/cgi/man.cgi?query=sysctl\&sektion=8\&format=html) 项目，让普通用户能打开 tap 设备。这些命令使虚拟机能与宿主的网络栈通信。
5. 切换到 **\~/QEMU/SCRIPTS** 目录，使用以下脚本启动第一个虚拟机“left”。该脚本使用了 QEMU 的 `raw` 磁盘格式。

   ```sh
   /usr/local/bin/qemu-system-x86_64  -monitor none \
     -cpu qemu64 \
     -vga std \
     -m 4096 \
     -smp 4   \
     -cdrom ../ISO/fbsd.iso \
     -boot order=cd,menu=on \
     -blockdev driver=file,aio=threads,node-name=imgleft,filename=../VM/left.img \
     -blockdev driver=raw,node-name=drive0,file=imgleft \
     -device virtio-blk-pci,drive=drive0,bootindex=1  \
     -netdev tap,id=nd0,ifname=tap0,script=no,downscript=no,br=bridge0 \
     -device e1000,netdev=nd0,mac=02:20:6c:65:66:74 \
     -name \"left\"
   ```

> **技巧**
>
> 将上述内容保存到一个文件中（例如 **left.sh**），并运行：% `/bin/sh left.sh`

QEMU 将在一个单独的窗口中启动虚拟机，并按 [图 2](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 中所示引导 FreeBSD ISO。所有命令选项，如 `-cpu` 和 `-boot`，均在 QEMU 的手册页 [qemu(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu\&sektion=1\&format=html) 中有详细说明。

![FreeBSD 引导加载菜单](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd02.png)

**图 2. FreeBSD 引导加载菜单**

> **技巧**
>
> 如果在 QEMU 控制台窗口中点击鼠标，QEMU 将“抓取”鼠标，如 [图 3](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 所示。按 Ctrl+Alt+G 可以释放鼠标。

![当 QEMU 抓取鼠标时](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd03.png)

**图 3. 当 QEMU 抓取鼠标时**

> **注意**
>
> 在 FreeBSD 上，在 QEMU 中首次安装系统可能会稍慢。这是因为模拟器在第一次使用磁盘时会写入文件系统格式和元数据。随后的操作通常会更快。

安装过程中有几个需要注意的要点：

* 选择使用 UFS 作为文件系统。ZFS 在小内存的环境下性能不佳。
* 网络配置使用 DHCP。如果本地局域网支持，也可以配置 IPv6。
* 在添加默认用户时，请确保该用户是 **wheel** 组的成员。

安装完成后，虚拟机将重启并进入新安装的 FreeBSD 镜像。

以 `root` 用户登录并按以下方式更新系统：

```sh
# freebsd-update fetch
# freebsd-update install
# shutdown -r now
```

> **注意**
>
> 安装成功后，QEMU 将引导已安装的操作系统，而不是安装程序。

> **注意**
>
> QEMU 支持 `-runas` 选项。为增加安全性，可以在上述脚本中添加“-runas user\_name”选项。详情请参见 [qemu(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu\&sektion=1\&format=html)。 再次以 `root` 用户登录，添加所需的任何软件包。若要在客户机中使用 X Window 系统，请参阅下文的“使用 X Window 系统”部分。

至此，“left”虚拟机的安装完成。

要安装“right”虚拟机，请运行以下脚本。此脚本包含了 tap1、`qcow2` 格式、镜像文件名、MAC 地址和终端窗口名的修改。如果需要，可以按照上述说明添加“-runas”参数。

```sh
/usr/local/bin/qemu-system-x86_64  -monitor none \
  -cpu qemu64 \
  -vga cirrus \
  -m 4096  -smp 4   \
  -cdrom ../ISO/fbsd.iso \
  -boot order=cd,menu=on \
  -drive if=none,id=drive0,cache=writeback,aio=threads,format=qcow2,discard=unmap,file=../VM/right.qcow2 \
  -device virtio-blk-pci,drive=drive0,bootindex=1  \
  -netdev tap,id=nd0,ifname=tap1,script=no,downscript=no,br=bridge0 \
  -device e1000,netdev=nd0,mac=02:72:69:67:68:74 \
  -name \"right\"
```

安装完成后，“left”和“right”虚拟机可以相互通信，并与宿主通信。如果宿主机上有严格的防火墙规则，考虑添加或修改规则以允许桥接和 tap 设备之间的通信。

## 25.6.3. 使用提示

### 25.6.3.1. 使用 X Window 系统

[安装 Xorg](/di-5-zhang-xwindow-xi-tong/5.4.-an-zhuang-xorg-fu-wu-qi.md) 说明了如何设置 `X Window` 系统。请参考该指南完成初始 `X Window` 设置，然后查阅 [桌面环境](/di-8-zhang-zhuo-mian-huan-jing/8.1.-gai-shu.md) 以了解如何设置完整的桌面环境。

本节演示了 XFCE 桌面环境的使用。

安装完成后，以普通用户身份登录，然后输入：

```sh
% startx
```

XFCE4 窗口管理器将启动并呈现一款功能齐全的图形桌面，如 [图 4](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 所示。首次启动时，可能需要一分钟才能显示桌面。有关使用详细信息，请参阅 [XFCE 网站](https://www.xfce.org/)。

![两个 QEMU 虚拟机](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd04.png)

图 4. 两个 QEMU 虚拟机

> **技巧**
>
> 为虚拟机添加更多内存可提升图形界面的响应速度。

在这里，“left”虚拟机已经安装了 `X Window` 系统，而“right”虚拟机仍处于文本模式。

### 25.6.3.2. 使用 QEMU 窗口

QEMU 窗口是完整的 FreeBSD 控制台，能像裸机系统一样运行多个虚拟终端。

要切换到另一个虚拟控制台，单击 QEMU 窗口并输入 **Alt**+**F2** 或 **Alt**+**F3**。FreeBSD 应该会切换到另一个虚拟控制台。[图 5](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了“left”虚拟机在 `ttyv3` 上显示虚拟控制台的情况。

![在 QEMU 窗口中切换到另一个虚拟控制台](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd05.png)

**图 5. 在 QEMU 窗口中切换到另一个虚拟控制台**

> **技巧**
>
> 当前主机桌面管理器或窗口管理器可能已经为 **Alt**+**F1**、**Alt**+**F2** 键序列设置了其他功能。如果是这样，请尝试输入 **Ctrl**+**Alt**+**F1**、**Ctrl**+**Alt**+**F2**，或其他类似的键组合。查看窗口管理器或桌面管理器文档以了解详细信息。

### 25.6.3.3. 使用 QEMU 窗口菜单

QEMU 窗口的另一个功能是 `View` 菜单和缩放控制。最有用的是 `Zoom to Fit`。当点击此菜单项时，点击窗口角部控制并调整窗口大小即可调整 QEMU 窗口的大小。[图 6](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了在图形模式下调整“left”窗口大小的效果。

![使用视图菜单中的 Zoom to Fit 选项](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd06.png)

**图 6. 使用视图菜单中的 `Zoom to Fit` 选项**

### 25.6.3.4. 其他 QEMU 窗口菜单选项

在 `View` 菜单中，还可以看到以下选项：

* `cirrus-vga`、`serial0` 和 `parallel0` 选项。这些选项能切换输入/输出到选定设备。

QEMU 窗口中的 `Machine` 菜单提供了对虚拟机的四种控制：

* `Pause` 可暂停 QEMU 虚拟机。这可能对冻结快速滚动的窗口有帮助。
* `Reset` 会立即将虚拟机重置为冷引导状态。与实际机器一样，除非绝对必要，否则不建议使用此选项。
* `Power Down` 模拟 ACPI 关闭信号，操作系统将执行优雅关闭。
* `Quit` 会立即关闭虚拟机电源 — 同样，除非必要，否则不建议使用此选项。

## 25.6.4. 向虚拟机添加串行端口接口

为实现串行控制台，需要在运行 FreeBSD 的虚拟机中插入以下内容：

```sh
console="comconsole"
```

将此行添加到 **/boot/loader.conf** 文件中，以启用 FreeBSD 串行控制台。

以下更新后的配置演示了如何在虚拟机上实现串行控制台。运行脚本以启动虚拟机。

```sh
# left+serial.sh
echo
echo "注意: telnet 启动服务器正在虚拟机上运行!"
echo "要启动 QEMU，请启动另一个会话并通过 telnet 连接到 localhost 的 4410 端口"
echo

/usr/local/bin/qemu-system-x86_64  -monitor none \
  -serial telnet:localhost:4410,server=on,wait=on\
  -cpu qemu64 \
  -vga std \
  -m 4096 \
  -smp 4   \
  -cdrom ../ISO/fbsd.iso \
  -boot order=cd,menu=on \
  -blockdev driver=file,aio=threads,node-name=imgleft,filename=../VM/left.img \
  -blockdev driver=raw,node-name=drive0,file=imgleft \
  -device virtio-blk-pci,drive=drive0,bootindex=1  \
  -netdev tap,id=nd0,ifname=tap0,script=no,downscript=no,br=bridge0 \
  -device e1000,netdev=nd0,mac=02:20:6c:65:66:74 \
  -name \"left\"
```

![通过 TCP 启用串行端口](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd07.png)

**图 7. 通过 TCP 启用串行端口**

在 [图 7](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 中，串行端口重定向到主机系统的 TCP 端口，并且 QEMU 监视器等待（`wait=on`）以激活虚拟机，直到在指定的 localhost 端口发生 [telnet(1)](https://man.freebsd.org/cgi/man.cgi?query=telnet\&sektion=1\&format=html) 连接。当收到来自另一个会话的连接时，FreeBSD 系统开始引导并查找 **/boot/loader.conf** 中的控制台指令。通过设置“console=comconsole”，FreeBSD 在串行端口上启动一个控制台会话。QEMU 监视器会检测到这一点，并将该串行端口的字符 I/O 导向主机上的 telnet 会话。系统引导完成后，登录提示将在串行端口（`ttyu0`）和控制台（`ttyv0`）上启用。

需要注意的是，这种通过 TCP 的串行重定向发生在虚拟机之外。它不与虚拟机中的任何网络交互，因此不受任何防火墙规则的限制。可以将其视为连接到实际机器的 RS-232 或 USB 端口的哑终端。

### 25.6.4.1. 使用串行控制台的注意事项

在串行控制台上，如果调整了窗口大小，可以执行 [resizewin(1)](https://man.freebsd.org/cgi/man.cgi?query=resizewin\&sektion=1\&format=html) 来更新终端大小。

有时可能需要（甚至必须）停止将 syslog 消息发送到控制台（包括 QEMU 控制台和串行端口）。有关将控制台消息重定向到其他位置的详细信息，请参考 [syslog.conf(5)](https://man.freebsd.org/cgi/man.cgi?query=syslog.conf\&sektion=5\&format=html)。

> **注意**
>
> **/boot/loader.conf** 更新为使用串行控制台后，虚拟机将在每次引导时尝试从串行端口引导。请确保如上所示启用串行端口，或者修改 **/boot/loader.conf** 以取消串行控制台的使用。

## 25.6.5. QEMU 用户模式仿真

QEMU 还支持在与主机 CPU 架构不同的体系结构上运行预编译的应用程序。例如，可以在 `x86_64` 主机上运行 Sparc64 架构的操作系统。下一节将展示这一过程。

### 25.6.5.1. 在 `x86_64` 主机上设置 SPARC64 虚拟机

设置与主机架构不同的新虚拟机涉及以下几个步骤：

* 获取将在虚拟机上运行的软件
* 为虚拟机创建一个新的磁盘镜像
* 设置一个新 QEMU 脚本，指定新的架构
* 执行安装

以下过程使用了 OpenBSD 6.8 SPARC64 软件作为本次 QEMU 用户模式仿真练习的示例。

> **注意**
>
> 并非所有版本的 OpenBSD Sparc64 都能在 QEMU 上运行。已知 OpenBSD 版本 6.8 可用，因此作为本节示例。

1. 从 OpenBSD 存档中下载 OpenBSD 6.8 Sparc64。 在 OpenBSD 下载站点上，仅保留最新版本，需要访问存档以获取过去的版本。

   ```sh
   % cd ~/QEMU/ISO
   % fetch https://mirror.planetunix.net/pub/OpenBSD-archive/6.8/sparc64/install68.iso
   ```
2. 为 Sparc64 虚拟机创建新的磁盘镜像，这与上面的“right”虚拟机创建方法类似。在本例中使用 QEMU 的 qcow2 格式：

   ```sh
   % cd ~/QEMU/VM
   qemu-img create -f qcow2 -o preallocation=full,lazy_refcounts=on sparc64.qcow2 16G
   ```
3. 使用以下脚本设置新的 Sparc64 架构。与上面的示例一样，运行该脚本，然后启动一个新的会话并通过 `telnet` 连接到 localhost 上指定的端口：

   ```sh
   echo
   echo "注意: telnet 启动服务器正在虚拟机上运行!"
   echo "要启动 QEMU，请启动另一个会话并通过 telnet 连接到 localhost 端口 4410"
   echo

   /usr/local/bin/qemu-system-sparc64 \
     -serial telnet:localhost:4410,server=on,wait=on \
     -machine sun4u,usb=off \
     -smp 1,sockets=1,cores=1,threads=1 \
     -rtc base=utc \
     -m 1024 \
     -boot d \
     -drive file=../VM/sparc64.qcow2,if=none,id=drive-ide0-0-1,format=qcow2,cache=none \
     -cdrom ../ISO/install68.iso \
     -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-1,id=ide0-0-1 \
     -msg timestamp=on \
     -net nic,model=sunhme -net user \
     -nographic \
     -name \"sparc64\"
   ```

注意以下几点：

* `-boot d` 选项使 QEMU 从设置为 `-cdrom ../ISO/install68.iso` 的 QEMU CDROM 设备引导。
* 如前所述，`telnet` 服务器选项设置为等待在端口 4410 上接收连接。启动另一个会话并使用 [telnet(1)](https://man.freebsd.org/cgi/man.cgi?query=telnet\&sektion=1\&format=html) 连接到 localhost 上的 4410 端口。
* 该脚本设置了 `-nographic` 选项，意味着只有串行端口 I/O，没有图形界面。
* 本例中网络未通过 [tap(4)](https://man.freebsd.org/cgi/man.cgi?query=tap\&sektion=4\&format=html) / [if\_bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=if_bridge\&sektion=4\&format=html) 组合设置。这里使用了 QEMU 网络的另一种方法，称为“串行线互联网协议”（SLIRP），有时也称为“用户模式网络”。有关该方法及其他 QEMU 网络方法的文档，请参见 [QEMU 网络文档](https://wiki.qemu.org/Documentation/Networking)

如果一切设置正确，系统将引导，如 [图 8](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 所示。

![QEMU 在用户模式仿真中从 CDROM 引导 OpenBSD 6.8 Sparc64](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd08.png)

**图 8. QEMU 在用户模式仿真中从 CDROM 引导 OpenBSD 6.8 Sparc64**

安装完成后，修改脚本并将引导参数更改为 `-boot c`。这将指示 QEMU 从提供的硬盘引导，而不是 CDROM。

安装后的系统可以像其他虚拟机一样使用。然而，虚拟机的底层架构是 Sparc64，而非 `x86_64`。

> **技巧**
>
> 如果系统在 OpenBios 控制台提示 `0 >` 时停止，请输入 `power-off` 来退出系统。

[图 9](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了登录已安装系统的 root 用户并运行 [uname(1)](https://man.freebsd.org/cgi/man.cgi?query=uname\&sektion=1\&format=html)。

![在用户模式仿真中从 CDROM 引导 QEMU](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd09.png)

**图 9. 在用户模式仿真中从 CDROM 引导 QEMU**

## 25.6.6. 使用 QEMU 监控器

[QEMU 监控器](https://www.qemu.org/docs/master/system/monitor.html) 用于控制正在运行的 QEMU 模拟器（虚拟机）。

通过使用监控器，可以：

* 动态地移除或插入设备，包括磁盘、网络接口、CD-ROM 或软盘
* 冻结/解冻虚拟机，并将其状态保存或恢复到磁盘文件中
* 收集有关虚拟机和设备状态的信息
* 实时更改设备设置

以及许多其他操作。

监控器的最常见用途是检查虚拟机的状态，并添加、删除或更改设备。一些操作，如迁移，仅在支持的虚拟化加速器（如 KVM、Xen 等）下可用，在 FreeBSD 主机上不受支持。

在使用图形桌面环境时，最简单的使用 QEMU 监控器的方法是启动 QEMU 时使用 `-monitor stdio` 选项。

```sh
# /usr/local/bin/qemu-system-x86_64  -monitor stdio \
  -cpu qemu64 \
  -vga cirrus \
  -m 4096  -smp 4   \
  ...
```

这将在终端窗口中生成一个新的提示符 `(qemu)`，如 [图 10](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 所示。

![QEMU 监控器提示符和 stop 命令](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd13.png)

**图 10. QEMU 监控器提示符和“stop”命令**

图中还显示了在 FreeBSD 引导序列中使用 `stop` 命令冻结系统。系统将保持冻结状态，直到在监控器中输入 `cont` 命令。

### 25.6.6.1. 向虚拟机添加新磁盘

要向运行中的虚拟机添加新磁盘，首先需要准备磁盘，如下所示：

```sh
% cd ~/QEMU/VM
% qemu-img create -f raw  new10G.img  10G
```

[图 11](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了向虚拟机添加新磁盘所需的监控器命令序列。使用监控器中的 `device_add` 命令添加设备后，它将在 FreeBSD 系统控制台中显示（图中的下半部分）。此时可以根据需要配置磁盘。

请注意，如果需要在虚拟机重启后使用新磁盘，必须将其添加到启动脚本中。

![使用 QEMU 监控器命令添加新磁盘](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd14.png)

**图 11. 使用 QEMU 监控器命令添加新磁盘**

### 25.6.6.2. 使用 QEMU 监控器管理快照

QEMU 文档在使用术语 **快照** 时说明了几个类似的概念。命令行上有 `-snapshot` 选项，它指的是使用一个磁盘或磁盘的一部分来包含设备的副本。然后是监控器命令 `snapshot_blkdev` 和 `snapshot_blkdev_internal`，它们说明了实际的复制块设备的操作。最后，还有监控器命令 `savevm`、`loadvm` 和 `delvm`，它们指的是创建并保存、加载或删除整个虚拟机的副本。结合后者，监控器的 `info snapshots` 命令列出了最近的快照详情。

本节将重点介绍创建、保存和加载完整的虚拟机镜像，并使用 **快照** 这一术语。

首先，从头开始重新创建“left”虚拟机，这次使用 `qcow2` 格式。

```sh
% cd ~/QEMU/VM
% rm left.img
% qemu-img create -f qcow2 left.qcow2 16G  # 为新的 FreeBSD 安装创建一个清理的文件。
% cd ../SCRIPTS
# /bin/sh left.sh                     # 参见下面的程序清单。
```

安装完成后，重新启动虚拟机，这次使用 `-monitor stdio` 选项来启用监控器。

```sh
# 左虚拟机脚本.
/usr/local/bin/qemu-system-x86_64  -monitor stdio \
  -cpu qemu64 \
  -vga std \
  -m 4096 \
  -smp 4   \
  -cdrom ../ISO/fbsd.iso \
  -boot order=cd,menu=on \
  -blockdev driver=file,aio=threads,node-name=imgleft,filename=../VM/left.qcow2 \
  -blockdev driver=qcow2,node-name=drive0,file=imgleft \
  -device virtio-blk-pci,drive=drive0,bootindex=1  \
  -netdev tap,id=nd0,ifname=tap0,script=no,downscript=no,br=bridge0 \
  -device e1000,netdev=nd0,mac=02:20:6c:65:66:74 \
  -name \"left\"
```

为了演示快照，可以使用以下步骤：

1. 从头安装 FreeBSD
2. 准备环境并使用 `savevm` 监控器命令创建快照
3. 安装几个软件包
4. 关闭系统
5. 重新启动一个裸 QEMU 实例，并使用监控器命令 `loadvm` 恢复虚拟机
6. 观察恢复后的虚拟机没有安装任何软件包

在“准备环境”步骤中，在一个独立的虚拟控制台（ttyv1）中启动一个 [vi(1)](https://man.freebsd.org/cgi/man.cgi?query=vi\&sektion=1\&format=html) 编辑会话，模拟用户活动。如果需要，可以启动其他程序。快照应该记录在创建快照时所有正在运行的应用程序的状态。

[图 12](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了全新安装的 FreeBSD 系统，尚未安装任何软件包，并且在 ttyv1 上单独显示了编辑会话。当前， [vi(1)](https://man.freebsd.org/cgi/man.cgi?query=vi\&sektion=1\&format=html) 编辑器处于 `insert` 模式，打字员正在输入“broadcast”一词。

![第一次快照之前的 QEMU 虚拟机](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd15.png)

**图 12. 第一次快照之前的 QEMU 虚拟机**

要生成快照，请在监控器中输入 `savevm`。确保为其指定标签（例如 `original_install`）。

```sh
QEMU 9.0.1 monitor - type 'help' for more information
(qemu)
(qemu) savevm original_install
```

接下来，在主控制台窗口中安装一个软件包，例如没有依赖关系的 [zip(1)](https://man.freebsd.org/cgi/man.cgi?query=zip\&sektion=1\&format=html)。完成后，重新进入监控器并创建另一个快照（`snap1_pkg+zip`）。

[图 13](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 显示了上述命令的结果以及 `info snapshots` 命令的输出。

![使用监控器命令创建快照](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd16.png)

**图 13. 使用监控器命令创建快照**

重新启动系统，在 FreeBSD 引导之前，切换到监控器并输入 `stop`。虚拟机将停止。

输入 `loadvm` 和之前使用的标签（此处为 `original_install`）。

```sh
QEMU 9.0.1 monitor - type 'help' for more information
(qemu) stop
(qemu) loadvm original_install
(qemu) cont
```

立即，虚拟机屏幕将切换到执行 `savevm` 命令时的准确时刻。请注意，虚拟机仍然处于停止状态。

输入 `cont` 启动虚拟机，切换到 `ttyv1` 上的编辑会话，并在键盘上输入一个字母。编辑器仍然处于插入模式，应该相应地响应。快照时运行的任何其他程序应该没有受到影响。

上述步骤展示了如何创建快照、修改系统，然后通过恢复之前的快照来“回滚”。

默认情况下，QEMU 将快照数据存储在与镜像相同的文件中。使用 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 查看快照列表，如下所示，见 [图 14](/di-25-zhang-xu-ni-hua/25.6.-qemu.md)。

![使用 qemu-img 检查快照](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd17.png)

**图 14. 使用** [**qemu-img(1)**](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) **检查快照**

## 25.6.7. 使用 QEMU USB 设备

QEMU 支持创建虚拟 USB 设备，这些设备由镜像文件提供支持。它们是虚拟 USB 设备，可以像真实 USB 设备一样分区、格式化、挂载和使用。

```sh
/usr/local/bin/qemu-system-x86_64  -monitor stdio \
  -cpu qemu64 \
  -vga cirrus \
  -m 4096  -smp 4   \
  -cdrom ../ISO/fbsd.iso \
  -boot order=cd,menu=on \
  -drive if=none,id=usbstick,format=raw,file=../VM/foo.img \
  -usb \
  -device usb-ehci,id=ehci \
  -device usb-storage,bus=ehci.0,drive=usbstick \
  -device usb-mouse \
  -blockdev driver=file,node-name=img1,filename=../VM/right.qcow2 \
  -blockdev driver=qcow2,node-name=drive0,file=img1 \
  -device virtio-blk-pci,drive=drive0,bootindex=1  \
  -netdev tap,id=nd0,ifname=tap1,script=no,downscript=no,br=bridge0 \
  -device e1000,netdev=nd0,mac=02:72:69:67:68:74 \
  -name \"right\"
```

此配置包括一个 `-drive` 规范，指定了 `id=usbstick`、raw 格式和一个镜像文件（必须使用 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 创建）。下一行包含 `-device usb-ehci` 规范，指定一个 USB EHCI 控制器，并指定 `id=ehci`。最后，`-device usb-storage` 规范将上述驱动与 EHCI USB 总线连接起来。

当系统引导时，FreeBSD 会识别到一个 USB 集线器，添加附加的 USB 设备，并将其分配为 `da0`，如图 15 所示。

![QEMU 创建的 USB 集线器和大容量存储设备](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd12.png)

**图 15. QEMU 创建的 USB 集线器和大容量存储设备**

该设备已准备好，可以使用 [gpart(8)](https://man.freebsd.org/cgi/man.cgi?query=gpart\&sektion=8\&format=html) 分区，并使用 [newfs(8)](https://man.freebsd.org/cgi/man.cgi?query=newfs\&sektion=8\&format=html) 格式化。由于 USB 设备由 [qemu-img(1)](https://man.freebsd.org/cgi/man.cgi?query=qemu-img\&sektion=1\&format=html) 创建的文件提供支持，写入设备的数据会在重启后保留。

## 25.6.8. 通过直通使用主机 USB 设备

QEMU USB 直通支持在 9.0.1 版本（2024 年夏季）中列为实验性功能。以下步骤展示了虚拟机如何使用挂载在主机上的 USB 闪存驱动器。

更多信息和示例，请参见：

* <https://www.qemu.org/docs/master/system/devices/usb.html>

[图 16](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 的上部分显示了 QEMU 监视器命令：

* `info usbhost` 显示主机系统上所有 USB 设备的信息。找到所需的 USB 设备并记下该行中的两个十六进制值。（在下面的示例中，主机 USB 设备是 Memorex Mini，vendorid 为 0718，productid 为 0619。）在下面的 `device_add` 步骤中使用 `info usbhost` 命令显示的两个值。
* `device_add` 将 USB 设备添加到虚拟机。

![QEMU 监视器命令访问主机上的 USB 设备](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd18.png)

**图 16. QEMU 监视器命令访问主机上的 USB 设备**

如前所述，`device_add` 完成后，FreeBSD 内核会识别到新的 USB 设备，如图下部分所示。

在 [图 17](/di-25-zhang-xu-ni-hua/25.6.-qemu.md) 中，展示了如何使用新设备。

![通过直通使用主机的 USB 设备](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd19.png)

**图 17. 通过直通使用主机的 USB 设备**

如果 USB 设备格式化为 FAT16 或 FAT32 文件系统，则可以使用 [mount\_msdosfs(8)](https://man.freebsd.org/cgi/man.cgi?query=mount_msdosfs\&sektion=8\&format=html) 将其挂载为 MS-DOS™ 文件系统，如示例所示。然后将 **/etc/hosts** 文件复制到新挂载的驱动器上，并对文件校验以验证其完整性。然后使用 [umount(8)](https://man.freebsd.org/cgi/man.cgi?query=umount\&sektion=8\&format=html) 卸载设备。

如果 USB 设备格式化为 NTFS，则需要安装 `fusefs-ntfs` 包并使用 [ntfs-3g(8)](https://man.freebsd.org/cgi/man.cgi?query=ntfs-3g\&sektion=8\&format=html) 访问该设备：

```sh
# pkg install fusefs-ntfs
# kldload fusefs
# gpart show da1
# ntfs-3g /dev/da1s1 /mnt

按需访问驱动器。完成后：

# umount /mnt
```

根据实际硬件修改上述设备标识符。有关 NTFS 文件系统操作的更多信息，请参阅 [ntfs-3g(8)](https://man.freebsd.org/cgi/man.cgi?query=ntfs-3g\&sektion=8\&format=html)。

## 25.6.9. QEMU 在 FreeBSD 上的总结

如上所述，QEMU 支持多种不同的虚拟化加速器。

QEMU 支持的 [虚拟化加速器](https://www.qemu.org/docs/master/system/introduction.html#virtualisation-accelerators) 包括：

* 在 Linux 上支持 64 位 Arm、MIPS、PPC、RISC-V、s390x 和 x86 的 `KVM`
* 在 Linux 上作为 dom0 支持 Arm、x86 的 `Xen`
* 在 MacOS 上支持 x86 和 Arm（仅 64 位）的 `Hypervisor Framework (hvf)`
* 在 Windows 上支持 x86 的 `Windows Hypervisor Platform (whpx)`
* 在 NetBSD 上支持 x86 的 `NetBSD Virtual Machine Monitor (nvmm)`
* 在 Linux 和其他 POSIX 系统、Windows、MacOS 上支持 Arm、x86、Loongarch64、MIPS、PPC、s390x 和 Sparc64 的 `Tiny Code Generator (tcg)`

本节中的所有示例都使用了 `Tiny Code Generator (tcg)` 加速器，因为这是当前在 FreeBSD 上支持的唯一加速器。
