uboot2015.04代码执行流程

记录uboot源码的下载地址。http://ftp.denx.de/pub/u-boot/

 

其实记录这些东西,我当时的处境是那么多相同名字的文件,相同名字的函数,自己不知道对于i.MX6dl来说,到底执行的是哪个文件里的哪个函数。

所以这里涉及到特定文件、函数的时候,会标红

 

说到当初分析代码执行流程,找了N久,找到了链接文件。当初又是打算分析Makefile,又是看编译的最后一步打印日志,闹的头都大了。找这些东西真的坑爹。

我就不知道到底有没有文档来明明白白的把这些问题说清楚。倒是带了很多的ReadMe文件,但是打开一看,你妹的看完这个文件我tm修仙成功了都。。。

 

/arch/arm/cpu/u-boot.lds还有一个是u-boot-spl.lds,我们没用SPL机制,所以不提他了

文件内容如下:

 1 ENTRY(_start)  最开始的入口
 2 SECTIONS
 3 {
 4     . = 0x00000000;
 5 
 6     . = ALIGN(4);
 7     .text :
 8     {
 9         *(.__image_copy_start)  需要拷贝的image文件,开始位置标志
10         *(.vectors)             中断向量表
11         CPUDIR/start.o (.text*) start.S函数的代码段,不含数据段
12         *(.text*)
13     }
14 
15 
16         CONFIG_ARMV7_SECURE_BASE相关的,略
17 
18         . = ALIGN(4);
19     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
20 
21     . = ALIGN(4);
22     .data : {
23         *(.data*)
24     }
25 
26     . = ALIGN(4);
27 
28     . = .;
29 
30     . = ALIGN(4);
31     .u_boot_list : {
32         KEEP(*(SORT(.u_boot_list*)));
33     }
34 
35     . = ALIGN(4);
36 
37     .image_copy_end :
38     {
39         *(.__image_copy_end) 需要拷贝的image文件,开始位置标志
40                 不包括rel_dyn数据,和bss段的数据
41     }
42 
43     .rel_dyn_start :
44     {
45         *(.__rel_dyn_start)
46     }
47 
48     .rel.dyn : {
49         *(.rel*)
50     }
51 
52     .rel_dyn_end :
53     {
54         *(.__rel_dyn_end)
55     }
56 
57     .end :
58     {
59         *(.__end)
60     }
61 
62     _image_binary_end = .;
63 
64 
65 /*  bss段
66  * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
67  * __bss_base and __bss_limit are for linker only (overlay ordering)
68  */
69 
70     .bss_start __rel_dyn_start (OVERLAY) : {
71         KEEP(*(.__bss_start));
72         __bss_base = .;
73     }
74 
75     .bss __bss_base (OVERLAY) : {
76         *(.bss*)
77          . = ALIGN(4);
78          __bss_limit = .;
79     }
80 
81     .bss_end __bss_limit (OVERLAY) : {
82         KEEP(*(.__bss_end));
83     }
84 
85      //其他数据
86     .dynsym _image_binary_end : { *(.dynsym) }
87     .dynbss : { *(.dynbss) }
88     .dynstr : { *(.dynstr*) }
89     .dynamic : { *(.dynamic*) }
90     .plt : { *(.plt*) }
91     .interp : { *(.interp*) }
92     .gnu.hash : { *(.gnu.hash) }
93     .gnu : { *(.gnu*) }
94     .ARM.exidx : { *(.ARM.exidx*) }
95     .gnu.linkonce.armexidx : { *(.gnu.linkonce.armexidx.*) }
96 }
97                 

 

最开始的入口是_start,他在vectors.S arch\arm\lib\vector.S

他的作用就是中断向量表,第一个跳转位置为reset函数,其后的各个函数,是中断入口地址,不过uboot的初始化过程是不涉及中断的,这里先忽略他们。

 

__image_copy_start这个玩意儿就是个标号,表示需要拷贝的image文件的开始位置。

在SourceInsight里面搜索这个标号,发现定义在 arch\arm\lib\sections.c中。略

 

 

 

于是找到了入口点,i.mx6dl是armv7架构的,所以是arch\arm\cpu\armv7\start.S文件。

首先执行reset标号处的内容,代码的注释很详细:disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl    cpu_init_cp15           @[this two func] ALL in this file
    bl    cpu_init_crit           @here is lowlevel_init
#endif

    bl    _main           @ arch\arm\lib\crt0.S    

 

两个cpu_init都在当前文件中。不管他俩,直接看跳到_main里面做了什么。

另外这个

CONFIG_SKIP_LOWLEVEL_INIT

有没有定义呢,抡起Linux下的板斧,因为别的命令不会,只会grep * -nR -nwR和find -name哈哈哈

搜索【此前已经问飞凌开发板的客服知道了配置文件是include/configs/mx6sabre_common.h

 grep '#define CONFIG_SKIP_LOWLEVEL_INIT' include/configs/mx* -nR

 

