openEuler社区的qemu-4.1.0实现了aarch64 CPU热插特性。
CPU热插功能涉及的修改主要包括ACPI(MADT表,DSDT表),GED,GICv3,以及热插流程的支持。
1 ACPI
1.1 什么是ACPI?
ACPI是Advanced Configuration and Power Interface的简写。可以将ACPI理解为与体系结构无关的电源管理和配置框架,该框架在主机OS内形成子系统。 该框架建立了一个硬件寄存器集来定义电源状态(睡眠,休眠,唤醒等)。 硬件寄存器集可以容纳专用硬件和通用硬件上的操作。标准ACPI框架和硬件寄存器集的主要目的是启用电源管理和系统配置,而无需直接从OS本地调用固件。ACPI充当系统固件(BIOS)和OS之间的接口层,并具有一定的限制和规则。
Definition blocks字节代码是从ACPI源语言(ASL)代码编译而成的。 ASL是用于定义ACPI对象和编写控制方法的语言。 ASL编译器将ASL转换为ACPI机器语言(AML)字节码。 AML是AML解释程序处理的语言。
1.2 ACPI整体系统
图中OSPM是Operating System-directed configuration and Power Management的简写。
ACPI有三个运行时组件:
- ACPI Description Tables:描述对硬件的接口。ACPI Description Tables包含了Definition Blocks,其可以使用称为ACPI Machine Lanague(AML)的伪代码。
- ACPI Registers:硬件接口的受约束部分,由ACPI系统描述表描述(至少在位置上)。
- ACPI Platform Firmware:与ACPI规范兼容的固件部分。通常,这是引导计算机(如旧版BIOS完成)并实现睡眠,唤醒和某些重新启动操作的接口的代码。
1.3 CPU热插涉及的ACPI表
- Differentiated System Description Table (DSDT):OEM必须向兼容ACPI的操作系统提供DSDT。 DSDT包含“差分definition blocks”,该块提供有关基本系统的实现和配置信息。 操作系统始终在系统引导时将DSDT信息插入ACPI namespace,并且永远不会删除它。
- Multiple APIC Description Table (MADT):用于支持APIC和SAPIC的系统上,以描述APIC实现。 M计ADT后面是APIC / SAPIC结构的列表,这些结构声明了算机的APIC / SAPIC功能。
1.4 ACPI事件编程模型(GED)
ACPI 6.1引入了对ACPI事件的支持:当Generic Event Device(GED)的_CRS对象中列出的中断发生时,会产生ACPI事件并由OSPM接收。OSPM声明所有此类中断,并将它们映射到ACPI事件模型所需的适当事件方法。GED在namespace中是一个设备,其_HID为ACPI0013。GED必须提供一个_CRS和_EVT对象,以声明中断并将它们映射到ACPI事件。OS可以通过_OSC方法查询平台是否支持GED。
2 GICv3
GIC(Generic Interrupt Controller)是一个通用的中断控制器,用来接收硬件中断信号,并经过一定处理后,分发给对应的CPU进行处理。GIC V3是其中一个版本,支持的中断类型如下表:
中断类型 |
中断号 |
描述 |
SGI (Software Generated Interrupt) |
0-15 |
软件触发中断,通常用于多核之间通讯,在Linux内核中通常被用作IPI(inter-process interrupts)中断,并送达到系统指定的CPU,最多支持16个SGI中断,中断号0-15 |
PPI (Private Peripheral Interrupt) |
16-31 |
每个处理器的私有外设中断,最多支持16个PPI中断,中断号16-31,PPI通常会送达到指定的CPU上 |
SPI (Shared Peripheral Interrupt) |
32-1019 |
系统共享的外设中断 |
LPI (Locality-specific Peripheral Interrupt) |
8192-MAX |
LPI是基于消息的中断,它们的配置保存在表中而不是寄存器 |
GIC V3中断控制器的组成部分包括:distributor,redistributor,cpu interface,ITS,GIC V3中断控制器和处理器核心之间的关系图如下:
3 主要修改
对于需要支持CPU热插的虚拟机,vcpu配置示例如下:
<vcpu placement='static' current='4'>8</vcpu>
其中current='4'指定当前CPU数量为4,<vcpu>8</vcpu>指定最大CPU数量为8。
3.1 CPU热插流程
qemu处理CPU热插事件的相关流程如下:
- 收到device_add qmp,且设备类型为cpu
- 进入device_set_realized流程
- virt_cpu_pre_plug,设置CPU相关属性,并暂停所有CPU
- 实例化CPU
- virt_cpu_plug,连接GIC irq,重置CPU,并恢复所有CPU运行,然后发送消息给guest OS,通知CPU热插。
guest处理CPU热插事件的相关流程如下:
- GED发送CPU热插事件给guest。
- guest中的ACPI驱动调用GED AML定义的_EVT方法。
- GED AML定义的_EVT方法判断是CPU热插事件,调用CPUS AML定义的CSCN方法获取所有CPU的状态。
- guest的CPU的状态由GED的CPUHotplugState结构进行模拟,并通过Memory Region由guest访问。
3.2 对ACPI表的修改
3.2.1 对MADT表的修改
MADT表向OSPM提供了中断控制器的描述信息。qemu模拟的aarch64平台使用的是GICv3作为中断控制器,因此MADT表中包含了n个GICC(GIC CPU Interface)结构,虚拟机每个CPU对应一个GICC。由于要支持CPU热插,因此提供给虚拟机的MADT表中GICC结构的数量需要指定为虚拟机配置的最大CPU数量。
build_madt
|
3.2.2 对DSDT表的修改
DSDT表向OSPM提供了CPU信息,构造CPU信息的功能由build_cpus_aml函数提供。
build_dsdt
|