uos 的庖丁解牛13 招:
这部分有时间总结一下,调试能力确实重要。
环境
[root@localhost ~]# uosinfo
#################################################
Release: UOS Server release 20 (kongzi)Kernel : 5.10.0-46.31.uelc20.x86_64Build : UOS Server 20 (1060a) 20231130 amd64
#################################################
问题现象
在1060u1a版本5.10内核系统上安装虚拟机,安装完成后,重启出现如下现象,虚拟机起不来。

Figure 1: “caption”

Figure 2: “caption”
复现方法
按照pms bug单描述的复现方法步骤如下:
1、部署虚拟化环境
2、virt-manager安装虚拟机,具体安装步骤如下:
1)UEFI固件选择如下:
A版本:


Figure 3: “caption”

Figure 4: “caption”

Figure 5: “caption”
3、虚拟机安装完成以后,虚拟机无法启动,具体现象如下:
legacy模式-重启-选择510内核进系统–之后报错如下:

Figure 6: “caption”
UEFI模式-重启-选择510内核进系统–之后报错如下:

Figure 7: “caption”
4、虚拟化对比测试如下:

Figure 8: “caption”
日志分析
从问题现象我们可以看到,内核出现了启动初期阶段,报了panic,如下图:


可以看到基本都是操作寄存器相关操作,我们反汇编看一下具体死在了哪行代码:

Figure 10: “caption”
可以看到正好是xsetbv指令,我们将xsetbv设置的值打印出来可以看到目前出现问题时,他的值是0x202e7,该指令是将EDX:EAX中的值写入ECX指定的XCR。这时候就需要看看intel手册关于这条指令的详细信息了,这个值是否有异常。
在Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1的13.3章节描述了关系XSTATE的相关内容:

Figure 11: “caption”
可以看到,当XCR0的bit18-17是01,10时候会报GP错误,而0x202e7的bit18-17确实是10,到现在报GP问题根因找到了,接下来的问题就是找到为什么EDA:EAX的值低32bit的bit18-17不是00或者11了。
下面我们梳理一下,GUEST、HOST、QEMU交互流程,如下图:

Figure 12: “caption”
接下来我们需要调试一下②流程:
执行:gdb /usr/libexec/qemu-kvm,进入gdb后执行设置参数,命令如下:
set args -smp 4 -m 4096 -cpu host,migratable=on -machine pc-i440fx-rhel7.6.0 -enable-kvm -kernel /root/bzImage -append
"console=ttyS0,115200 loglevel=8 nokaslr" -nographic -initrd ./myrootfs.cpio.gz
然后打断点到main、kvm_arch_get_supported_cpuid:


Figure 13: “caption”
bpftrace -e 'kprobe:kvm_arch_vcpu_ioctl {printf("ioctl args: flip %x, ioctl %x, arg %lx\n", arg0, arg1, arg2);}'
开始debug,执行run,观察function,当等于13时候,n单步执行,观察,kvm_ioctl返回结果:

查看此时的host kvm ioctl,没有抓到任何信息,由此可见,是qemu:kvm_ioctl->host出了问题,那接下来需要看一下qemu的kvm_ioctl使用的fd是否合host一致,查看代码发现,qemu中kvm_ioctl使用的fd是open /dev/kvm时候创建的,如下图:


下面我们看一下host内核KVM_GET_DEVICE_ATTR所使用的ioctl是否是/dev/kvm

从代码可以看出,KVM_GET_DEVICE_ATTR属于kvm_vcpu_ioctl的,怎么会这样呢,上游搞错了?于是看了这几行补丁的提交记录,发现是回合anolis的commit,而anolis的这个补丁也是回合上游的补丁,最后发现是anolis回合上游补丁错误导致的。
anolis回合上游补丁部分代码如下:

实际上游补丁部分代码如下:

可以看到KVM_GET_DEVICE_ATTR命令应该加到kvm_arch_dev_ioctl下面,而不是kvm_arch_vcpu_ioctl里,修改代码合入修正补丁,再次测试发现,host dev_ioctl可以抓到qemu发送的KVM_GET_DEVICE_ATTR(0xAEE2)了,如图:

此时虚拟机可以正常启动了。
解决方案
由于anolis在回合上游补丁时候,补丁与上游补丁不一致,导致qemu与kvm交互异常,因此最终解决方案如下:
修复回合上游补丁32eb80465a51 (“KVM: x86: add system attribute to retrieve full set of supported xsave states"的错误,将kvm_dev_ioctl命令KVM_GET_DEVICE_ATTR由kvm_arch_vcpu_ioct()l函数移动到kvm_arch_dev_ioctl()函数里。
参考资料
1、https://gitee.com/anolis/cloud-kernel/pulls/1532
2、A-32 Intel Architecture Software Developer’s Manual Volume.3:System Programming Guide
3、kernel-server 5.10 source code