# AxVisor 设备树配置使用说明

本文档详细说明了在 AxVisor 中如何配置和使用设备树（FDT）来生成客户机 VM 的设备树。

本文档所述功能只在aarch64 架构下支持。

## 1. 概述

AxVisor 支持两种方式生成客户机 VM 的设备树：

1. **使用预定义的设备树文件**：通过 [kernel] 部分的 `dtb_path` 指定设备树文件路径
2. **动态生成设备树**：当 `dtb_path` 字段未使用时，根据配置文件中的参数动态生成设备树

无论采用哪种方式，CPU 节点和内存节点都会根据配置进行更新。

## 2. 配置文件结构

配置文件采用 TOML 格式，主要包含以下几个部分：

```toml
[base]
# 基本配置信息

[kernel]
# 内核和设备树配置

[devices]
# 设备配置信息
```

## 3. 设备树处理机制

### 3.1 使用预定义设备树文件

当 [kernel] 部分的 `dtb_path` 配置了设备树文件路径时：

```toml
[kernel]
dtb_path = "/path/to/device-tree.dtb"
```

AxVisor 会优先使用提供的设备树文件，并根据以下配置更新其中的 CPU 节点和内存节点：

- CPU 节点根据 [base] 部分的 `phys_cpu_ids` 更新
- 内存节点根据 [kernel] 部分的 `memory_regions` 更新

注意：当使用预定义设备树文件时，[devices] 部分的 `passthrough_devices` 中如果有规范化的[Name,Base-Ipa,Base-Pa,Length,Alloc-Irq]设备配置，则axvisor会直接按照 `passthrough_devices`中的配置给guest映射设备内存，设备树中的解析则会被忽略，只是将更改过内存和cpu的预定义设备树文件直接传给guest。

### 3.2 动态生成设备树

当 [kernel] 部分的 `dtb_path` 未添加时：

```toml
[kernel]
# dtb_path = ""
```

AxVisor 会根据配置文件中的参数动态生成客户机设备树：

1. **CPU 节点**：根据 [base] 部分的 `phys_cpu_ids` 生成
2. **内存节点**：根据 [kernel] 部分的 `memory_regions` 生成
3. **其他设备节点**：根据 [devices] 部分的 `passthrough_devices` 和 `excluded_devices` 生成

## 4. 配置参数详解

### 4.1 基本配置 [base]

```toml
[base]
id = 1                      # 客户机 VM ID
name = "linux-qemu"         # 客户机 VM 名称
vm_type = 1                 # 虚拟化类型
cpu_num = 1                 # 虚拟 CPU 数量
phys_cpu_ids = [0]          # 客户机 VM 物理 CPU 集合
```

注意：配置文件中的 `phys_cpu_sets` 字段已不再需要手动配置。AxVisor 会根据主机设备树和 `phys_cpu_ids` 自动识别并生成相应的 CPU 集合掩码。

### 4.2 内核配置 [kernel]

```toml
[kernel]
entry_point = 0x8020_0000           # 内核镜像入口点
image_location = "memory"           # 镜像位置 ("memory" | "fs")
kernel_path = "tmp/Image"           # 内核镜像文件路径
kernel_load_addr = 0x8020_0000      # 内核镜像加载地址
dtb_path = "tmp/linux.dtb"          # 设备树文件路径（空字符串表示动态生成）
dtb_load_addr = 0x8000_0000         # 设备树加载地址

# 内存区域配置，格式为 (基地址, 大小, 标志, 映射类型)
其中映射类型0为MAP_Alloc(由host负责，随机分配内存)，1为Map_Identical(由host负责1:1给guest映射内存，但是起始地址随机)，2为MAP_Reserved(由host负责，将host中一块标记为reserved的内存完全1:1映射给guest，起始地址和配置一致)
memory_regions = [
  [0x8000_0000, 0x1000_0000, 0x7, 0], # 系统 RAM 1G MAP_IDENTICAL
]
```

### 4.3 设备配置 [devices]

```toml
[devices]
# 直通设备配置（仅在动态生成设备树时生效）
passthrough_devices = [
  ["/intc"],
]

# 排除设备配置（仅在动态生成设备树时生效）
excluded_devices = [
  ["/intc"],
]
```

注意：直通设备配置已简化，现在只需要提供从根节点开始的完整路径即可，如 ["/intc"]。设备的地址、大小等信息会根据设备树自动识别并直通，无需手动填写。

## 5. 设备直通机制

### 5.1 直通设备配置

`passthrough_devices` 定义了需要直通给客户机的设备节点：

```toml
passthrough_devices = [
  ["/"],              # 直通根节点及其所有子节点
  ["/intc"],          # 直通 /intc 节点及其子节点
]
```

设备节点格式为从根节点开始的全局路径（如 `/intc`），在直通时会将以下节点包含在客户机设备树中：

1. 指定的直通节点本身
2. 直通节点的所有后代节点
3. 与直通设备相关的依赖节点

