ARM下Kernel panic - not syncing: Attempted to kill init!错误分析
最近在通过busybox制作rootfs的时候,发现使用不同版本的交叉编译器去编译busybox的时候,有些版本编译器编译出的busybox可执行文件不能用,它会导致系统启动过程中在加载init程序时出错。本文将分析怎么去查找这个错误具体是由什么引起的,以及如何才能解决该错误。如果我在分析中有什么不正确的地方,希望大家能够指正,谢谢。
我的开发环境如下
系统环境:Ubuntu 12.04(lsb_release -a命令查看)
交叉编译工具:arm-linux-gcc 3.3.2、arm-linux-gcc 4.2.2、arm-linux-gcc 4.5.1
busybox:busybox1.13.3、busybox1.25.0
linux内核:2.6.29
soc:s3c6410
下面是我选择的不同busybox和交叉编译器版本的组合。
(1)busybox1.13.3 + arm-linux-gcc 3.3.2,出现如下错误
(2)busybox1.13.3 + arm-linux-gcc 4.2.2,没有问题,能正常启动进入shell命令行
(3)busybox1.25.0 + arm-linux-gcc 4.2.2,没有问题,能正常启动进入shell命令行
(4)busybox1.25.0 + arm-linux-gcc 4.5.1,没有问题,能正常启动进入shell命令行
根据2中不同版本busybox和arm-linux-gcc的实验结果,第1个组合出现这个错误,肯定跟编译器的版本有关。但是具体是什么原因导致这个kernel panic的错误呢?还得继续去分析。
我们打开在内核中配置CONFIG_DEBUG_USER=y,并在uboot 启动参数bootargs 中添加 user_debug=31,打开全部调试信息,例如 setenv bootargs console=ttySAC0,115200 user_debug=31 saveenv。下图是user_debug每一位对应要开启的调试信息。
然后再次启动系统,这时可以看到多了两行打印信息,如下:
这时,从打印看出,我们知道是出现了未定义的指令导致kernel panic错误的,可在内核 (arch/arm/kernel/traps.c) 中找到相关的异常处理函数。
接下来我们要找出是什么未定义的指令,通过命令arm-linux-objdump -D -S busybox > tmp,可将rootfs bin目录中busybox可执行文件反汇编,然后查看pc=000d3f38的地方,可知我们要找的就是rfs这条未定义指令。
我查了下这条指令的含义,在arm information center里的描述,rfs指令是指读浮点状态寄存器到指定的 ARM 寄存器中,也就是说这是浮点指令。(http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0041c/ch11s03s03.html)
既然知道了是rfs这条未定义的浮点指令导致kernel panic错误的,那我们就要看一下为什么这条指令是未定义的。
由于一个浮点数操作最后是翻译成VFP指令,还是翻译成fpa,或者是softfloat是编译器决定的。也就是说假如我们应用程序中用到了浮点运算,那这种运算由哪种指令去执行,可以由编译器参数去决定,即在编译器配置参数中显式指定将浮点运算翻译成何种浮点指令。
下面是一些相关概念,可参考文章“[3] ARM GCC浮点相关总结...”
(1)名字解释:
ABI(Application Binary Interface):应用程序二进制接口。
FPE(Floating Point Emulation):浮点运算仿真,是使用软件仿真了FPA协处理器的执行。
FPA(Floating Point Accelerator):浮点累加协处理器,ARM上提供了一组协处理器指令专门实现浮点运算。但这需要硬件支持,具体某一处理器上是否有FPA协处理器支持,可以查看ARM相关手册。
VFP(vector floating point):矢量浮点,由vfp硬浮点处理器处理器支持。
(2)编译版本问题:
GCC 4.0 为分界线
4.0版本以下,由于采用OABI接口,其对浮点的支持不太好
4.0版本以上,采用了新的EABI接口,其对软浮点和硬浮点的支持都比较好。
(3)编译器相关的参数:
(3-1)-mfloat-abi来指定浮点运算处理方式
-mfloat-abi=soft 使用这个参数时,其将调用软浮点库(softfloat lib)来支持对浮点的运算,GCC编译器已经有这个库了,一般在libgcc里面。这时根本不会使用任何浮点指令,而是采用常用的指令来模拟浮点运算。 但使用的ARM芯片不支持硬浮点时,可以考虑使用这个参数。在使用这个参数时,连接时一般会出现下面的提示:
undefined reference to `__aeabi_fdiv'
或者类似的提示,主要因为一般情况下连接器没有去主动寻找软浮点库,这时使用将libgcc库加入即可。
-mfloat-abi=softfp
-mfloat-abi=hard
这两个参数都用来产生硬浮点指令,至于产生哪里类型的硬浮点指令,需要由-mfpu=xxx参数来指令。这两个参数不同的地方是:
-mfloat-abi=softfp生成的代码采用兼容软浮点调用接口(即使用-mfloat-abi=soft时的调用接口),这样带来的好处是:兼 容性和灵活性。库可以采用-mfloat-abi=soft编译,而关键的应用程序可以采用-mfloat-abi=softfp来编译。特别是在库由第 三方发布的情况下。
-mfloat-abi=hard生成的代码采用硬浮点(FPU)调用接口。这样要求所有库和应用程序必须采用这同一个参数来编译,否则连接时会出现接口不兼容错误。
(3-2)-mfpu来指定浮点协处理的类型
-mfpu=vfp
-mfpu=fpa
...
前面已经讲述了,-mfpu参数就是用来指定要产生哪种硬浮点指令。常见的有vfp,fpa等。
另外,可以查看“[4] ARM GCC浮点编译选项...”这篇文章,里面讲了各参数的使用的例子。同时,这篇文章对编译浮点参数从另一角度作了解释:
在编译带有浮点参数的函数时,有三种可能的编译选项:
-mfloat-abi=soft
-mfloat-abi=softfp
-mfloat-abi=hard (hardfp)
"soft"选项:表明不使用FPU硬件,而是使用GCC的整数算术运算来模拟浮点运算。
"softfp"选项:表明要使用FPU硬件来做浮点运算,只是,函数的参数传递到整数寄存器(r0-r3)中,然后再传递到FPU中。
"hard"选项:表明要使用FPU硬件来做浮点运算,并且,函数的参数直接传递到FPU的寄存器(s0、d0)中。
s3c6410的处理器是ARM1176JZF-S,ARM11是ARMv6架构,该处理器支持 VFP coprocessor,因此s3c6410是支持VFP硬件浮点指令的。在内核的Floating point emulation配置中,看arm是否支持硬浮点协处理器,支持的话选择VFP,不支持选择NWFPE,我们配置的是VFP。
rfs和wfs等是FPA的指令集,FPA是Old ABI里面的硬件浮点指令集,也就是说arm-linux-gcc 3.3.2编译器将busybox浮点运算翻译成了FPA指令集中的指令。而我们硬件支持的是VFP指令,且内核中只配置了支持VFP浮点运算。
因此,第一种解决办法,就是在内核中配置再添加NWFPE的配置,使用浮点运算仿真,通过使用软件仿真FPA协处理器的执行。我们可以在arch/arm/nwfpe/fpopcode.h中看到有定义RFS指令。
/*
===
=== Definitions for register transfer and comparison instructions
===
*/
#define MASK_CPRT 0x0e000010 /* register transfer opcode */
#define MASK_CPRT_CODE 0x00f00000
#define FLT_CODE 0x00000000
#define FIX_CODE 0x00100000
#define WFS_CODE 0x00200000
#define RFS_CODE 0x00300000
#define WFC_CODE 0x00400000
#define RFC_CODE 0x00500000
#define CMF_CODE 0x00900000
第二种办法,就是使用更高版本的编译器,例如前面用的arm-linux-gcc 4.2.2或arm-linux-gcc 4.5.1去编译busybox。
本文分析了在通过busybox制作的rootfs,低版本的编译器编译的busybox,会导致Kernel panic错误的原因,以及对应的解决办法。
[1] 关于出现kernel panic错误的讨论文章,可打开user_debug去查看调试信息
http://www.friendlyarm.net/forum/topic/1326
[2] 如何打开user_debug调试
http://blog.csdn.net/adaptiver/article/details/12778621
[3] ARM GCC浮点相关总结,编译器参数概念及内核浮点配置
http://www.cnblogs.com/wlei/archive/2012/09/03/2669268.html
[4] ARM GCC浮点编译选项,各参数的使用的例子
http://blog.csdn.net/jijiagang/article/details/12952681
[5] ARM(S3C2440 )下解决的非法指令问题(Illegal instruction)的分析及解决过程
http://blog.chinaunix.net/uid-25756789-id-3420210.html
[6] illegal instruction非法指令的解决思路
http://blog.csdn.net/chyxwzn/article/details/8879750?utm_source=tuicool