# 24.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 命令和命令行工具的使用示例。

## 24.6.1. 安装 QEMU 软件

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

```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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-nullboot) 所示。不过，这表明 QEMU 软件已正确安装。

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

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

## 24.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 的原始磁盘格式。

   ```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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-newboot-loader-menu) 中所示引导 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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-grab) 所示。按 Ctl+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 install
# reboot
```

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

> **注意**
>
> QEMU 支持 `-runas` 选项。为了增加安全性，可以在上述脚本中包括 "-runas your\_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 设备之间的通信。

## 24.6.3. 使用提示

### 24.6.3.1. 使用 X Window 系统

[安装 Xorg](https://docs.freebsd.org/en/books/handbook/x11/#x-install) 描述了如何设置 `X Window` 系统。请参考该指南进行初始的 `X Window` 设置，然后查阅 [桌面环境](https://docs.freebsd.org/en/books/handbook/desktop/#desktop) 以了解如何设置完整的桌面环境。

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

安装完成后，作为常规用户登录，然后输入：

```sh
% startx
```

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

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

图 4. 两个 QEMU 虚拟机

> **技巧**
>
> 为虚拟系统添加更多内存可能会加速图形用户界面。

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

### 24.6.3.2. 使用 QEMU 窗口

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

要切换到另一个虚拟控制台，单击 QEMU 窗口并输入 **Alt**+\*\*F2 或 **Alt**+**F3**。FreeBSD 应该会切换到另一个虚拟控制台。[图 5](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-console-ttyv3) 显示了 "left" 虚拟机在 `ttyv3` 上显示虚拟控制台的情况。

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

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

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

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

QEMU 窗口的另一个功能是 `View` 菜单和缩放控制。最有用的是 `Zoom to Fit`。当点击此菜单项时，可以通过点击窗口角部控制并调整窗口大小来调整 QEMU 窗口的大小。[图 6](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-zoom-to-fit) 显示了在图形模式下调整“left”窗口大小的效果。

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

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

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

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

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

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

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

## 24.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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-notes-on-serial-console) 中，串行端口被重定向到主机系统的 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 端口的傻终端。

### 24.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** 文件以不要求使用串行控制台。

## 24.6.5. QEMU 用户模式仿真

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

### 24.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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-sparc64-boot-cdrom-installation) 所示。

![qemu freebsd08](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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-sparc64-login-to-installed-system) 显示了登录已安装系统的 root 用户并运行 [uname(1)](https://man.freebsd.org/cgi/man.cgi?query=uname\&sektion=1\&format=html)。

![qemu freebsd09](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd09.png)

**图 9. 在用户模式仿真中从 CDROM 启动 QEMU**

## 24.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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-monitor-operation) 所示。

![qemu freebsd13](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd13.png)

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

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

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

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

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

[图 11](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-add-new-disk-figure) 显示了向虚拟机添加新磁盘所需的监控器命令序列。待使用监控器中的 `device_add` 命令添加了设备，它将在 FreeBSD 系统控制台中显示（图中的下半部分）。此时可以根据需要配置磁盘。

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

![qemu freebsd14](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd14.png)

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

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

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

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

首先，从头开始重新创建“左”虚拟机，这次使用 `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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-using-monitor-snapshots) 显示了全新安装的 FreeBSD 系统，尚未安装任何软件包，并且在 ttyv1 上单独显示了编辑会话。当前， [vi(1)](https://man.freebsd.org/cgi/man.cgi?query=vi\&sektion=1\&format=html) 编辑器处于 `insert` 模式，打字员正在输入“broadcast”一词。

![qemu freebsd15](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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-after-monitor-snapshots) 显示了上述命令的结果以及 `info snapshots` 命令的输出。

![qemu freebsd16](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](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-examine-monitor-snapshots)。

![qemu freebsd17](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) **检查快照**

## 24.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 freebsd12](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) 创建的文件提供支持，写入设备的数据会在重启后保留。

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

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

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

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

[图 16](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-usb-passthrough) 的上部分显示了 QEMU 监视器命令：

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

![qemu freebsd18](https://docs.freebsd.org/images/books/handbook/virtualization/qemu-freebsd18.png)

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

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

在 [图 17](https://docs.freebsd.org/en/books/handbook/virtualization/#qemu-usb-passthrough2) 中，展示了如何使用新设备。

![qemu freebsd19](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)。

## 24.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 上支持的唯一加速器。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/hanbook/di-24-zhang-xu-ni-hua/24.6-qemu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