注意：
1. 此配置仅在动态生成设备树时生效，当使用预定义设备树文件时将被忽略。
2. 直通设备配置已简化，现在只需要提供从根节点开始的完整路径即可，设备的地址、大小等信息会根据设备树自动识别并直通。

### 5.2 排除设备配置

`excluded_devices` 定义了不希望直通给客户机的设备节点：

```toml
excluded_devices = [
  ["/timer"],         # 排除 /timer 节点及其子节点
]
```

在查找所有直通节点后，会将排除的节点及其后代节点从最终的客户机设备树中移除。

注意：此配置仅在动态生成设备树时生效，当使用预定义设备树文件时将被忽略。

### 5.3 直通地址配置

`passthrough_addresses` 定义了直通给客户机使用的地址信息：

```
passthrough_addresses = [
  [0x28041000, 0x100_0000],
]
```

该字段定义的地址会直通给客户机使用，这在某些情况下非常有用，例如设备树文件为非标准设备树格式或客户机系统时定制linux。

## 6. 示例配置

### 6.1 使用预定义设备树文件的配置

```toml
[base]
id = 1
name = "linux-qemu"
vm_type = 1
cpu_num = 2
phys_cpu_ids = [0, 1]
# phys_cpu_sets 不再需要手动配置，会自动根据 phys_cpu_ids 生成

[kernel]
entry_point = 0x8020_0000
image_location = "memory"
kernel_path = "tmp/Image"
kernel_load_addr = 0x8020_0000
dtb_path = "/home/user/device-tree.dtb"  # 使用预定义设备树文件
dtb_load_addr = 0x8000_0000

memory_regions = [
  [0x8000_0000, 0x1000_0000, 0x7, 1], # System RAM 1G MAP_IDENTICAL
]

[devices]
# 注意：以下配置在使用预定义设备树时将被忽略
passthrough_devices = [
  ["/intc"],
]
# 直通地址配置
passthrough_addresses = [
  [0x28041000, 0x100_0000],
]

excluded_devices = [
  ["/timer"],
]
```

### 6.2 动态生成设备树的配置

```toml
[base]
id = 1
name = "linux-qemu"
vm_type = 1
cpu_num = 2
phys_cpu_ids = [0, 1]
# phys_cpu_sets 不再需要手动配置，会自动根据 phys_cpu_ids 生成

[kernel]
entry_point = 0x8020_0000
image_location = "memory"
kernel_path = "tmp/Image"
kernel_load_addr = 0x8020_0000
# dtb_path = ""  # 不使用该字段表示动态生成设备树
dtb_load_addr = 0x8000_0000

memory_regions = [
  [0x8000_0000, 0x1000_0000, 0x7, 1], # System RAM 1G MAP_IDENTICAL
]

[devices]
# 以下配置仅在动态生成设备树时生效
# 注意：直通设备配置已简化，现在只需要提供从根节点开始的完整路径即可
passthrough_devices = [
  ["/"],
  ["/intc"],
]
# 直通地址配置
passthrough_addresses = [
  [0x28041000, 0x100_0000],
]
excluded_devices = [
  ["/timer"],
  ["/watchdog"],
]
```

## 7. 处理流程

1. **检查 dtb_path**：
   - 如果使用 `dtb_path` 字段，则加载并使用预定义的设备树文件，此时 `passthrough_devices` 和 `excluded_devices` 配置将被忽略
   - 如果未使用 `dtb_path` 字段，则动态生成设备树，此时 `passthrough_devices` 和 `excluded_devices` 配置生效

2. **CPU 节点处理**：
   - 根据 `phys_cpu_ids` 配置更新或生成 CPU 节点
   - 只包含配置中指定的 CPU
   - 自动根据 `phys_cpu_ids` 生成 `phys_cpu_sets`，无需手动配置

3. **内存节点处理**：
   - 根据 `memory_regions` 配置更新或生成内存节点
   - 按照指定的地址和大小创建内存区域

4. **设备节点处理**（仅在动态生成时）：
   - 根据 `passthrough_devices` 确定需要包含的设备节点
   - 包括直通节点、其后代节点以及相关依赖节点
   - 根据 `excluded_devices` 排除指定的设备节点及其后代节点

5. **生成最终设备树**：
   - 将处理后的节点组合成完整的设备树
   - 存储在全局缓存中供后续使用

## 8. 特别配置
1. **qemu 启动参数**：
```
  arceos_args = ["BUS=mmio", "BLK=y", "LOG=info", "SMP=4", "MEM=8g",
                "QEMU_ARGS=\"-machine gic-version=3  -cpu cortex-a72 -append 'root=/dev/vda rw init=/bin/sh' \"",
                "DISK_IMG=\"tmp/qemu/rootfs.img\"",]
```
其中当不提供设备树时 `-append 'root=/dev/vda rw init=/bin/sh'`参数必须添加，目的是在主机设备树中添加chosen节点的bootargs属性。
