> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 启用虚拟化

Qualcomm<sup>®</sup> Linux 通过 KVM(基于内核的虚拟机)支持硬件辅助虚拟化,KVM 直接集成到 Linux 内核中,能够以接近原生的性能运行客户机操作系统。在实现 Armv8.1 或更高版本的 Qualcomm SoC 上,虚拟主机扩展(VHE)默认启用,使主机内核运行在 EL2,而客户机内核和用户空间运行在 EL1 和 EL0。

<Note>
  请参阅发行说明,了解平台能力以及对 hypervisor 方案的支持情况。
</Note>

## **先决条件与 Kconfig**

在主机内核配置中启用以下选项:

```text theme={null}
CONFIG_KVM=y
CONFIG_VIRTUALIZATION=y
```

KVM 要求内核在异常级别 2(EL2)启动。启动后在设备上验证 KVM 是否可用:

```bash theme={null}
ls -l /dev/kvm
```

## **在 EL2 启动内核**

除少数平台外,各平台现已默认配置为启动进入 KVM。请参阅发行说明了解各平台的能力。

对于启动进入 Gunyah 而非 KVM 的平台,请使用以下说明切换到 KVM。请按给定顺序执行步骤。

<Note>
  默认配置为启动进入 KVM 的平台不需要执行以下步骤。
</Note>

1. 使用默认镜像启动。

2. 更新 EFI 变量以选择 KVM 设备树覆盖:

   ```bash theme={null}
   echo -n "el2kvm" > /var/data
   efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -w -f /var/data
   efivar -n 882f8c2b-9646-435f-8de5-f208ff80c1bd-VendorDtbOverlays -p
   sync
   ```

3. 重启进入 fastboot 模式。在设备 shell 中运行以下命令:

   ```bash theme={null}
   reboot bootloader
   ```

4. 从主机刷写 KVM XBL 配置镜像:

   ```bash theme={null}
   fastboot flash xbl_config_a xbl_config_kvm.elf
   ```

   `xbl_config_kvm.elf` 文件位于 Yocto 构建输出的 `build/tmp/deploy/images/<machine-name>` 目录下。

   替换以下内容:

   * 将 `<machine-name>` 替换为实际的 Yocto 机器配置名称,例如 `iq-9075-evk`。

5. 重启设备。

## **启动客户机 VM**

在启动客户机 VM 之前,请确保客户机内核镜像(`Image`)、根文件系统 CPIO(`rootfs.cpio.gz`)和根文件系统镜像(`rootfs.ext4`)已存在于主机的 `/mnt/overlay/guest/` 目录中。

### 使用 QEMU

使用 ramdisk 启动:

```bash theme={null}
qemu-system-aarch64 \
    -M virt -m 2G \
    -kernel /mnt/overlay/guest/Image \
    -initrd /mnt/overlay/guest/rootfs.cpio.gz \
    -cpu host --enable-kvm -smp 4 -nographic
```

使用根文件系统镜像启动:

```bash theme={null}
qemu-system-aarch64 \
    -M virt -m 2G \
    -kernel /mnt/overlay/guest/Image \
    -drive file=/mnt/overlay/guest/rootfs.ext4,if=virtio,format=raw \
    -append "root=/dev/vda" \
    -cpu host --enable-kvm -smp 4 -nographic
```

### 使用 libvirt

Libvirt 通过 `virsh` 命令行工具和 `libvirtd` 守护进程管理 VM。从 XML 域文件定义 VM,然后使用以下命令进行控制:

**表:常用 virsh VM 管理命令**

| 命令                        | 用途                        |
| ------------------------- | ------------------------- |
| `virsh define <xml-file>` | 从 XML 定义文件注册一个新的 VM 域     |
| `virsh list --all`        | 列出所有已定义的 VM 域及其状态         |
| `virsh start <domain>`    | 启动一个已停止的 VM               |
| `virsh console <domain>`  | 连接到 VM 串行控制台(按 Ctrl+] 断开) |
| `virsh shutdown <domain>` | 正常关闭正在运行的 VM              |
| `virsh undefine <domain>` | 移除一个 VM 定义                |

替换以下内容:

* 将 `<xml-file>` 替换为 libvirt XML 域定义文件的路径。
* 将 `<domain>` 替换为 XML `<name>` 元素中定义的 VM 域名称。

