seabios问题的原理还是很简单的,只是我对bios的原理一点也不了解,可谓盲人骑瞎马,夜半看bug,过程记录一下,还是有些意义。
问题就是给定qemu分配78个vcpu的时候,qemu提示找不到硬盘,即是"Boot failed: could not read the boot disk",出现了这样的问题,正确的思路就是看打印,就是seabios的boot_disk里面的:

call16_int获取的br没有满足flag的条件,由兴趣的可以翻看一下__call16_int,我确实没看明白调用机制是什么,此路不通。
从整体看,disk是一个文件虚拟化而成的,除了seabios本身机制问题,还一个可能出在qemu虚拟化设备上,因为本身是cpu个数导致问题,后者的疑点更重,启动2个qemu,一个有问题,另外一个没问题,进行对比,在qemu的控制端查看所有设备,都一样,OK,此路证伪。
只好重新回到__call16_int,看不懂还有万能的gdb呢,有开发文档在此,http://www.seabios.org/Debugging,主要就几条:1.make menuconfig中的CONFIG_DEBUG_LEVEL控制日志输出;2.在qemu中输出debug信息;3.在gdb中以qemu为中转调试seabios。开启第一条开关,执行第二条,失败,不能识别chardev,执行第三条,调试到call16_int深处,程序异常退出。
然后上万能大法,二分法,确定了qemu的seabios有问题,在rel-1.8.0引入的问题,然后二分法seabios代码,悲剧就此产生,二分法失效,先说一下原因,因为问题本身出在seabios内存使用上,而CONFIG_DEBUG_LEVEL也会影响内存的使用。
重新回头看一下问题,发现qemu输出debug的时候qemu被checkout到老版本上了,checkout master上测试一下,生效,日志输出了很多,和正常执行的日志对比挨着看,发现了疑点:

init_atadrive申请fseg内存失败,然后直接返回,而它的调用者init_drive_ata也直接返回,导致后续的ata格式的设备初始化没有完成。

malloc_fseg内存申请失败就要看seabios具体的内存管理结构了,此处我也是似懂非懂状态...seabios用类似于buddy的系统管理内存,所有的zone都是分配完成的,如果前面申请的内存比较多,剩下的内存可能就不足了,在allocSpace代码中就是一开始一个大块,分出一块后,就有两块,如下图:

seabio_fseg_mem_oenhan
因为申请内存是需要对齐的,所以A,B不一定会衔接到一起,最后空余的内存都算到尾巴上的一个,对应代码如下:

到现在看,即是你明白了fseg的分配,只能确认前面有人把内存都占走了,当然最可能的就是cpu个数占走的,还是对比日志看,因为前面对比我们知道fseg分配的zone id=0x000ec260,所以只看这个的内存分配,疑点很快就看到了:

此处多分配了0x20内存,日志打印是在copy_mptable中,但是内存分配的length + mpclength来自调用它的mptable_setup,其中代码:

抽出以上代码就明显看出length=cpunr * M + N;CPU个数愈多申请的内存越大,然后后面的ata初始化就无法申请内存。
但是QA测试时到86个CPU时就OK了,原因就是86个CPU导致copy_mptable也申请不到内存,反而给ata初始化留下了残羹冷炙。

修改方法比较简单,就是限制CPU的个数,可以参考http://code.coreboot.org/p/seabios/source/commit/9ee2e26255661a191b0ff9fa276d545ce59845c2/。


seabios缺陷导致特定VCPU个数的qemu找不到硬盘来自于OenHan

链接为:http://oenhan.com/seabios-qemu-vcpu-disk

发表评论