ppc linux内核,用BDI2000快速定位PPC Linux内核Uncompressing Kernel Image

用BDI2000快速定位PPC Linux内核Uncompressing Kernel Image ... OK后无输出问题

【摘要】本文以MPC8270处理器和Linux2.5.15.5内核为例,讲述了用BDI2000快速定位PPC

Linux内核串口无输出的问题。分析了典型的原因并详细介绍了用BDI2000快递定位问题的基本方法,及利用GDB查看printk输出buffer

的方式,模拟串口打印输出来迅速定位。

【关键字】BDI2000  GDB  MPC8270  Linux  Uncompressing  printk  printk_buf

病症

内核移植最痛苦的莫过于跳到内核入口后,无任何输出,这时候真是丈二和尚摸不着头脑啊

对于PPC Linux内核,典型的现象如下,

=> bootm 0x400000

*  kernel: cmdline image address = 0x00400000

## Booting kernel from Legacy Image at 00400000 ...

Image Name:   Linux-2.6.19

Created:      2009-11-03   8:09:41 UTC

Image Type:   PowerPC Linux Kernel Image (gzip compressed)

Data Size:    1285009 Bytes =  1.2 MB

Load Address: 00000000

Entry Point:  00000000

Verifying Checksum ... OK

kernel data at 0x00400040, len = 0x00139b91 (1285009)

Uncompressing Kernel Image ... OK

kernel loaded at 0x00000000, end = 0x002cf086

## Current stack ends at 0x03f96530

## cmdline at 0x007fff00 ... 0x007fff00

## kernel board info at 0x007ffeb0

bd address  = 0x03F96AB6

memstart    = 0x00000000

memsize     = 0x00000000

flashstart  = 0x40000000

flashsize   = 0x01000000

flashoffset = 0x00042000

sramstart   = 0x00000000

sramsize    = 0x00000000

immr_base   = 0xFFF00000

bootflags   = 0x00000001

vco         =    330 MHz

sccfreq     = 82.500 MHz

brgfreq     = 20.625 MHz

intfreq     =    198 MHz

cpmfreq     =    165 MHz

busfreq     =     66 MHz

ethaddr     = 00:A0:1E:A8:7B:CB

IP addr     = 150.236.68.211

baudrate    =  19200 bps

## No init Ramdisk

ramdisk start = 0x00000000, ramdisk end = 0x00000000

## initrd_high = 0xffffffff, copy_to_ram = 1

ramdisk load start = 0x00000000, ramdisk load end = 0x00000000

## Transferring control to Linux (at address 00000000) ...

Booting using board info...

待审嫌疑犯

串口无输出,一般有以下几个典型的可疑:

1、内核中串口是否正确配置了,和开发板上目前的调试串口是否一致

2、内核使用的波特率是否和当前的调试串口一致

3、内核的串口驱动本身有问题

4、在串口初始化之前,由于内核本身移植的有问题,系统可能已经crash了

对于1和2,这都需要bootargs参数和内核一致,如console=ttyCPMx,115200

当系统有多个串口时,console采用第几个串口这个配置则尤其重要

另外关于波特率的解析,要确保内核和Uboot对于bd_t结构体的定义一致,因为内核启动时很多启动信息都是从这个板子配置信息得到的,如果解析有误的话可能会存在问题

对于3,这种情况很少见,因为对于已经支持的CPU系列,串口驱动都是比较完善的,只是一个配置的问题

对于4,内核移植需要修改的文件,不在本文讨论之列

若上述几个疑问都确认过了,串口仍然没有输出,则只能借助点灯或者仿真器来定位内核究竟在哪一步出问题了

BDI2000单步调试

用BDI2000调试PPC Linux内核的基本步骤,可参加

http://blog.csdn.net/sailor_8318/archive/2009/11/10/4795287.aspx

GDB和BDI2000调试PPC Linux内核

在MMU开启之前,系统运行的都是汇编代码,这个时候并没有任何printk打印输出,如果此阶段内核crash,则现象就是Uncompressing Kernel Image ... OK之后没有任何反应

这个时候可以阶段性的设置断点,快速定位在跳转到start_kernel之前,内核是否运行正常。若不正常,则回退,定位出问题的大概范围,然后单步调试

断点显示printk输出

当进入start_kernel后,此时已经建立起了完善的C代码运行环境,开始调用