有关 libvirt XML 域定义示例,请参阅 [libvirt 域格式文档](https://libvirt.org/formatdomain.html)。

## **Virtio 设备支持**

Virtio 提供了一个半虚拟化 I/O 框架,用于在客户机 VM 与主机之间实现高性能设备模拟。前端驱动运行在客户机操作系统中;后端驱动运行在 QEMU 或内核中。通信使用 virtqueue(环形缓冲区)以最大限度减少客户机到主机的切换。

**表:支持的 virtio 设备**

| 设备             | 主机 Kconfig                             | 客户机 Kconfig                                           | 用途                    |
| -------------- | -------------------------------------- | ----------------------------------------------------- | --------------------- |
| virtio-block   | —                                      | `CONFIG_VIRTIO_BLK`                                   | 客户机 VM 的块存储设备         |
| virtio-net     | —                                      | `CONFIG_VIRTIO_NET`                                   | 客户机 VM 的网络接口          |
| virtio-serial  | —                                      | `CONFIG_VIRTIO_CONSOLE`                               | 主机与客户机之间的串行通信通道       |
| virtio-9p      | `CONFIG_NET_9P`、`CONFIG_NET_9P_VIRTIO` | `CONFIG_NET_9P`、`CONFIG_NET_9P_VIRTIO`、`CONFIG_9P_FS` | 通过 9P 协议实现主机到客户机的目录共享 |
| VSOCK          | `CONFIG_VSOCKETS`、`CONFIG_VHOST_VSOCK` | `CONFIG_VSOCKETS`、`CONFIG_VIRTIO_VSOCKETS`            | 主机到客户机的套接字通信          |
| virtio-IOMMU   | —                                      | `CONFIG_VIRTIO_IOMMU`                                 | 用于 DMA 管理的半虚拟化 IOMMU  |
| virtio-balloon | —                                      | `CONFIG_VIRTIO_BALLOON`                               | 动态客户机内存回收与分配          |

### 主机到客户机的文件共享(virtio-9p)

使用 9P 文件系统将主机目录传递给客户机 VM:

```bash theme={null}
qemu-system-aarch64 \
    -M virt -m 2G \
    -kernel /mnt/overlay/guest/Image \
    -drive file=/mnt/overlay/guest/rootfs.ext4,if=virtio,format=raw \
    -append "root=/dev/vda" \
    -cpu host --enable-kvm -smp 4 -nographic \
    -fsdev local,id=fsdev0,path=/mnt/overlay/test_dir,security_model=passthrough \
    -device virtio-9p-pci,fsdev=fsdev0,mount_tag=hostshare
```

在客户机内挂载共享目录:

```bash theme={null}
mount -t 9p -o trans=virtio hostshare <mount-point>
```

替换以下内容:

* 将 `<mount-point>` 替换为客户机内用于挂载共享文件夹的目录。

### 虚拟套接字(VSOCK)

VSOCK 使用上下文标识符(CID)实现客户机 VM 与主机之间的套接字通信。主机 CID 始终为 2;客户机 CID 从 3 开始。

**表:保留的 CID 值**

| CID | 说明           |
| --- | ------------ |
| -1  | 任意地址(用于绑定)   |
| 0   | Hypervisor   |
| 1   | 回环(Loopback) |
| 2   | 主机           |

在 QEMU 调用中添加 VSOCK:

```bash theme={null}
-device vhost-vsock-pci,guest-cid=<cid>
```

替换以下内容:

* 将 `<cid>` 替换为要分配给客户机 VM 的 CID,例如 `73`。

### 设备直通

可以使用 VFIO(PCI)、libusb(USB)或 chardev 后端(UART)将物理设备直通给客户机 VM。

在主机上识别 USB 设备:

```bash theme={null}
lsusb
```

在主机上识别 PCI 设备:

```bash theme={null}
lspci
```

使用 `lsusb` 输出中的厂商 ID 和产品 ID,在 QEMU 调用中添加 USB 直通:

```bash theme={null}
-device qemu-xhci -device usb-host,vendorid=<vid>,productid=<pid>
```

使用 `lspci` 输出中的域、总线、插槽和功能号添加 PCI 直通:

```bash theme={null}
-device vfio-pci,host=<bus>:<slot>.<function>
```

替换以下内容:

* 将 `<vid>` 和 `<pid>` 替换为十六进制的 USB 厂商 ID 和产品 ID,例如 `0x0781` 和 `0x5567`。
* 将 `<bus>`、`<slot>`、`<function>` 替换为 `lspci` 输出中的 PCI 地址组成部分。

对于 UART 直通,配置指向主机 TTY 设备的 `chardev` 后端,并将其作为 `virtserialport` 暴露给客户机。

## **可观测性与维护**

### KVM 跟踪

通过 tracefs 启用 KVM 事件跟踪:

```bash theme={null}
echo 1 > /sys/kernel/tracing/events/kvm/enable
cat /sys/kernel/tracing/trace
```

QEMU 跟踪事件可以重定向到内核 ftrace 缓冲区。启动客户机 VM 并启用 virtio 跟踪:

```bash theme={null}
qemu-system-aarch64 \
    -M virt -m 2G \
    -kernel /mnt/overlay/guest/Image \
    -drive file=/mnt/overlay/guest/rootfs.ext4,if=virtio,format=raw \
    -append "root=/dev/vda" \
    -cpu host --enable-kvm -smp 4 -nographic \
    -trace "virtio*"
```

### 看门狗

QEMU 模拟一个 I6300 ESB 看门狗设备,以标准看门狗字符设备的形式暴露给客户机。在客户机内核中启用它:

```text theme={null}
CONFIG_I6300ESB_WDT=y
```

将看门狗添加到 libvirt 域 XML:

```xml theme={null}
<devices>
  <watchdog model='i6300esb' action='reset'/>
</devices>
```

`action` 属性控制超时时的行为:`reset` 重启客户机,`poweroff` 将其关机。详情请参阅 [libvirt 看门狗文档](https://libvirt.org/formatdomain.html#watchdog-devices)。

### 远程命令执行

QEMU 客户机代理(`qemu-ga`)允许在没有网络连接的情况下从主机在客户机 VM 上运行命令。在客户机操作系统用户空间中启用 `qemu-ga`,并通过 virtio-serial 接口进行配置。

使用带有 `guest-exec` 子命令的 `virsh qemu-agent-command` 远程执行命令:

```bash theme={null}
virsh qemu-agent-command <domain> '{"execute":"guest-exec","arguments":{"path":"cat","arg":["/proc/meminfo"],"capture-output":true}}'
```

替换以下内容:

* 将 `<domain>` 替换为 VM 域名称。

更多信息请参阅 [QEMU Guest Agent](https://qemu-project.gitlab.io/qemu/interop/qemu-ga.html)。
