Linux-u-boot

来源:互联网 发布:西安软件新城二期商铺 编辑:程序博客网 时间:2024/06/07 18:00
 

很多产品几乎采用u-boot引导,44B0X板当然也少不了跑个u-boot,网上很多攻略,可以参考,但是不建议直接基于上面修改,自己下载一份完整的源代码,自己完完全全修改对流程更清晰

调试的话,很少有人用到的BDM和TRACE,太奢侈了,山寨板里面已经有了u-boot,配上网络就可以tftp下载调试了;还有一个比较牛B的方法,用arm-elf-gdb+ocdremot,可以gdb单步调试,但是用wiggler,加载代码到SDRAM中的速度太慢了,简直无法忍受;实际应用过程中,肯定刚开始是没有loader的,只能每次烧写到FLASH中看串口信息了呢

 

1.        u-boot解析

     搭好编译环境,会发现u-boot.bin和u-boot两个文件,其中u-boot.bin是data的二进制文件,用于下载到启动ROM进行系统引导,u-boot是elf格式的,可加载到SDRAM或SRAM中进行调试,可以objdump这个的,elf比bin要大,因为它填充了很多空白,调试中和RAM中对应的,还有一个u-boot.srec,是Motorola S-Records格式映像,下面是编译窗口

 

arm-elf-ld -Bstatic -T /home/huangyonggang/u-boot-1.1.1/board/dave/B2/u-boot.lds -Ttext 0x00000000  $UNDEF_SYM cpu/s3c44b0/start.o /

                --start-group lib_generic/libgeneric.a board/dave/B2/libB2.a cpu/s3c44b0/libs3c44b0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --no-warn-mismatch -L /usr/local/lib/gcc-lib/arm-elf/2.95.3 -lgcc --end-group /

                -Map u-boot.map -o u-boot

arm-elf-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec

arm-elf-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

2.        修改u-boot

u-boot实际就是一个小应用了,和修改ucos一样,最基础的就是,IO口初始化,时钟,串口,中断

既然是应用了,SDRAM大小,FLASH大小及驱动,网卡的驱动程序都要跑起来

一般说来,u-boot都提供了类似的芯片的start.s,汇编代码改动很少,s3c44b0x和B2类似,这里选择B2的代码来修改,下面就按照一步步的需要做修改

SDRAM和FLASH的大小,网卡芯片的使能以及网卡CS片选的地址,默认配置参数放在EEPROM中,改为FLASH中,并设置好起址地址,在B2.h中先修改好,顺便把config.mk的TEXT_BASE修改为0x0C700000(SDRAM的最高处)

 

#define CONFIG_DRIVER_RTL8019

#define RTL8019_BASE        0x06000300 /* base address         */

/* 使能8019,按照CS选择起址地址 */

 

#define PHYS_SDRAM_1        0x0c000000 /* SDRAM Bank #1 */

#define PHYS_SDRAM_1_SIZE    0x00800000 /* 8 MB */

/* 按照硬件SDRAM大小修改 */

 

#define PHYS_FLASH_1        0x00000000 /* Flash Bank #1 */

#define PHYS_FLASH_SIZE        0x00200000 /* 2 MB */

/* 按照硬件FLASH大小修改 */

 

#define CFG_ENV_IS_IN_FLASH      1  /* use FLASH for environment vars */

#define CFG_ENV_ADDR    (PHYS_FLASH_1+0x40000) 

#define CFG_ENV_OFFSET    0x40000

/* 在FLASH中储存ENV信息,并规定起址地址 */

 

//#define CFG_ENV_IS_IN_EEPROM    1    /* use EEPROM for environment vars */

/* 默认是用EEPROM储存ENV信息 */

 

在B2.c中修改board_init,这个严格按照硬件电路图IO的功能,配合spec设置好,涉及到GPIO啊,串口啊,SDRAM、FLASH并行通信,网口接口以及中端口,我是从ucos中copy过来的

