基于 armhf-qemu 的 ARMv7 linux-5.6 qemu-KVM 代码分析 1 qemu与kvm 的交互

前提

-我在 ubuntu armhf cloud 发行版 仿真 中搭建了一个 “基于ARMv7” 且 “abi为armhf” 且 “os 为 ubuntu” 的 “虚拟化调试平台”,主要是为了研究

1. ARMv7 对虚拟化的支持 
2. linux armv7 kvm 的实现 
3. qemu 与 kvm 的交互

调试平台是这个样子的

L0 : win10 x86_64
L1 : L0 上用 vmware work station 搭建的一个 ubuntu20.04-x86_64
L2 : L1 上用 qemu-6.1.0 搭建的一个 armhf-ubuntu 16.04,并手动编译升级内核到 linux-5.6
L3 : L2 上用 qemu-2.5.0 搭建的一个 armhf-linux-initramfs,并手动编译升级内核到 linux-5.6
  • 研究手段及目标顺序
怎么实现这些研究目的
1. 在 L1 上 安装 arm-none-eabi-gdb
2. 开启L2 的时候 添加 -S -s 选项 , 并 用 arm-none-eabi-gdb 不加断点让其全速运行
3. L2 启动到 shell , 此时 用 arm-none-eabi-gdb 添加 kvm 相关的断点
4. 启动 L3(需要添加 --enable-kvm)  , 启动后 自动停在 断点 

研究目的的顺序
	1. qemu 与 kvm 的交互
		通过书籍获取大概交互资料(主要是三个fd),并验证(这三个fd)的实现原理
		通过每个 fd 访问了多少次,都访问了什么
	2. linux armv7 kvm 的实现
		fd 中的 ioctl 怎么处理的
		如何 VM enter 和 VM exit
	3. ARMv7 对虚拟化的支持
		PL2 异常向量表的设置
		相关寄存器的读写

qemu 与 kvm 的交互

初始化
fd_kvm = open(/dev/kvm) 							kvm_chardev_ops  		kvm_dev_ioctl
fd_vm = ioctl(fd_kvm,KVM_CREATE_VM,0) 				kvm_vm_fops				kvm_vm_ioctl
fd_vcpu = ioctl(fd_vm,KVM_CREATE_VCPU,0) 			kvm_vcpu_fops 			kvm_vcpu_ioctl

运行
ioctl(fd_vcpu,KVM_RUN,NULL)
主要是 要考虑 通过三个 fd (fd_kvm fd_vm fd_vcpu) 操控 kvm 做事
按照书籍资料,kvm负责 
	KVM本身基于硬件辅助虚拟化,仅仅实现CPU和内存的虚拟化,但一台计算机不仅仅有CPU和内存,还需要各种各样的I/O设备,不过KVM不负责这些。KVM负责底层执行引擎和内存的虚拟
	经过改造后的QEMU,负责外部设备的虚拟
	两者彼此互补,成为新一代云计算虚拟化方案的宠儿。

little-qemu & test.S

不能用(太庞大) qemu 来探究 qemu 与 kvm 的交互,而是我们要是实现一个小的qemu(little-qemu),并实现一个小的虚拟机程序(test.S)来探究

  • little-qemu
TODO
https://www.cnblogs.com/Bozh/p/5753379.html
https://www.cnblogs.com/pengdonglin137/p/14083316.html
http://soulxu.github.io/blog/2014/08/11/use-kvm-api-write-emulator/
  • test.S
TODO
  • 如何调试
涉及到 
little-qemu(运行在L2) ,L2(ARMv7-ubuntu-16.04) 上运行 arm-gdb
test.S(运行在L3)
linux-5.6-kvm(运行在L1) ,L1(x86_64-ubuntu-20.04) 上运行 arm-gdb
little-qemu 需要完成的步骤
1.创建虚拟机
	2.设置虚拟机内存,并加载镜像到虚拟机内存
	3.创建VCPU
		4.设置sregs和regs
	5.将虚拟机(guest)运行时结构映射到host user space
	6.循环(1.开始运行 2.退出时检查虚拟机运行时结构)
	
顺序要求
	2必须在1后面
	3必须在1后面
	4 5必须在3后面
	4 5之间没有顺序要求

QEMU与KVM交互的分析

"QEMU/KVM 源码解析与应用" 中讲述的实例为例
QEMU与KVM的交互 只有 ioctl , 涉及到了三个 fd , 主要有以下动作
	1. fd_vm = ioctl(fd_kvm,KVM_CREATE_VM,0) 												// 创建虚拟机
	2. ioctl(fd_vm,KVM_SET_USER_MEMORY_REGION,(struct kvm_userspace_memory_region)(&mem)) 	// 设置虚拟机的 内存
	3. fd_vcpu = ioctl(fd_vm,KVM_CREATE_VCPU,0) 											// 创建虚拟机的 VCPU
	4. struct kvm_run * run = mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd_vcpu,0) 	// 获取虚拟机的 内存中的 运行时结构 // (这个运行时结构属于虚拟机的内存吗?TODO)
	5. ioctl(fd_vcpu,KCM_SET_SREGS,(struct kvm_sregs *)(&sregs)) 							// 设置虚拟机的 VCPU 的 代码段寄存器 // 这里对应x86,如果是arm,则是另一个 cmd
	6. ioctl(fd_vcpu,KVM_SET_REGS,(struct kvm_regs *)(&regs)) 								// 设置虚拟机的 VCPU 的 通用寄存器 // 这里对应x86,如果是arm,则是另一个 cmd
	7. ioctl(fd_vcpu,KVM_RUN,NULL)															// 启动虚拟机的 VCPU  

可以看到,一个很简单的 x86 程序 的仿真(仿真了cpu和内存)要用到
	1. 对 fd_kvm  进行 虚拟机 (一块内存&一个CPU)的创建
	2. 对 fd_vcpu 进行 虚拟机 CPU (寄存器的设置和启动)
	3. 对 fd_vcpu 进行 虚拟机 的运行时结构体访问

如果 我要仿真一个完整的 soc , 则要用到 kvm 侧的
	1. cpu 内存 中断 设备 的 相关 ioctl
	// cpu 相关的 KVM_CREATE_VCPU,KCM_SET_SREGS,KVM_SET_REGS,KVM_RUN
	// 内存 相关的 KVM_SET_USER_MEMORY_REGION
	// 设备 相关的 // 设备 不是通过 ioctl 做的, 而是 vm exit 后分析原因, 然后 设备模拟
	// 中断 相关的 KVM_SIGNAL_MSI

如果 我要仿真一个完整的 soc , 还要用到 qemu侧的
	1. cpu 内存 中断 设备 的 相关管理// 以内存为例来说,总不能一块内存创建一个全局变量来管理,而是形成一个数据结构,让数据结构来管理内存
	// cpu 相关的 TODO
	// 内存相关的 结构体: RAMBlock MemoryRegion AddressSpace
	// 设备相关的 virtio 等等等
	// 中断相关的 ioctl函数 : kvm_set_irq -> kvm_vm_ioctl(XXX)

猜你喜欢

转载自blog.csdn.net/u011011827/article/details/120622352