Skip to content

Commit 80c807d

Browse files
author
szy
committed
优化设备树说明
1 parent f6cd4f2 commit 80c807d

File tree

5 files changed

+900
-629
lines changed

5 files changed

+900
-629
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
---
2+
sidebar_position: 2
3+
---
4+
5+
# 原理说明
6+
7+
### 1. 设备树在虚拟化中的作用机制
8+
9+
#### 1.1 硬件抽象层的核心地位
10+
11+
设备树(FDT,Flattened Device Tree)在现代 ARM 系统中扮演着硬件抽象层的核心角色。它是一种描述硬件配置的数据结构,由 Bootloader 加载并传递给操作系统。
12+
13+
在 AxVisor 虚拟化环境中,设备树承担着三个关键角色:
14+
15+
1. **硬件发现者**:宿主机启动时,AxVisor 首先解析主机的设备树,了解可用的物理硬件资源,包括:
16+
- CPU 的数量和类型
17+
- 内存布局和容量
18+
- 中断控制器类型和配置
19+
- 各种 I/O 设备的地址空间和属性
20+
21+
2. **资源分配器**:基于对物理资源的了解,AxVisor 可以智能地为多个虚拟机分配资源:
22+
- 为每个 VM 分配特定的 CPU 核心
23+
- 划分内存区域,确保 VM 间的隔离
24+
- 配置中断路由,避免冲突
25+
26+
3. **虚拟化构建者**:AxVisor 不是简单地传递原始设备树,而是为每个 VM 构建定制的虚拟设备树,包含:
27+
- 分配给该 VM 的 CPU 节点
28+
- VM 的内存映射信息
29+
- 配置为直通的物理设备
30+
- 虚拟化的系统设备
31+
32+
#### 1.2 设备树的数据结构原理
33+
34+
设备树采用树形层次结构,每个节点代表一个硬件设备或组件,节点属性以键值对形式描述设备特性。
35+
36+
```
37+
/ (根节点)
38+
├── cpus (CPU节点)
39+
│ ├── cpu@0 (CPU核心0)
40+
│ └── cpu@1 (CPU核心1)
41+
├── soc (系统级芯片)
42+
│ ├── uart@2800c000 (串口设备)
43+
│ └── gpio@fe760000 (GPIO设备)
44+
└── memory (内存区域)
45+
```
46+
47+
每个节点的关键属性:
48+
- `compatible`: 设备兼容性字符串,用于驱动匹配
49+
- `reg`: 地址和大小信息,定义设备的物理地址空间
50+
- `interrupts`: 中断信息,指定中断号和触发方式
51+
- `phandle`: 节点标识符,用于其他节点的引用
52+
53+
### 2. 两种生成模式的深层原理
54+
55+
#### 2.1 预定义模式的适用场景和原理
56+
57+
**适用场景**
58+
- 设备树经过严格验证,确保稳定性
59+
- 需要特定的设备配置,不希望自动处理
60+
- 来自硬件供应商的标准设备树
61+
62+
**工作原理**
63+
当配置了 `dtb_path` 时,AxVisor 采用最小干预策略:
64+
65+
1. **加载验证**:读取指定的设备树文件,验证格式正确性
66+
2. **CPU 节点更新**:从主机设备树提取 CPU 信息,根据 `phys_cpu_ids` 过滤和更新
67+
3. **内存节点更新**:根据 `memory_regions` 配置,重新生成内存节点
68+
4. **直通地址处理**:如果有完整的设备配置,直接应用地址映射
69+
70+
**优势**:保持原有设备树的完整性,降低引入错误的风险
71+
72+
#### 2.2 动态生成模式的智能处理机制
73+
74+
**适用场景**
75+
- 需要根据不同 VM 配置灵活调整设备
76+
- 希望系统自动处理设备依赖关系
77+
- 需要精确控制设备直通范围
78+
79+
**工作原理**
80+
动态生成采用分析驱动的构建方式:
81+
82+
1. **设备发现阶段**
83+
- 解析配置中的 `passthrough_devices`
84+
- 查找每个直通设备的所有后代节点
85+
- 构建设备路径的完整树形结构
86+
87+
2. **依赖分析阶段**
88+
- 分析每个设备的 phandle 引用
89+
- 识别时钟、电源、中断等依赖设备
90+
- 递归解析依赖关系,确保完整性
91+
92+
3. **过滤处理阶段**
93+
- 应用 `excluded_devices` 配置
94+
- 移除指定设备及其后代节点
95+
- 确保最终设备列表的一致性
96+
97+
4. **生成构建阶段**
98+
- 根据 NodeAction 分类处理每个节点
99+
- 重新构建设备树的层次结构
100+
- 生成二进制的 DTB 文件
101+
102+
**优势**:高灵活性,智能依赖处理,精确控制
103+
104+
### 3. 设备直通的依赖关系原理
105+
106+
#### 3.1 Phandle 机制的核心作用
107+
108+
Phandle(property handle)是设备树中的节点引用机制,类似于编程语言中的指针。每个节点可以有一个或多个 phandle 属性,其他节点通过引用这些 phandle 来建立依赖关系。
109+
110+
**Phandle 声明方式**
111+
112+
```dts
113+
// 方式1:显式声明
114+
clock_controller: clock@fdd20000 {
115+
compatible = "vendor,clock";
116+
reg = <0xfdd20000 0x1000>;
117+
phandle = <0x100>; // 显式设置phandle值
118+
};
119+
120+
// 方式2:标签声明(编译器自动生成)
121+
clock: clock@fdd20000 { // 定义标签
122+
compatible = "vendor,clock";
123+
reg = <0xfdd20000 0x1000>;
124+
// 编译器会自动分配phandle
125+
};
126+
```
127+
128+
**Phandle 引用方式**
129+
130+
```dts
131+
uart0: serial@2800c000 {
132+
compatible = "vendor,uart";
133+
clocks = <&clock 0x14a>; // 引用时钟节点
134+
interrupt-parent = <&gic>; // 引用中断控制器
135+
};
136+
```
137+
138+
编译后,`&clock` 会被替换为具体的 phandle 值,如 `clocks = <0x100 0x14a>`
139+
140+
#### 3.2 依赖类型解析
141+
142+
AxVisor 支持 15+ 种依赖类型的自动识别和解析:
143+
144+
**时钟依赖(Clock Dependencies)**
145+
```
146+
clocks = <&clk_uart>, <&clk_apb>;
147+
clock-names = "baudclk", "apb_pclk";
148+
```
149+
解析时会自动找到对应的时钟控制器节点,确保 UART 设备有可用的时钟源。
150+
151+
**电源域依赖(Power Domain Dependencies)**
152+
```
153+
power-domains = <&pmu 0x3>;
154+
```
155+
确保设备在使用前,对应的电源域已正确初始化。
156+
157+
**中断依赖(Interrupt Dependencies)**
158+
```
159+
interrupt-parent = <&gic>;
160+
interrupts = <0x0 0x73 0x4>; // GIC_SPI, IRQ 115, 上升沿
161+
```
162+
建立设备与中断控制器的连接关系。
163+
164+
**GPIO 依赖(GPIO Dependencies)**
165+
```
166+
gpios = <&gpio0 0x5 0x0>; // GPIO控制器, GPIO号, 配置标志
167+
```
168+
处理设备对 GPIO 引脚的控制需求。
169+
170+
#### 3.3 依赖解析算法
171+
172+
AxVisor 采用工作队列算法进行递归依赖分析:
173+
174+
```
175+
工作队列算法:
176+
1. 初始队列:配置的直通设备
177+
2. 循环处理:
178+
a. 取出队首设备
179+
b. 分析其所有 phandle 属性
180+
c. 将依赖设备加入队列(如果未处理过)
181+
d. 标记当前设备为已处理
182+
3. 结束条件:队列为空
183+
```
184+
185+
这种算法确保:
186+
- **完整性**:所有传递依赖都被发现
187+
- **无重复**:每个设备只处理一次
188+
- **无循环**:通过已处理集合避免死循环
189+
190+
### 4. 设备树相关节点查找流程
191+
192+
设备相关节点的查找主要用于识别直通设备及其相关的祖先节点和后代节点:
193+
194+
1. **解析配置**:从配置文件读取直通设备列表
195+
2. **查找后代**:遍历设备树,找出所有直通设备的子节点、孙节点等后代节点
196+
3. **查找依赖**:分析设备属性中的 phandle 引用,找出依赖的其他设备
197+
4. **查找祖先**:确定需要包含的祖先节点,确保设备路径完整
198+
5. **排除节点**:移除配置中指定的排除设备及其后代
199+
6. **生成结果**:构建最终的设备节点列表用于生成 Guest FDT
200+
201+
假设有以下设备树结构:
202+
203+
```plain
204+
/
205+
├── soc
206+
│ ├── bus@10000000
207+
│ │ ├── device@10001000
208+
│ │ └── device@10002000
209+
│ └── bus@20000000
210+
│ ├── device@20001000
211+
│ └── device@20002000
212+
└── pci@30000000
213+
├── pci-bridge@0
214+
│ └── eth@0
215+
└── usb@1
216+
```
217+
218+
如果配置指定了直通设备 `/soc/bus@10000000/device@10001000`,那么:
219+
220+
- **后代节点**:无(该设备没有子节点)
221+
- **祖先节点**`/soc/bus@10000000``/soc`
222+
- **最终结果**:包含这三个节点以确保设备路径完整
223+
224+
如果配置指定了直通设备 `/pci@30000000`,那么:
225+
226+
- **后代节点**`/pci@30000000/pci-bridge@0``/pci@30000000/pci-bridge@0/eth@0``/pci@30000000/usb@1`
227+
- **祖先节点**[/](file:///home/szy/work/hypervisor/buddy/axvisor/Cargo.lock)(根节点)
228+
- **最终结果**:包含所有这些节点
229+
230+
这种机制确保了直通设备在 客户机系统中能获得完整的设备树支持,包括必要的父节点和子节点。
231+
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
# 设备树(FDT)使用说明
5+
6+
### 1. 快速开始
7+
8+
AxVisor 的设备树(FDT)处理模块为 AArch64 架构的虚拟机提供定制化的设备树生成服务。根据需求,可以选择以下两种使用方式:
9+
10+
**方式一:使用预定义设备树文件**
11+
```toml
12+
[kernel]
13+
dtb_path = "/path/to/your-custom.dtb"
14+
```
15+
适用场景:已经有完整的、经过验证的设备树文件,后续将只会更新memory节点和CPU节点信息。
16+
17+
**方式二:动态生成设备树**
18+
```toml
19+
[kernel]
20+
# dtb_path = "" # 不使用此字段,触发动态生成
21+
```
22+
适用场景:无客户机设备树文件。
23+
24+
### 2. 配置文件完整模板
25+
26+
以下是一个完整的 VM 配置模板,包含了所有 FDT 相关的配置选项:
27+
28+
```toml
29+
[base]
30+
id = 1 # VM 唯一标识
31+
name = "my-vm" # VM 名称,用于日志和调试
32+
vm_type = 1 # 虚拟化类型(固定为1)
33+
cpu_num = 2 # 虚拟CPU数量
34+
phys_cpu_ids = [0x200, 0x201] # 物理CPU ID列表
35+
36+
[kernel]
37+
# 镜像配置
38+
entry_point = 0x80200000 # 内核入口地址
39+
image_location = "memory" # 镜像位置:"memory" 或 "fs"
40+
kernel_path = "Image" # 内核文件路径
41+
kernel_load_addr = 0x80200000 # 内核加载地址
42+
43+
# 设备树配置
44+
#dtb_path = "/path/to/your-custom.dtb" # 可选:预定义DTB
45+
#dtb_load_addr = 0x80000000 # 可选:DTB加载地址
46+
47+
# 内存区域配置
48+
memory_regions = [
49+
[0x80000000, 0x20000000, 0x7, 1], # 基地址, 大小, 权限, 映射类型
50+
[0xa0000000, 0x10000000, 0x7, 0]
51+
]
52+
53+
[devices]
54+
# 直通设备配置(仅在动态生成时生效)
55+
passthrough_devices = [
56+
["/soc/uart@2800c000"], # 完整路径格式(推荐)
57+
# 或者传统格式,两种格式不可以混用
58+
# ["uart0", 0x2800c000, 0x2800c000, 0x1000, 0x1] #[name, base_gpa, base_hpa, length, irq_id]
59+
]
60+
61+
# 排除设备配置
62+
excluded_devices = [
63+
["/gic-v3"], # 排除中断控制器
64+
]
65+
66+
# 直通地址配置
67+
passthrough_addresses = [
68+
[0x28041000, 0x1000000], # 基地址, 长度
69+
]
70+
```
71+
72+
### 3. 字段说明
73+
74+
**3.1 `dtb_path`(设备树文件位置)**
75+
76+
客户机设备树可以有两种来源,一种是基于axvisor的设备树和客户机配置文件生成的客户机设备树,另一种是基于开发者提供的客户机设备树。当客户机配置文件中使用`dtb_path`字段时,客户机设备树基于`dtb_path`字段指定的设备树文件生成,不使用该字段时基于axvisor设备树生成。
77+
78+
```toml
79+
[kernel]
80+
dtb_path = "/path/to/custom.dtb" # 使用预定义设备树
81+
# dtb_path = "" # 动态生成设备树
82+
```
83+
84+
**3.2 `dtb_load_addr`(客户机设备树加载地址)**
85+
86+
`dtb_load_addr`字段指定生成的客户机设备树放置的客户机物理地址(GPA),当使用该字段且当客户机内存使用直通方式(GPA=HVA)时,客户机设备树将会加载到该地址,当配置文件中未使用该字段或客户机内存使用非直通方式(GPA≠HVA)时,客户机设备树将放置到客户机内存的前512MB内存的最后一段的位置,该地址由axvisor计算获得。
87+
88+
**3.3 `phys_cpu_ids`(客户机CPU ID)**
89+
90+
phys_cpu_ids字段用来选择客户机使用的CPU物理ID,例如飞腾派e2000平台的设备树cpus字段如下,其中reg属性中定义了CPU物理ID (0x200/0x201/0x00/0x100)。
91+
```
92+
cpus {
93+
#address-cells = <0x02>;
94+
#size-cells = <0x00>;
95+
96+
cpu@0 {
97+
compatible = "phytium,ftc310\0arm,armv8";
98+
reg = <0x00 0x200>;
99+
...
100+
};
101+
102+
cpu@1 {
103+
compatible = "phytium,ftc310\0arm,armv8";
104+
reg = <0x00 0x201>;
105+
...
106+
};
107+
108+
cpu@100 {
109+
compatible = "phytium,ftc664\0arm,armv8";
110+
reg = <0x00 0x00>;
111+
...
112+
};
113+
114+
cpu@101 {
115+
compatible = "phytium,ftc664\0arm,armv8";
116+
reg = <0x00 0x100>;
117+
...
118+
};
119+
};
120+
```
121+
**3.4 `memory_regions`(客户机内存地址)**
122+
123+
无论哪种客户机内存分配方式,客户机设备树都会根据申请到的客户机内存更新memory字段
124+
```
125+
memory {
126+
device_type = "memory";
127+
reg = <0x00 0x80000000 0x00 0x20000000>;
128+
};
129+
```
130+
**3.5 `passthrough_devices`(直通设备)**
131+
132+
现支持两种格式的设备直通方式
133+
134+
格式一:传统完整配置
135+
```
136+
passthrough_devices = [
137+
["intc@8000000", 0x800_0000, 0x800_0000, 0x50_000, 0x1], #[name, base_gpa, base_hpa, length, irq_id]
138+
["pl011@9000000", 0x900_0000, 0x900_0000, 0x1000, 0x1],
139+
["pl031@9010000", 0x901_0000, 0x901_0000, 0x1000, 0x1],
140+
]
141+
```
142+
143+
格式二:全路径配置(推荐)
144+
```
145+
passthrough_devices = [
146+
["/syscon@fdc20000"],
147+
["/pinctrl/gpio3@fe760000"], #从根节点开始的完整路径
148+
["/"], #根节点,表示所有设备都直通
149+
]
150+
```
151+
152+
当直通设备使用全路径方式时,这里只需要填写需要直通的设备名称即可,设备名称是从跟节点开始的完整路径,此时axvisor会根据提供的设备树或主设备树自动查找相关节点并直通,该节点及相关节点的地址均等信息会根据设备树识别并补充完整,其中"/"表示根节点,当直通根节点时主机所有节点均会直通给客户机。
153+
154+
**3.6 `excluded_devices` (不直通设备)**
155+
156+
设备直通时axvisor会识别相关设备并一并直通给客户机,当某个设备不希望直通给客户机时可以加入该字段中,这样该设备及其地址将不会直通给客户机使用,生成的客户机设备树也不会包含该设备。
157+
158+
**3.7 `passthrough_addresses`(直通地址)**
159+
160+
该字段用于将指定地址直通给客户机使用,在启动如定制linux客户机需要使用某段地址或设备树非标准需要直接指定直通地址时将会使用到。
161+

0 commit comments

Comments
 (0)