现象描述:
在MTK平台移植Xen,利用Xen构建的dom0启动linux_kernel从而启动android,在调试过程中需要在linux_kernel的汇编阶段增加打印log确认dom0中的kernel是否启动,在增加log的打印过程,引发了Xen中的panic问题,即说找不到guest os。
在进入linux_kernel头文件head.s中b primary_entry和efi_signature_nop(这是汇编的一个宏也是一条指令)之间增加如图所示的打印会造成上面Xen panic的问题,而在b primary_entry之后增加打印并不会引起Xen中panic的问题。
现象原因分析:
为了分析问题需要将内核编译生成的vmlinux反汇编对比一下指令码。
反汇编命令:
aarch64-linux-gnu-objdump -S vmlinux > vmlinux.S
反汇编结果:
依据panic的日志不停增加log找到Xen中发生panic的源码所在之处,定位发生panic的原因
发生panic的日志:
正常运行的日志:
对比日志所定位到xen解析kernel的函数实现中
static int __init kernel_zimage64_probe(struct kernel_info *info,
paddr_t addr, paddr_t size)
{
/* linux/Documentation/arm64/booting.txt */
#pragma pack(1)
struct {
uint32_t magic0;
uint32_t res0;
//uint64_t res7;
//uint32_t res8;
uint64_t text_offset; /* Image load offset */
uint64_t res1;
uint64_t res2;
/* zImage V1 only from here */
uint64_t res3;
uint64_t res4;
uint64_t res5;
uint64_t res7;
uint32_t res8;
uint32_t magic1;
uint32_t res6;
} zimage;
#pragma pack()
uint64_t start, end;
if ( size < sizeof(zimage) )
return -EINVAL;
copy_from_paddr(&zimage, addr, sizeof(zimage));
printk("0x%x 0x%x\n",zimage.magic0,zimage.magic1);
if ( zimage.magic0 != ZIMAGE64_MAGIC_V0 &&
zimage.magic1 != ZIMAGE64_MAGIC_V1 )
return -EINVAL;
/* Currently there is no length in the header, so just use the size */
start = 0;
end = size;
/*
* Given the above this check is a bit pointless, but leave it
* here in case someone adds a length field in the future.
*/
if ( (end - start) > size )
return -EINVAL;
info->zimage.kernel_addr = addr;
printk("zimage.kernel_addr: 0x%lx\n",info->zimage.kernel_addr);
info->zimage.len = end - start;
info->zimage.text_offset = zimage.text_offset;
info->load = kernel_zimage_load;
info->type = DOMAIN_64BIT;
return 0;
}
结合前面反汇编的结果和打印的信息的log,可以发现正常运行zimage.magic0应该是0xfa405a4d,而zimage.magic1应该等于0x644d5241,可以明显看出panic发的日志中zimage.magic1却是等于0。通个分析反汇编的结果可以算出正常zimage.magic1是相对ffffffc008000000偏移了56个字节,而增加log之后,zimage.magic1需要偏移68个字节才能得到0x644d5241。
因为后面copy_from_paddr(&zimage, addr, sizeof(zimage));会从内核所在地址拷贝数据到zimage的结果里面来,所以关注这里的zimage结构体,其中res7和res8是我自己添加的,经过前面的分析要想将 zimage.magic1的变成0x644d5241,需要在原来的基础上偏移12个字节,也就是8+4个字节就行,在magic1前+12字节,重新编译刷机,发现遇到新的问题,Xen无法将dom0的kernel拷贝到dom0的物理内存中(相对虚拟机是物理的,相对Xen_hypervisor就是虚拟的)
正常拷贝到00000000c000000:
拷贝失败:
根据这个kernel_zimage_place(info),可以看到00000000c000000这个加载值是由下面这个计算出来,等于说正常运行时的text_offset偏移量应该为0,而发生panic的原因是因为偏移位置被改变了,此时text_offset为0x390001f05807ffcf,接下来调整结构体zimage中text_offset,使其偏移之后值为0就行。
修改的同时注意取消掉结构体内存对齐的问题,在原先的基础上偏移res7和res8(12个字节)就行。
注意:通过Xen构建的dom0启动kernel,在通过设备树传递kernel的大小必须是解压之后的大小,至少传递的kernel大小需要大于解压之后,后续Xen需要依据这个kernel大小建议对等页表。就这块内存映射到真实的设备物理地址上去。(在之前的调试中由于我传递的kernel的大小是为未解压的内核大小-20M左右,但从反汇编的结果a9d0000看出来这个是远远大于压缩内核的大小的)。
panic解决之后的现象:
这个时候看到swapper就可以确认dom0启动kernel是成功了