qemu系统¶
qemu系统模拟 提供了一个虚拟的机器模型,用于运行在客户操作系统。
qemu系统模拟 支持多种虚拟机管理程序(加速器), 支持微型代码生成器(TCG)的JIT,能够模拟多个CPU。
加速器有:¶
1. KVM, 主机操作系统为Linux (架构可以是: Arm (64 bit only), MIPS, PPC, RISC-V, s390x, x86)
1. Hypervisor Framework (hvf) , 主机操作系统为MacOS ( 架构可以是: x86 (64 bit only), Arm (64 bit only) )
1. Windows Hypervisor Platform (whpx), 主机操作系统为 Windows ( 架构可以是: x86 )
1. NetBSD Virtual Machine Monitor (nvmm), 主机操作系统为 NetBSD( 架构可以是: x86 )
1. Tiny Code Generator (tcg), 主机操作系统为 Linux, other POSIX, Windows, MacOS( 架构可以是: Arm, x86, Loongarch64, MIPS, PPC, s390x, Sparc64)
qemu-system-arm -machine [machine opts] \ # 定义机器类型、内存量等
-cpu [cpu opts] \ # vCPU 的类型和数量/拓扑。大多数加速器都提供hostCPU 选项,该选项会直接传递主机 CPU 配置,而不会过滤任何功能。
-accel [accelerator opts] \ # 这取决于您运行的虚拟机管理程序。请注意,默认设置是 TCG,它是纯模拟的,因此您必须指定加速器类型才能利用硬件虚拟化。
-device [device opts] \ # 机器类型中默认未定义的附加设备。
[backend opts] \ # 后端是 QEMU 处理客户机数据的方式,例如块设备如何存储、网络设备如何查看网络或串行设备如何指向外部世界。
[interface opts] \ # 系统如何显示,如何管理和控制或调试。
[boot opts] # 系统如何启动,通过固件还是直接内核启动
# 支持的机器
qemu-system-arm -M help
# 支持的设置
qemu-system-arm -device help
# 支持的设置 scsi-hd中的参数查询
qemu-system-x86_64 -device scsi-hd,help
QEMU 支持模拟大量设备,从网卡、USB 等外围设备到集成片上系统 (SoC)¶
设备前端, 设备呈现给客户机的方式,呈现的设备类型应与客户机操作系统期望看到的硬件相匹配,使用
--device命令行选项指定设备总线,大多数设备都会存在于某种总线上
设备后端,后端描述了 QEMU 将如何处理来自模拟设备的数据
设备直通
qemu架构¶
Apps | Apps ...
--------------------|-------------------
客户机系统(Guest) |客户机系统(Guest)... |-----------------
--------------------|------------------- |----QEMU模块-----|
Qemu(x86架构) | Qemu(ARM架构)... --> | CPU模拟 |
---------------------------------------- | 内存模拟 |
宿主系统(host, linux) | I/O设备模拟 |
---------------------------------------- | 其它设备模拟 |
硬件平台(如x86架构)
----------------------------------------
从本质上看,虚拟出的每个虚拟机对应 host 上的一个 Qemu 进程,而虚拟机的执行线程(如 CPU 线程、I/O 线程等)对应 Qemu 进程的一个线程。
下面通过一个虚拟机启动过程看看 Qemu 是如何与 KVM 交互的:¶
// 第一步,获取到 KVM 句柄
kvmfd = open("/dev/kvm", O_RDWR);
// 第二步,创建虚拟机,获取到虚拟机句柄。
vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
// 第三步,为虚拟机映射内存,还有其他的 PCI,信号处理的初始化。ioctl(kvmfd, KVM_SET_USER_MEMORY_REGION, &mem);
// 第四步,将虚拟机镜像映射到内存,相当于物理机的 boot 过程,把镜像映射到内存。
// 第五步,创建 vCPU,并为 vCPU 分配内存空间。
ioctl(kvmfd, KVM_CREATE_VCPU, vcpuid);
vcpu->kvm_run_mmap_size = ioctl(kvm->dev_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
// 第五步,创建 vCPU 个数的线程并运行虚拟机。ioctl(kvm->vcpus->vcpu_fd, KVM_RUN, 0);
// 第六步,线程进入循环,并捕获虚拟机退出原因,做相应的处理。
for (;;) {
ioctl(KVM_RUN);
switch (exit_reason) {
case KVM_EXIT_IO: /* ... */
case KVM_EXIT_HLT: /* ... */
}
}
// 这里的退出并不一定是虚拟机关机,
// 虚拟机如果遇到 I/O 操作,访问硬件设备,缺页中断等都会退出执行,
// 退出执行可以理解为将 CPU 执行上下文返回到 Qemu。
qemu源码结构:¶
Qemu 软件虚拟化实现的思路是采用二进制指令翻译技术,主要是提取 guest 代码,然后将其翻译成 TCG 中间代码,最后再将中间代码翻译成 host 指定架构的代码,如 x86 体系就翻译成其支持的代码形式,ARM 架构同理。
/vl.c:最主要的模拟循环,虚拟机环境初始化,和 CPU 的执行。
/target/arch/tcg/translate.c:将 guest 代码翻译成不同架构的 TCG 操作码。
/tcg/tcg.c:主要的 TCG 代码。
/tcg/arch/tcg-target.c:将 TCG 代码转化生成主机代码。
/cpu-exec.c:主要寻找下一个二进制翻译代码块,如果没有找到就请求得到下一个代码块,并且操作生成的代码块。
总体流程:
命令行参数 –> 初始化机器–> 创建设备 –> 初始化CPU -> 加载内核
| |
V V
内存/设备配置 <– 事件循环 –> 执行翻译块 –> 处理中断
1、初始化阶段
1、解析命令行参数, 参数决定了模拟的硬件配置(如 开发板型号、cpu类型、内存大小等)
2、创建虚拟机器, -M, 调用machine_init(),初始化该机器的硬件配置
3、初始化虚拟设备, 根据机器模型注册虚拟设备,设备初始化包括 内存映射、中断请求线分配、设备状态初始化
2、CPU模拟内核
1、初始化CPU,创建虚拟cpu,初始化寄存器状态
2、翻译块(TB)生成与执行,将客户机的指令翻译为宿主机的中间代码(TCG IR)并优化,并生成原生代码缓存起来
3、内存模拟
1、虚拟内存布局, ram区域(-m指定)、rom(如加载固件)、设备寄存器(MMIO)
2、内存访问处理, 检测地址是否命中RAM/ROM/MMIO, 对RAM/ROM直接读写宿主内存、对MMIO触发设备回调函数
4、外设模拟
5、启动客户机操作系统
6、事件循环与退出
1、主循环, cpu执行、设备io事件、异步任务
2、退出条件,客户机执行关机指令、用户强制终止
main.c
1.qemu_init
2.qemu_main -> qemu_main_loop, qemu_cleanup
qemu_init
1.qemu基本配置
2.module_call_init(MODULE_INIT_OPTS)
#3.error_init
#4.qemu_init_exec_dir
#5.os_setup_limits
#6.qemu_init_arch_modules
7.qemu_init_subsystems
0.module_call_init(MODULE_INIT_TRACE)
1.qemu_init_cpu_list # cpu锁初始化
2.qemu_init_cpu_loop # 初始化信号总线,和锁
3.qemu_run_exit_notifiers #退出hook
4.module_call_init(MODULE_INIT_QOM) ###关键###
5.module_call_init(MODULE_INIT_MIGRATION)
#6.runstate_init
#7.precopy_infrastructure_init 通知相关
#8.postcopy_infrastructure_init 通知相关
9.monitor_init_globals
#10.bdrv_init_with_whitelist
8.根据入参配置qemu # 参数说明在 qemu-options.hx文件中,构建后会生成qemu-options.def文件
9.qemu_init_main_loop
10.cpu_timers_init ###关键###
11.configure_rtc
12.parse_memory_options
13.qemu_create_machine ###关键, 这里实现对象的创建###
#suspend_mux_open
14.qemu_setup_display
15.qemu_create_default_devices
16.qemu_create_early_backends
17.configure_accelerators ###关键###
18.qemu_create_late_backends
19.migration_object_init
20.qemu_resolve_machine_memdev ###关键###
21.qemu_init_displays
#resume_mux_open
主要模拟点有:
CPU虚拟化: arm cpu实现分析,arm soc建立,一些寄存器实现添加,TCG原理,指令添加¶
TYPE_CPU
所有 CPU 类的基类,定义在 hw/core/cpu-common.c 中。
提供通用 CPU 功能,如寄存器、内存管理、中断处理等
TYPE_ARM_CPU
继承自 TYPE_CPU,定义在 target/arm/cpu.c 中。
提供 ARM 架构通用功能,如:
ARM 寄存器(R0-R15、CPSR、SPSR)。
ARM 指令集(ARM、Thumb、Thumb2)。
ARM 异常模型(IRQ、FIQ、Abort、Undef)。
ARM 内存管理(MMU、TLB、页表)。
TYPE_ARM_V7M_CPU
继承自 TYPE_ARM_CPU,定义在 target/arm/tcg/cpu-v7m.c 中。
模拟 ARMv7-M 架构(Cortex-M3/M4/M7)。
支持 Thumb-2 指令集、NVIC、MPU。
TYPE_CPU
|
+-- TYPE_ARM_CPU
|
+-- TYPE_ARM_V7M_CPU
| |
| +-- TYPE_ARM_CORTEX_M3_CPU
| +-- TYPE_ARM_CORTEX_M4_CPU
| +-- TYPE_ARM_CORTEX_M7_CPU
|
+-- TYPE_ARM_V7A_CPU
| |
| +-- TYPE_ARM_CORTEX_A7_CPU
| +-- TYPE_ARM_CORTEX_A8_CPU
| +-- TYPE_ARM_CORTEX_A9_CPU
| +-- TYPE_ARM_CORTEX_A15_CPU
| +-- TYPE_ARM_CORTEX_R5_CPU
|
+-- TYPE_ARM_V8A_CPU
| |
| +-- TYPE_ARM_CORTEX_A53_CPU
| +-- TYPE_ARM_CORTEX_A57_CPU
| +-- TYPE_ARM_CORTEX_A72_CPU
| +-- TYPE_ARM_CORTEX_A73_CPU
| +-- TYPE_ARM_CORTEX_A75_CPU
| +-- TYPE_ARM_CORTEX_A76_CPU
|
+-- TYPE_ARM_V8R_CPU
|
+-- TYPE_ARM_CORTEX_R52_CPU
中断虚拟化: qemu irq机制¶
TYPE_SYS_BUS_DEVICE
|
+-- TYPE_ARM_GIC_COMMON
| |
| +-- TYPE_ARM_GIC
| | |
| | +-- TYPE_ARM_GIC_KVM
| |
| +-- TYPE_ARM_GICV3_COMMON
| |
| +-- TYPE_ARM_GICV3
| |
| +-- TYPE_ARM_GICV3_KVM
|
+-- TYPE_ARM_GICV3_ITS
| |
| +-- TYPE_ARM_GICV3_ITS_KVM
|
+-- TYPE_ARM_V7M_NVIC
内存虚拟化: qemu内存原理, 用户态/系统态程序加载运行方式¶
总线虚拟化: qemu总线原理¶
外设虚拟化: uart、gpio实现与应用¶
TYPE_ARM_TIMER
继承自 TYPE_SYS_BUS_DEVICE,定义在 hw/timer/arm_timer.c 中。
模拟 ARM 通用定时器,支持:
定时器计数。
定时器中断。
定时器控制。
TYPE_ARM_GTIMER
继承自 TYPE_SYS_BUS_DEVICE,定义在 hw/timer/arm_gtimer.c 中。
模拟 ARM 通用定时器,支持:
定时器计数。
定时器中断。
定时器控制
TYPE_SYS_BUS_DEVICE
|
+-- TYPE_ARM_SYSCTL
|
+-- TYPE_ARM_SMMU
| |
| +-- TYPE_ARM_SMMUV3
|
+-- TYPE_ARM_TIMER
|
+-- TYPE_ARM_MPTIMER
|
+-- TYPE_ARM_GTIMER
|
+-- TYPE_ARM_PL011
|
+-- TYPE_ARM_PL031
|
+-- TYPE_ARM_NETWORK
|
+-- TYPE_ARM_SD
|
+-- TYPE_ARM_EMMC
|
+-- TYPE_ARM_FRAMEBUFFER
|
+-- TYPE_ARM_AUDIO
TYPE_ARM_SYSCTL 提供:
系统配置寄存器。
系统状态寄存器。
系统控制寄存器。
TYPE_ARM_SMMU 提供:
内存地址转换。
内存访问权限控制。
内存缓存控制。
TYPE_ARM_SMMUV3 提供:
内存地址转换。
内存访问权限控制。
内存缓存控制。
支持 Stage 1 和 Stage 2 转换。
TYPE_ARM_TIMER 提供:
定时器计数。
定时器中断。
定时器控制。
TYPE_ARM_MPTIMER 提供:
多核定时器计数。
多核定时器中断。
多核定时器控制。
TYPE_ARM_GTIMER 提供:
定时器计数。
定时器中断。
定时器控制。
TYPE_ARM_PL011 提供:
串口通信。
串口中断。
串口控制。
TYPE_ARM_PL031 提供:
实时时钟。
闹钟功能。
RTC 中断。
TYPE_ARM_NETWORK 提供:
网络通信。
网络中断。
网络控制。
TYPE_ARM_SD 提供:
SD 卡读写。
SD 卡中断。
SD 卡控制。
TYPE_ARM_EMMC 提供:
eMMC 读写。
eMMC 中断。
eMMC 控制。
TYPE_ARM_FRAMEBUFFER 提供:
显示输出。
显示中断。
显示控制。
TYPE_ARM_AUDIO 提供:
音频输出。
音频中断。
音频控制。
Machine虚拟化: qemu整体运行流程分析,MCU/LINUX 设备组织方式¶
TYPE_MACHINE
|
+-- TYPE_ARM_MACHINE
|
+-- TYPE_VIRT_MACHINE
+-- TYPE_VEXPRESS_MACHINE
+-- TYPE_HIGHBANK_MACHINE
+-- TYPE_MPS2_MACHINE
+-- TYPE_MUSCA_MACHINE
+-- TYPE_MUSICPAL_MACHINE
+-- TYPE_NETDUINO2_MACHINE
+-- TYPE_NSERIES_MACHINE
+-- TYPE_OMAP_SX1_MACHINE
+-- TYPE_PALM_MACHINE
+-- TYPE_REALVIEW_MACHINE
+-- TYPE_SABRELITE_MACHINE
+-- TYPE_SBSA_REF_MACHINE
+-- TYPE_STELLARIS_MACHINE
+-- TYPE_STM32VLDISCOVERY_MACHINE
+-- TYPE_STRONGARM_MACHINE
+-- TYPE_COLLIE_MACHINE
+-- TYPE_GUMSTIX_MACHINE
+-- TYPE_SPITZ_MACHINE
+-- TYPE_TERRIER_MACHINE
+-- TYPE_TOSA_MACHINE
+-- TYPE_Z2_MACHINE
QEMU中的一些机制:
QOM(qemu object model): 一个面向对象的C框架, 主要用来注册用户创建的类型与初始化这些类型
说明:
type_init 将各种类型注册到模块中的初始化数组中(这个注册过程在执行模拟前会运行,因为 __attribute__((constructor)) 修饰,不用手动调用函数 )
在执行模拟时,会调用模块初始化过程, 执行object.c中的type_register_static函数,初始化类型实现TypeImpl, 并放入object.c中的 hashTable中
type_init
type_init(function) 宏展开是下面的格式 static void __attribute__((constructor)) do_qemu_init_ ## function(void) { register_module_init(function, MODULE_INIT_QOM); }
DEFINE_MACHINE
DEFINE_TYPES
类层次结构梳理
所有对象类的父类是 ObjectClass 所有对象的父类是 Object 所有类型的实现使用 TypeImpl --> 并放入对象类中