FCLK 串口时钟

FLASH用的芯片同B2一样,不需要修改

8019也是一样的,唯一的修改是16B和8B的区别,8019的寄存器地址会有差别的

 

3.        u-boot中断

下面代码将把ROM中从real_vectors开始的1024字节内容,复制0x0c000008开始的目标区域中去,相当于在RAM中建立一个二级跳转表。

疑惑:为什么从0x0c000008开始?不是和最开始的跳转错开了吗?IRQ的0x0c000018不是跳转到了data_abort了?

 

/*

    now copy to sram the interrupt vector

*/

    adr    r0, real_vectors

    add    r2, r0, #1024

    ldr    r1, =0x0c000000

    add    r1, r1, #0x08

vector_copy_loop:

    ldmia    r0!, {r3-r10}

    stmia    r1!, {r3-r10}

    cmp    r0, r2

    ble    vector_copy_loop

 

......

/*************************************************/

/*    interrupt vectors    */

/*************************************************/

real_vectors:

    b    reset

    b    undefined_instruction

    b    software_interrupt

    b    prefetch_abort

    b    data_abort

    b    not_used

    b    irq

    b    fiq

 

/*************************************************/

 

undefined_instruction:

    mov    r6, #3

    b    reset

 

software_interrupt:

    mov    r6, #4

    b    reset

 

prefetch_abort:

    mov    r6, #5

    b    reset

 

data_abort:

    mov    r6, #6

    b    reset

 

not_used:

    /* we *should* never reach this */

    mov    r6, #7

    b    reset

 

irq:

    mov    r6, #8

    b    reset

 

fiq:

    mov    r6, #9

    b    reset

这是vector的跳转表,比如如果一个IRQ中断来了,直接跳到FLASH的0x18处,代码这里跳转到了0x0c000018,这里应该就是b    irq了,跳转到irq:的函数处理,因为u-boot没有中断,这里是直接复位操作的,这里应用程序可以自己接管的

 

/*

 * Jump vector table

 */

.globl _start

_start:    b       reset

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

    add    pc, pc, #0x0c000000

 

    .balignl 16,0xdeadbeef

/* 其实等价于下面的 */

    ldr pc, =0x0c000004

    ldr pc, =0x0c000008

    ldr pc, =0x0c00000c

    ldr pc, =0x0c000010

    ldr pc, =0x0c000014

    ldr pc, =0x0c000018

    ldr pc, =0x0c00001c

如果要用u-boot加载自己编译的ucos调试的话,因为ucos的二级中断向量表在0xc7f ff00,而u-boot的跳转地址是0x0c000008处,所以只需要修改u-boot的汇编成,这样ucos就接管了u-boot的中断了

 

/*

 * Jump vector table

 */

.globl _start

_start:    b       reset

    ldr pc, =0x0c7fff04

    ldr pc, =0x0c7fff08

    ldr pc, =0x0c7fff0c

    ldr pc, =0x0c7fff00

    ldr pc, =0x0c7fff04

    ldr pc, =0x0c7fff08

    ldr pc, =0x0c7fff0c

 

    .balignl 16,0xdeadbeef

4.        u-boot FLASH和SDRAM中分布

1,u-boot和应用烧入FLASH后的分布

|0x0020 0000

|

|    应用程序

|

|0x0008 0000

|

|

|

|0x0005 0000

|

|    u-boot env

|

|0x0004 0000

|

|    u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改

|

|_start = 0x0000 0000

 

2,运行起来后SDRAM的分布

 

|0x0C80 0000

|    ucos的代码会把二级中断向量表放这里的

|0xc7f ff00

|

|    stack栈

|

|0xc7f f000 堆heap end地址,紧跟的是stack栈

|

|    堆heap

|   

|

|0x0C70 0000=0x0C80 0000-1MB

|

|

|    rw段+bss        

|

|0x0C50 0000 :ucos rw段 紧跟的是ZI段(BSS)