单引号表示搜索的东东是一个整体。

发现没有在include/configs/mx6sabre_common.h当中定义。

 

下面到_main里面看看,目录在 arch\arm\lib\crt0.S

详细的内存分布,在这个函数里面开始形成,但这不是我的重点,我的重点就是管你怎么分布的呢,我又不写你源代码,我就想看看你代码是怎么个执行过程!

之后就跳转到board_init_f函数

/*
    u-boot的基本策略,就是声明一系列的API(如low_level_init、board_init_f、board_init_r等等),
    并在u-boot的核心逻辑中调用它们。
    平台的移植和开发者,所需要做的,就是根据实际情况,实现它们。

    与此同时,为了减少开发的工作量,u-boot为大部分API提供了通用实现
    (一般通过CONFIG配置项或者若定义去控制是否编译)。
    以board_init_f和board_init_r两个板级的初始化接口为例,
    u-boot分别在common/board_f.c和common/board_r.c两个文件中提供了通用实现。
    查看common/Makefile可知:

    obj-$(CONFIG_SYS_GENERIC_BOARD) += board_f.o 
    obj-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o 


    ./include/configs/mx6sabre_common.h 里定义了 CONFIG_SYS_GENERIC_BOARD
*/

 

这句话引自窝窝科技:uboot章节:http://www.wowotech.net/sort/u-boot

 

/*
    别的不管,这里是一个初始化函数的数组,会一一调用他们来初始化开发板。
*/
if (initcall_run_list(init_sequence_f))
        hang();

 

 

这里的函数有没有执行,我都是一个个添加打印进去看他的输出日志有没有那句话来判断的,一个个的加,想想就感觉蛋碎!

( 打开debug输出日志的方法是,在 include/common.h   当中 加入 #define DEBUG )

//#define DEBUG


#ifdef DEBUG
#define _DEBUG  1
#else
#define _DEBUG  0
#endif


#define debug_cond(cond, fmt, args...)                  \
        do {                                            \
                if (cond)                               \
                        printf(pr_fmt(fmt), ##args);    \
        } while (0)

#define debug(fmt, args...)                     \
        debug_cond(_DEBUG, fmt, ##args)

/* 要想打印输出成功,只能定义DEBUG */

 

 

看一下这个数组里的东东:

static init_fnc_t init_sequence_f[] = {
    前略
    ...
    env_init,        /* initialize environment   环境变量初始化开始    env_mmc.c*/

    init_baud_rate,        /* initialze baudrate settings */
    serial_init,        /* serial communications setup */
    console_init_f,        /* stage 1 init of console */

    // 如果你想裁剪uboot的启动时间,这里的函数有一部分是可以去掉的。

    // 初始化DDR
    dram_init,        /* configure available RAM banks */

    // 为代码重定位所做的工作,主要是操作内存的空间

}

 

 

之后跳转到代码重定位:

adr    lr, here
    ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off 新旧地址的偏移长度*/
    add    lr, lr, r0                  /* lr = relocate后,新的here地址 */
    ldr    r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr */
    b    relocate_code  代码重定位的函数所在文件: /* relocate.S (arch\arm\lib)  */ 
here:
/*
 * now relocate vectors
 */

    bl    relocate_vectors

 

 

这里对比说为什么新版的uboot代码的重定位搞的这么复杂,又是代码段、又是rel_dyn数据段的,为什么不像以前一样直接打包成一个文件,全部从flash拷贝的内存里去。

看了一篇文章里说,是为了把uboot定位到内存比较高的地址,因为将来内核是加载到内存低地址的。

二一个是,反正都要重定位,你管我怎么做呢?我Fxck,你厉害

代码重定位具体的实现就不说了,韦东山也讲过,很多其他博客也都有讲解。

 

之后就到了重定位之后的半段:

board_init_r函数,在common\board_r.c,他里面同样有一个初始化函数数组,init_sequence_r

同样,我不能确定这里的宏,哪个定义了与否,便不能确定这个数组里的函数被初始化调用了与否。

所以只能是一个个函数加上打印语句。这样也能根据函数执行的情况,知道当下的这个宏有没有被定义。

#ifdef CONFIG_GENERIC_MMC
    initr_mmc,       //mmc preinit?
#endif


//undef CONFIG_HAS_DATAFLASH



    initr_env,  /*环境变量重定位,初始化结束,第一次mmc_init*/



#ifdef CONFIG_BOARD_LATE_INIT
    board_late_init,  //mmc_init 1次
    //board_late_mmc_env_init => setenv_ulong => setenv => _do_env_set
    //board_late_mmc_env_init => run_command[mmc dev N] => do_mmc_dev(cmd_mmc.c)
    //=> init_mmc_device => mmc_init
#endif



    run_main_loop,   // 最终大BOSS!!!
};

 

到这里,板子的MMC也初始化成功了,最后执行到run_main_loop不再返回。

 

posted @ 2017-10-26 19:18  为民除害  阅读(1319)  评论(0)    收藏  举报