ARM下Kernel panic - not syncing: Attempted to kill init!错误分析

ARM下Kernel panic - not syncing: Attempted to kill init!错误分析

1. 前言

      最近在通过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

2. 不同busybox和编译器版本组合结果

       下面是我选择的不同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命令行

3. 查找Kernel panic - not syncing: Attempted to kill init!错误

3.1 确认引起错误的原因

     根据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每一位对应要开启的调试信息。

ARM下Kernel panic - not syncing: Attempted to kill init!错误分析_第1张图片

        然后再次启动系统,这时可以看到多了两行打印信息,如下:


       这时,从打印看出,我们知道是出现了未定义的指令导致kernel panic错误的,可在内核 (arch/arm/kernel/traps.c) 中找到相关的异常处理函数。 

ARM下Kernel panic - not syncing: Attempted to kill init!错误分析_第2张图片

       接下来我们要找出是什么未定义的指令,通过命令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)

ARM下Kernel panic - not syncing: Attempted to kill init!错误分析_第3张图片

3.2 解决错误

       既然知道了是rfs这条未定义的浮点指令导致kernel panic错误的,那我们就要看一下为什么这条指令是未定义的。

3.2.1 编译器浮点相关参数的知识

      由于一个浮点数操作最后是翻译成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)中。

3.2.2 解决办法

      s3c6410的处理器是ARM1176JZF-S,ARM11是ARMv6架构,该处理器支持 VFP coprocessor,因此s3c6410是支持VFP硬件浮点指令的。在内核的Floating point emulation配置中,看arm是否支持硬浮点协处理器,支持的话选择VFP,不支持选择NWFPE,我们配置的是VFP。

ARM下Kernel panic - not syncing: Attempted to kill init!错误分析_第4张图片

        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。

4. 总结

       本文分析了在通过busybox制作的rootfs,低版本的编译器编译的busybox,会导致Kernel panic错误的原因,以及对应的解决办法。

5. 参考资料

[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

你可能感兴趣的:(Env,config,Linux,kernel,File,system)