|

|

|

|    .... 把应用程序ucos加载到这里开始跑

|

|0x0C10 0000:ucos ro段

|

|

|0xc00 0000+1024

|

|    u-boot指向的二级中断(可以修改为ucos的二级中断)

|

|0xc00 0000       

.

.

.

|0x0020 0000

|

|    应用程序(ro+rw)

|

|0x0008 0000

|

|

|

|0x0005 0000

|

|    u-boot env

|

|0x0004 0000

|

|    u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改

|

|_start = 0x0000 0000

      

3,直接网络加载u-boot后SDRAM的分布

|0x0C80 0000

|   

|0xc7f ff00

|

|

|    运行中的:从flash拷贝过来的u-boot代码

|

|0x0C70 0000=0x0C80 0000-1MB

|

|0x0C10 0000

|

|0xc00 0000+1024

|

|    u-boot指向的二级中断(可以修改为ucos的二级中断)

|

|0xc00 0000

.

.

.

|0x0020 0000

|

|   

|

|0x0008 0000

|

|

|

|0x0005 0000

|

|    u-boot env

|

|0x0004 0000

|

|    u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改

|

|_start = 0x0000 0000

          

一边对照代码,一边对照串口打印信息,整个u-boot的思路很明确

-->cpu/s3c44b0/start.s(CONFIG_USE_IRQ 没有定义的,flash中时候,经过start,start_code,cpu_init_crit;拷贝code+data;拷贝0xc00 0008;stack_setup)

-->lib_arm/board.c(start_armboot)

    -->board/.../flash.c

    -->board/.../lowlevel_init.s

-->start_armboot

-->init_fnc_ptr

-->

init_fnc_t *init_sequence[] = {

    cpu_init,        /* basic cpu dependent setup */

    board_init,        /* basic board dependent setup */

    interrupt_init,        /* set up exceptions */

    env_init,        /* initialize environment */

    init_baudrate,        /* initialze baudrate settings */

    serial_init,        /* serial communications setup */

    console_init_f,        /* stage 1 init of console */

    display_banner,        /* say that we are here */

    dram_init,        /* configure available RAM banks */

    display_dram_config,

#if defined(CONFIG_VCMA9)

    checkboard,

#endif

    NULL,

};

-->这是一个函数数组,会逐步调下面函数做初始化

board_init(board/...)

env_init(common/env_eeprom.c)

serial_init(cpu/s3c44b0/serial.c)

console_init_f(common/console.c)

display_banner(lia_arm/board.c)

(到这里就开始打印下面信息了)  

 

U-Boot 1.1.1 (Oct 21 2008 - 04:54:09)

 

U-Boot code: 0C700000 -> 0C719218  BSS: -> 0C71D9E4

display_dram_config(lia_arm/board.c):

RAM Configuration:

Bank #0: 0c000000  8 MB

display_flash_config(lia_arm/board.c)

(到这里就开始打印下面信息了)

 

Flash:  2 MB

env_relocate

 

*** Warning - bad CRC, using default environment

console_init_r(lia_arm/board.c)

(到这里就开始打印下面信息了)

 

In:    serial

Out:   serial

Err:   serial

main_loop(lia_arm/board.c)

-->abortboot若没有键按下则run_command (s, 0)(s为默认的bootcmd,这个是事先设置好的env bootcmd=run jffsboot) do_bootm  do_bootm_linux

(到这里就开始打印下面信息了)

 

Hit any key to stop autoboot:

 

 

5.        小结

先把u-boot代码流程弄清楚,要不然都不知道在哪里改代码,最好是参考类似的板子操作,走了不少弯路,有TRACE这样的牛B工具最好,不过我用gdb+ocdremot单步调试也很爽,那里初始化不对一目了然,就是下载到SDRAM时速度有点慢

MCLK这个我搞糊涂了,MCLK到底是根据外部的晶振来判断的吗???