U-Boot学习-第二阶段代码分析

来源:互联网 发布:ppt全屏快捷键 mac 编辑:程序博客网 时间:2024/06/04 19:27

U-Boot在完成stage1的工作后会跳转到第一个c语言函数start_armboot()函数中

1 在介绍该函数之前,我们需要看一看几个数据结构,这些是u-boot中几个重要的数据结构:
1)、gd_t该数据结构保存了u-boot 需要的配置信息,注释简单明了
typedef    struct    global_data {
    bd_t        *bd; //与板子相关的结构,见下面
    unsigned long    flags;
    unsigned long    baudrate;
    unsigned long    have_console;    /* serial_init() was called */
    unsigned long    reloc_off;    /* Relocation Offset */
    unsigned long    env_addr;    /* Address  of Environment struct */
    unsigned long    env_valid;    /* Checksum of Environment valid? */
#ifdef CONFIG_VFD  //我们一般没有配置这个,这个是frame buffer的首地址
    unsigned long    fb_base;    /* base address of frame buffer */
#endif
} gd_t;
2)、bd_t 保存与板子相关的配置参数
typedef struct bd_info {
    int            bi_baudrate;    /* serial console baudrate */
    unsigned long    bi_ip_addr;    /* IP Address */
    unsigned char    bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s           *bi_env;
    ulong            bi_arch_number;    /* unique id for this board */
    ulong            bi_boot_params;    /* where this board expects params */
    struct                /* RAM configuration */
    {
    ulong start;
    ulong size;
    }             bi_dram[CONFIG_NR_DRAM_BANKS];//在我的板子上是1个
} bd_t;

3). 初始化函数列表(以数组的形式)

init_fnc_t **init_fnc_ptr;//其中init_fnc_ptr指向一个数组指针:

init_fnc_t *init_sequence[] = {
cpu_init,//初始化IRQ/FIQ模式的栈;

board_init, //这个是对板子的初始化,设置MPLL,改变系统时钟,它是开发板相关的函数,比如2410是在:board/smdk2410/smdk2410.c中实现

interrupt_init,   /* set up exceptions || cpu/arm920t,s3c24x0/interrupts.c */初始化定时器
env_init, /* initialize environment */检查flash上的环境变量是否有效
init_baudrate,   /* initialze baudrate settings */
serial_init,   /* serial communications setup || cpu/arm920t/s3c24x0/serial.c */
//串口初始化后我们就可以打印信息了
console_init_f,   /* stage 1 init of console */
display_banner,   /* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,   /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,   /* display board info */
#endif
dram_init,   /* configure available RAM banks */检测系统内存映射,设置内存的起始地址和大小
display_dram_config,
NULL,
};

4) u-boot的命令格式:

U_BOOT_CMD(name,maxargs,repeatable,command,”usage”,"help")

name:命令的名字,不是一个字符串;

maxargs:最大的参数个数;

repeatable:命令是可重复的;

command:对应的函数指针

内核的复制和启动,可以通过如下命令来完成:bootm从内存、ROM、NOR Flash中启动内核,bootp则通过网络来启动,而nboot从NAND Flash启动内核。他们是先将内核映像从各种媒介中读出,存放在指定的位置;然后设置标记列表以给内核传递参数;最后跳到内核的入口点去执行。

2 U-Boot第二阶段流程图:

3 star_armboot()源码分析:

=============================================================

void start_armboot (void)
{
    init_fnc_t **init_fnc_ptr;//指向初始化函数列表
    char *s;
#ifndef CFG_NO_FLASH
    ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
    unsigned long addr;
#endif

    /* Pointer is writable since we allocated a register for it */
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));//为数据结构分配空间_armboot_start=0x33f880000
    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");

    memset ((void*)gd, 0, sizeof (gd_t));//初始化全局数据区为0;
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));//为bd_t分配空间,并赋值到gd
    memset (gd->bd, 0, sizeof (bd_t));

    monitor_flash_len = _bss_start - _armboot_start; //代码段的大小

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {//依次调用初始化函数
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }

