Skip to content

Commit

Permalink
Add Documentation for zone config, hvisor structure, percpu struct, a…
Browse files Browse the repository at this point in the history
…nd ARM-GIC (#15)
  • Loading branch information
Inquisitor-201 authored Jul 20, 2024
1 parent 25058c2 commit 8fec6d6
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 3 deletions.
4 changes: 1 addition & 3 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@

- [启动两个VM:Linux 和 RTOS](./chap03/BootNonRootRTOS.md)

- [ZONE的配置与管理](./chap03/subchap01/ZoneConfig.md)

- [设备直通](./chap03/subchap01/PassThrough.md)
- [ZONE的配置与管理](./chap03/ZoneConfig.md)

- [命令行工具](./chap03/CMDTools.md)

Expand Down
59 changes: 59 additions & 0 deletions src/chap03/ZoneConfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Zone的配置和管理

hvisor项目作为一款轻量级的hypervisor,它使用了Type-1架构,允许在硬件之上直接运行多个虚拟机(zones)。下面是对zone配置和管理的关键点的详细说明:

## 资源分配

资源如CPU、内存、设备和中断对每个zone都是静态分配的,这意味着一旦分配,这些资源就不会在zones之间动态调度。

## Root Zone配置

根zone的配置是硬编码在hvisor内部的,以Rust语言编写,并表现为一个C风格的结构体HvZoneConfig。这个结构体包含了zone ID、CPU数量、内存区域、中断信息、内核和设备树二进制(DTB)的物理地址与大小等关键信息。

## Non-root Zones配置

非root zones的配置则存储在root linux的文件系统中,通常以JSON格式表示。例如:

```json
{
"arch": "arm64",
"zone_id": 1,
"cpus": [2, 3],
"memory_regions": [
{
"type": "ram",
"physical_start": "0x50000000",
"virtual_start": "0x50000000",
"size": "0x30000000"
},
{
"type": "io",
"physical_start": "0x30a60000",
"virtual_start": "0x30a60000",
"size": "0x1000"
},
{
"type": "virtio",
"physical_start": "0xa003c00",
"virtual_start": "0xa003c00",
"size": "0x200"
}
],
"interrupts": [61, 75, 76, 78],
"kernel_filepath": "./Image",
"dtb_filepath": "./linux2.dtb",
"kernel_load_paddr": "0x50400000",
"dtb_load_paddr": "0x50000000",
"entry_point": "0x50400000"
}
```

- `arch`字段指定了目标架构(例如arm64)。
- `cpus`是一个列表,指明了分配给该zone的CPU核心ID。
- `memory_regions`描述了不同类型的内存区域及其物理和虚拟起始地址与大小。
- `interrupts`列出了分配给zone的中断号。
- `kernel_filepath``dtb_filepath`分别指明了内核和设备树二进制文件的路径。
- `kernel_load_paddr``dtb_load_paddr`则是内核和设备树二进制在物理内存中的加载地址。
- `entry_point`指定了内核的入口点地址。

root linux的管理工具负责读取JSON配置文件并将其转换为C风格的结构体,随后传递给hvisor以启动非root zones。
Empty file.
Empty file removed src/chap03/subchap01/ZoneConfig.md
Empty file.
17 changes: 17 additions & 0 deletions src/chap04/Structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# hvisor总体架构

- CPU虚拟化
- 架构兼容性:支持aarch64, riscv64, 和loongarch等架构,每种架构有专门的CPU虚拟化组件。
- CPU分配:采用静态分配方式,预先决定每个虚拟机的CPU资源。

- 内存虚拟化
- 二阶段页表:利用二阶段页表技术,优化内存虚拟化过程。

- 中断虚拟化
- 中断控制器虚拟化:支持ARM GIC、RISC-V PLIC等不同架构的中断控制器虚拟化。
- 中断处理:管理中断信号的传递和处理流程。

- I/O虚拟化
- IOMMU集成:支持IOMMU,增强DMA虚拟化的效率和安全性。
- VirtIO标准:遵循VirtIO规范,提供高性能的虚拟设备。
- PCI虚拟化:实现PCI虚拟化,确保虚拟机可以访问物理或虚拟I/O设备。
29 changes: 29 additions & 0 deletions src/chap04/subchap01/ARMVirtualization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# AArch64下的CPU虚拟化

## CPU启动机制

在AArch64架构下,hvisor利用`psci::cpu_on()`函数唤醒指定的CPU核心,将其从关闭状态带入运行状态。该函数接收CPU的ID、启动地址以及一个不透明参数作为输入。遇到错误时,如CPU已处于唤醒状态,函数会进行适当的错误处理避免重复唤醒。

## CPU虚拟化初始化与运行

`ArchCpu`结构体封装了特定于架构的CPU信息和功能,其`reset()`方法负责将CPU设置为虚拟化模式的初始状态。这包括:

- 设置ELR_EL2寄存器至指定的入口点
- 配置SPSR_EL2寄存器
- 清空通用寄存器
- 重置虚拟机相关寄存器
- `activate_vmm()`,激活虚拟内存管理器(VMM)

`activate_vmm()`方法用于配置VTCR_EL2和HCR_EL2寄存器,启用虚拟化环境。

`ArchCpu``run()``idle()`方法分别用于启动和闲置CPU。启动时,激活zone的GPM(Guest Page Management),重置到指定的入口点和设备树二进制(DTB)地址,然后通过`vmreturn`宏跳转到EL2入口点。在闲置模式下,CPU被重置到等待状态(WFI),并准备`parking`指令页面以供闲置期间使用。

## EL1与EL2之间的切换

hvisor在AArch64架构中使用EL2作为hypervisor模式,而EL1用于guest OS。`handle_vmexit`宏处理从EL1到EL2的上下文切换(VMEXIT事件),保存用户模式寄存器上下文,调用外部函数处理退出原因,之后返回到hypervisor代码段继续执行。`vmreturn`函数用于从EL2模式回到EL1模式(VMENTRY事件),恢复用户模式寄存器上下文后,通过`eret`指令返回到guest OS的代码段。

## MMU配置与启用

为了支持虚拟化,`enable_mmu()`函数在EL2模式下配置MMU映射,包括设置MAIR_EL2、TCR_EL2和SCTLR_EL2寄存器,允许指令和数据缓存能力,并确保虚拟范围覆盖整个48位地址空间。

通过这些机制,hvisor在AArch64架构上实现了高效的CPU虚拟化,允许多个独立的zones在静态分配的资源下运行,同时保持系统稳定性和性能。
51 changes: 51 additions & 0 deletions src/chap04/subchap01/PerCPU.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

# PerCPU结构体

在hvisor的架构中,PerCpu结构体扮演着核心角色,用于实现每个CPU核心的本地状态管理以及支持CPU虚拟化。下面是对PerCpu结构体及相关函数的详细介绍:

## PerCpu结构体定义

PerCpu结构体被设计为每个CPU核心存储其特定数据和状态的容器。它的布局如下:

```
#[repr(C)]
pub struct PerCpu {
pub id: usize,
pub cpu_on_entry: usize,
pub dtb_ipa: usize,
pub arch_cpu: ArchCpu,
pub zone: Option<Arc<RwLock<Zone>>>,
pub ctrl_lock: Mutex<()>,
pub boot_cpu: bool,
// percpu stack
}
```

各字段定义如下:

```
id: CPU核心的标识符。
cpu_on_entry: 一个用于追踪CPU进入状态的地址,初始化为INVALID_ADDRESS,表示无效地址。
dtb_ipa: 设备树二进制的物理地址,同样初始化为INVALID_ADDRESS。
arch_cpu: 一个指向ArchCpu类型的引用,ArchCpu包含特定于架构的CPU信息和功能。
zone: 一个可选的Arc<RwLock<Zone>>类型,表示当前CPU核心正在运行的虚拟机(zone)。
ctrl_lock: 一个互斥锁,用于控制访问和同步PerCpu的数据。
boot_cpu: 一个布尔值,指示是否为引导CPU。
```

## PerCpu的构造和操作

```
PerCpu::new: 此函数创建并初始化PerCpu结构体。它首先计算结构体的虚拟地址,然后安全地写入初始化数据。对于RISC-V架构,还会更新CSR_SSCRATCH寄存器来存储ArchCpu的指针。
run_vm: 当调用此方法时,如果当前CPU不是引导CPU,则会先将其置于空闲状态,然后再运行虚拟机。
entered_cpus: 返回已进入虚拟机运行状态的CPU核心数。
activate_gpm: 激活所关联zone的GPM(Guest Page Management)。
```

## 获取PerCpu实例

```
get_cpu_data: 提供基于CPU ID获取PerCpu实例的方法。
this_cpu_data: 返回当前执行CPU的PerCpu实例。
```

51 changes: 51 additions & 0 deletions src/chap04/subchap02/ARM-GIC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ARM GICv3模块

## 1. GICv3模块

### GICv3初始化流程

hvisor中的GICv3初始化流程涉及了GIC分布控制器(GICD)和GIC重新分布控制器(GICR)的初始化,以及中断处理和虚拟中断注入的机制。这一过程的关键步骤:

- SDEI版本检查:通过smc_arg1!(0xc4000020)获取Secure Debug Extensions Interface (SDEI)的版本信息。
- ICCs配置:设置icc_ctlr_el1以仅提供优先级下降功能,设置icc_pmr_el1以定义中断优先级掩码,使能Group 1 IRQs。
- 清除待处理中断:调用gicv3_clear_pending_irqs函数,清除所有待处理的中断,确保系统处于干净状态。
- VMCR和HCR配置:设置ich_vmcr_el2和ich_hcr_el2寄存器,使能虚拟化CPU接口,准备虚拟中断处理。

### 待处理中断处理

- `pending_irq`函数读取`icc_iar1_el1`寄存器,返回当前正在处理的中断ID,若值大于等于0x3fe则视为无效中断。
- `deactivate_irq`函数通过写入`icc_eoir1_el1``icc_dir_el1`寄存器来清除中断标志,使能中断。

### 虚拟中断注入

- `inject_irq`函数检查是否有可用的`List Register (LR)`,并将虚拟中断信息写入其中。此函数区分硬件中断和软件生成中断,适当设置LR中的字段。

### GIC数据结构初始化

- GIC是一个全局的Once容器,用于延迟初始化Gic结构体,其中包含了GICD和GICR的基地址及其大小。
- primary_init_early和primary_init_late函数分别在早期和后期初始化阶段配置GIC,使能中断。

### 区域(Zone)级别的初始化

在Zone结构体中,`arch_irqchip_reset`方法负责重置分配给特定zone的所有中断,通过直接写入GICD的ICENABLER和ICACTIVER寄存器来实现。

## 2. vGICv3模块

hvisor的VGICv3(Virtual Generic Interrupt Controller version 3)模块提供了对ARMv8-A架构中GICv3的虚拟化支持。它通过MMIO(Memory Mapped I/O)访问和中断比特图管理来控制和协调不同zone(虚拟机实例)间的中断请求。

### MMIO区域注册

在初始化阶段,`Zone`结构体的`vgicv3_mmio_init`方法注册了GIC分布控制器(GICD)和每个CPU的GIC重新分布控制器(GICR)的MMIO区域。MMIO区域注册是通过`mmio_region_register`函数完成的,该函数关联了特定的处理器或中断控制器地址,以及相应的处理函数`vgicv3_dist_handler``vgicv3_redist_handler`

### 中断比特图初始化

`Zone`结构体的`irq_bitmap_init`方法用于初始化中断比特图,这是为了跟踪哪些中断属于当前`zone`。通过遍历提供的中断列表,每个中断都会被插入到比特图中。`insert_irq_to_bitmap`函数负责将特定的中断号映射到比特图中的相应位置。
MMIO访问限制

`restrict_bitmask_access`函数用于限制对`GICD`寄存器的`MMIO`访问,确保只有属于当前`zone`的中断才能被修改。该函数检查访问是否针对当前zone的中断,如果是,则更新访问掩码,以允许或限制特定的读写操作。

### VGICv3 MMIO处理

`vgicv3_redist_handler``vgicv3_dist_handler`函数分别处理GICR和GICD的MMIO访问。`vgicv3_redist_handler`函数处理GICR的读写操作,检查是否访问的是当前`zone`的GICR,如果是,则允许访问;否则,忽略该访问。`vgicv3_dist_handler`函数根据不同的GICD寄存器类型,调用`vgicv3_handle_irq_ops``restrict_bitmask_access`函数,以适当地处理中断路由和配置寄存器的访问。

通过上述机制,hvisor能够有效地管理跨zone的中断,确保每个zone只能够访问和控制分配给它的中断资源,同时提供必要的隔离性。这使得在多zone环境中,VGICv3能够高效、安全地工作,支持复杂的虚拟化场景。

0 comments on commit 8fec6d6

Please sign in to comment.