Printk打印系统关键的启动信息,当然在串口未真正初始化之前,printk将打印信息都暂时存储在了一个全局的buffer之中__log_buf,其大小在内核选项中可配置

系统最早的串口输出在console_init之后,若console没有问题,则前期积累的打印信息将在此之后真正输出到物理串口上。

若程序运行到console_init之后,仍然没有crash且没有串口输出,则说明串口有问题。若程序未能运行到console_init,则说明在start_kernel入口到console_init之间的代码有问题。则只能跟踪了。

当系统出现可控的异常时,一般都会有打印信息。此时不是没有串口吗?怎么看打印信息了?

每次调用printk时,都会将本次待打印的信息保存在一个static的数组中printk_buf,在vprintk函数中设置断点,待将本次打印信

息解析后存储在printk_buf中,即可通过host断的GDB环境查看printk_buf中的打印信息,相当于主机环境做了一个虚拟的串口啦

asmlinkage int printk(const char *fmt, ...)

{

va_list args;

int r;

va_start(args, fmt);

r = vprintk(fmt, args);

va_end(args);

return r;

}

/* cpu currently holding logbuf_lock */

static volatile unsigned int printk_cpu = UINT_MAX;

asmlinkage int vprintk(const char *fmt, va_list args)

{

unsigned long flags;

int printed_len;

char *p;

static char printk_buf[1024];

static int log_level_unknown = 1;

preempt_disable();

if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id())

/* If a crash is occurring during printk() on this CPU,

* make sure we can't deadlock */

zap_locks();

/* This stops the holder of console_sem just where we want him */

local_irq_save(flags);

lockdep_off();

spin_lock(&logbuf_lock);

printk_cpu = smp_processor_id();

/* Emit the output into the temporary buffer */

printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);

/*

* Copy the output into log_buf.  If the caller didn't provide

* appropriate log level tags, we insert them here

*/

for (p = printk_buf; *p; p++) {

if (log_level_unknown) {

通过查看printk的参数const char *fmt,可大概知道相关的打印信息,但并没有完全解析,在printed_len =

vscnprintf(printk_buf, sizeof(printk_buf), fmt,

args)之后,打印信息便保存在了printk_buf中。

GDB的x/s printk_buf或者display printk_buf都可以查看printk_buf中的内容。断点设置在_len =

vscnprintf(printk_buf, sizeof(printk_buf), fmt,

args)之后即可,每次系统有关键的信息打印时,在此即可看到,相当于串口正常工作了。

打印调试比GDB单步调试要高效的多,内核在关键启动过程中都有打印输出,因此根据虚拟的打印信息可以快速定位问题。

Breakpoint 3, vprintk (fmt=, args=)

at kernel/printk.c:554

554             for (p = printk_buf; *p; p++) {

(gdb) x/s printk_buf

0xc01d120c :   "Linux version 2.6.15.5

(sailing@cnbjc0052) (gcc version 4.2.2) #2 Fri Nov 6 12:09:22 CST

2009\n"

(gdb) display printk_buf

1: printk_buf ="Linux version 2.6.15.5 (sailing@cnbjc0052) (gcc version 4.2.2) #2 Fri Nov 6 12:09:22 CST 2009\n"

(gdb) c

Breakpoint 3, vprintk (fmt=, args=)

at kernel/printk.c:554

554             for (p = printk_buf; *p; p++) {

1: printk_buf = "<5>Kernel command line: \n\000, LIFO

batch:0\n\000 (gcc version 4.2.2) #2 Fri Nov 6 12:09:22 CST 2009\n",

'\0' 发现内核命令行参数既然是空???????如果console参数有问题的话,内核当然无法正常初始化调试串口啦

仔细检查bootargs,发现因为手动设置的bootargs,拷贝时不当心拷贝成了boottargs,因此uboot无法识别这个参数,导致启动时传递给内核的启动参数是空串

重新设置bootargs,由下列打印信息可以看出,内核正确解析了U-boot传递过来的启动参数

1: printk_buf = "<5>Kernel command line: console=ttyCPM1,19200

root=/dev/nfs rw

nfsroot=150.236.70.104:/home/sailing/eldk_tool/ppc_82xx

ip=147.128.19.123:150.236.70.104:147.128.19.1:255.255.255.128:eric::off\n",

'\

在console_init之后即有打印信息输出啦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值