//CFG_NO_FLASH 表示没有flash,如果没定义该常量则表示板子上有flash,此时调用flash_init()对其进行初始化.

#ifndef CFG_NO_FLASH
    /* configure available FLASH banks */
    size = flash_init ();
    display_flash_config (size); //打印flash的信息,仅是其大小;
#endif /* CFG_NO_FLASH */

#ifdef CONFIG_VFD
#    ifndef PAGE_SIZE
#      define PAGE_SIZE 4096
#    endif
    /*
     * reserve memory for VFD display (always full pages)
     */
    /* bss_end is defined in the board-specific linker script */
    addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
    size = vfd_setmem (addr);
    gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD
#    ifndef PAGE_SIZE
#      define PAGE_SIZE 4096
#    endif
    /*
     * reserve memory for LCD display (always full pages)
     */
    /* bss_end is defined in the board-specific linker script */
    addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
    size = lcd_setmem (addr);
    gd->fb_base = addr;
#endif /* CONFIG_LCD */

    /* armboot_start is defined in the board-specific linker script */
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //初始化malloc区域

#if (CONFIG_COMMANDS & CFG_CMD_NAND) //如果定义了命令和NAND命令,初始化nand
    puts ("NAND:  ");
    nand_init();        /* go init the NAND */
#endif

#ifdef CONFIG_HAS_DATAFLASH
    AT91F_DataflashInit();
    dataflash_print_info();
#endif

    /* initialize environment */
    env_relocate (); //对环境变量重新定位

#ifdef CONFIG_VFD
    /* must do this after the framebuffer is allocated */
    drv_vfd_init();
#endif /* CONFIG_VFD */

    /* IP Address */ //初始化网络设备
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //传递IP地址

    /* MAC Address */
    {
        int i;
        ulong reg;
        char *s, *e;
        char tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp)); //从环境变量获取网卡的MAC地址并填充gd结构体变量
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg < 6; ++reg) {
            gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
            if (s)
                s = (*e) ? e + 1 : e;
        }

#ifdef CONFIG_HAS_ETH1
        i = getenv_r ("eth1addr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg < 6; ++reg) {
            gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
            if (s)
                s = (*e) ? e + 1 : e;
        }
#endif
    }

    devices_init ();    /* get the devices list going. */ //对设备初始化,在common/devices.c文件中,会根据配置来完成各个设备的初始化,其中会调用函数drv_system_init(),这个函数对串口设备初始化,然后注册串口设备

#ifdef CONFIG_CMC_PU2
    load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */

    jumptable_init (); //跳转表初始化

    console_init_r ();    /* fully init console as a device */

#if defined(CONFIG_MISC_INIT_R) //没有定义
    /* miscellaneous platform dependent initialisations */
    misc_init_r ();
#endif

    /* enable exceptions */
    enable_interrupts (); //使能中断

    /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
    cs8900_get_enetaddr (gd->bd->bi_enetaddr); //获取网卡的MAC地址
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)//没有定义
    if (getenv ("ethaddr")) {
        smc_set_mac_addr(gd->bd->bi_enetaddr);
    }
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

    /* Initialize from environment */
    if ((s = getenv ("loadaddr")) != NULL) {
        load_addr = simple_strtoul (s, NULL, 16);
    }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
    if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));
    }
#endif    /* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
    board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
    puts ("Net:   ");
#endif
    eth_initialize(gd->bd);
#endif
    /* main_loop() can return to retry autoboot, if so just run it again. */ //进入主循环
    for (;;) {
        main_loop ();
    }

    /* NOTREACHED - no way out of command loop except booting */
}

main_loop函数在common/main.c中定义

4 U-Boot内存使用情况:

参考文献:

1 http://6xudonghai.blog.163.com/blog/static/33640629200911364735696/

2 http://hi.baidu.com/yeanleo/blog/item/88d9ed5871e8cf222934f0a6.html

3 http://blog.chinaunix.net/u3/114171/showart_2426405.html

4 http://www.cnblogs.com/heaad/archive/2010/07/17/1779829.html

原创粉丝点击