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)

  1. 设备前端, 设备呈现给客户机的方式,呈现的设备类型应与客户机操作系统期望看到的硬件相匹配,使用 --device命令行选项指定

  2. 设备总线,大多数设备都会存在于某种总线上

  3. 设备后端,后端描述了 QEMU 将如何处理来自模拟设备的数据

  4. 设备直通

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中
  1. type_init

    type_init(function) 宏展开是下面的格式
    static void __attribute__((constructor)) do_qemu_init_ ## function(void)
    {                                                                           
        register_module_init(function, MODULE_INIT_QOM);                                 
    }
    
  2. DEFINE_MACHINE

  3. DEFINE_TYPES

  4. 类层次结构梳理

    所有对象类的父类是 ObjectClass
    所有对象的父类是 Object
    所有类型的实现使用 TypeImpl --> 并放入对象类中