用仿真器解决Linux内核加载问题

时间:2022-05-25 23:37:49

快乐虾

http://blog.csdn.net/lights_joy/

欢迎转载,但请保留作者信息


在使用合众达DVS6467T开发板时遇到一个问题,在内核选项中加上initramfs的支持,结果在bootm时内核加载失败:

## Booting image at 8e000000 ...

   Image Name:   Linux-2.6.10_mvl401-davinci_evm-

   Image Type:   ARM Linux Kernel Image (uncompressed)

   Data Size:    3479208 Bytes =  3.3 MB

   Load Address: 80008000

   Entry Point:  80008000

   Verifying Checksum ... OK

OK

 

Starting kernel ...

 

UncompressingLinux..........................................................................................................................................................done, booting the kernel.

然后就没有下文了。

这种情况其实在刚开始调试内核时经常会遇到,通常也只能通过内核功能的添加和删除来初步判断问题的位置。但我们现在有仿真器这个神器,就不再需要这么摸索了。

下面有请仿真器大神上场。

首先启动uboot并将内核tftp到板上。Bootm后出现上文所提的现象。

ccs 下用仿真器连接设备:

用仿真器解决Linux内核加载问题

用仿真器解决Linux内核加载问题

很显然pc跑飞了,但此时已经无法得到更多信息了。

再来一次。

uboot将内核tftp下载到设备上,在bootm之前用ccs连接到设备,此时ccs将在uboot的代码中中断下来:

用仿真器解决Linux内核加载问题

添加两个断点:

用仿真器解决Linux内核加载问题

因为0x80008000这个地址是Linux内核的入口地址。

ccs中继续执行,uboot继续工作,我们也可以通过串口和uboot进行交互。

在串口中输入bootm,此时仿真器将在内核入口处中断下来:

用仿真器解决Linux内核加载问题

通过单步执行,很容易发现程序跑飞的位置:

/*

 * The following fragment of code is executedwith the MMU on, and uses

 * absolute addresses; this is not positionindependent.

 *

 * r0  = cp#15 control register

 * r1  = machine ID

 * r9  = processor ID

 */

    .type   __mmap_switched, %function

__mmap_switched:

    adr r3,__switch_data + 4

 

    ldmia   r3!,{r4, r5, r6, r7}

    cmp r4,r5              @ Copy data segment if needed

1:  cmpne   r5,r6

    ldrne   fp,[r4], #4

    strne   fp,[r5], #4

    bne 1b

 

    mov fp,#0              @ Clear BSS (and zero fp)

1:  cmp r6,r7

    strcc   fp,[r6],#4

    bcc 1b

在这里清除BSS段时程序飞了。通过检查各寄存器的值感觉并没有什么异常,但当内核执行到这里时,可以发现mmu已经启用了,那么问题估计和这个有关了。

看看之前执行的MMU相关的一段代码:

/*

 * Setup the initial page tables.  We only setup the barest

 * amount which are required to get the kernelrunning, which

 * generally means mapping in the kernel code.

 *

 * r8  =machinfo

 * r9  =cpuid

 * r10 = procinfo

 *

 * Returns:

 *  r0,r3, r5, r6, r7 corrupted

 *  r4 =physical page table address

 */

    .type   __create_page_tables, %function

__create_page_tables:

    ldr r5,[r8, #MACHINFO_PHYSRAM]    @ physram

    pgtbl   r4,r5              @ page table address

………..

    /*

     * Nowsetup the pagetables for our kernel direct

     *mapped region.  We round TEXTADDR down tothe

     *nearest megabyte boundary.  It is assumedthat

     * thekernel fits within 4 contigous 1MB sections.

     */

    add r0,r4,  #(TEXTADDR & 0xff000000)>> 18   @ start of kernel

    str r3,[r0, #(TEXTADDR & 0x00f00000) >> 18]!

    add r3,r3, #1 << 20

    str r3,[r0, #4]!          @ KERNEL + 1MB

    add r3,r3, #1 << 20

    str r3,[r0, #4]!          @ KERNEL + 2MB

    add r3,r3, #1 << 20

    str r3,[r0, #4]           @ KERNEL + 3MB

……

很显然这里只配置了内核代码开始的3M空间,而我们的内核在加上initramfs之后,bss段的一部分数据是处于3M之外的,这也是正是内核跑飞的原因!!

知道原因就好办了,修改下这段代码:

    /*

     * Nowsetup the pagetables for our kernel direct

     *mapped region.

     */

    add r0,r4,  #(TEXTADDR & 0xff000000)>> 18

    str r3,[r0, #(TEXTADDR & 0x00f00000) >> 18]!

    ldr r6,=(TEXTADDR + 0x01000000 - 1)

    add r0,r0, #4

    add r6,r4, r6, lsr #18

1:  cmp r0,r6

    add r3,r3, #1 << 20

    strls   r3,[r0], #4

    bls 1b

再编译运行,搞定!!