分类: 嵌入式
2014-02-23 13:48:22
8974 启动之初死在kernel里面的问题
现象:
机器开机,起不来,串口log打印如下就没有了:
[1210] Updating device tree: done
[1220] booting linux @ 0x8000, ramdisk @ 0x2000000 (468121), tags/device tree @ 0x1e00000
Uncompressing Linux... done, booting the kernel.
分析:
1,有可能是kernel启动地址不对
2, 有可能是devices tree 不匹配
3,有可能是machine ID 不对 或者是processor ID 不对
4, 如果可以跑到start_kernel 表示以上假设都不成立
5,某些驱动的初始化出了问题
解决步骤:
首先,我们用T32 跟踪代码,打断点可以到start_kernel ,说明前面三点都不成立
其次,我们用T32一步步跟,可以跑到cpu_idle ,以为是内核初始化都跑完了,顿时无语了。
第三,其实可以跑到cpu_idle 并不表示内核初始化都跑完了,跑cpu_idle 的是进程0 ,在此之前已经在rest_init函数里面开了进程1 ,kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
第四步,在进程1中会进行外设的初始化,代码如下:
do_basic_setup 中会先后调用driver_init初始化驱动模型 do_initcalls 初始化各种级别的外设驱动
解决问题:
通过T32跟踪,我们可以确认,机器是跑在这一步do_initcalls 初始化某些驱动代码的时候挂掉了,但是具体是哪一个呢?用T32就不好跟了。
在上一步中提到各种级别的外设驱动初始化,这一点是解决这个问题的关键,因为截至到目前我们只能用T32来跟踪代码,要定位问题非常费力,如果有串口那就好了!但是没有,怎么办?
我们都知道外设驱动都是有级别的,代码如下:
static void __init do_initcalls(void)
{
int level;
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
do_initcall_level(level);
}
根据level级别来初始化驱动,串口的也在其中,如果我们把串口的初始化级别提高到最先初始化,那么串口log 就可以出来了。
打印出串口log 后,可以看到死机是内核panic引起的,引起panic的打印是:
L2 master port error detected
调查发现,在代码Cache_erp.c (arch\arm\mach-msm )中,有规定一旦出现该错误立即panic。
那么,为了让机器先起来,我们可以先把这个panic的判断规避掉,以后再来调查为什么会有L2 的error。
如此在代码中做如下修改即可:
#ifdef CONFIG_MSM_L2_ERP_PORT_PANIC
#define ERP_PORT_ERR(a) panic(a) // 把这句改成ERP_PORT_ERR(a) WARN(1, a)