原创 uboot源码分析3-board.c

2013-9-6 22:21 1819 23 23 分类: MCU/ 嵌入式 文集: uboot

/*省去了一些没注释的部分 只贴上一些注释的主要的部分  有问题还望指正*/

typedef int (init_fnc_t) (void);
//typedif 起到一个替换的作用,
//init_fnc_t *init_sequence[] = {,}这句话解析开来就是
//int (*init_sequence[]={})(void);
//定义了一个指向函数的指针数组,并且每个函数的返回值为int
//在下面的函数中 会依次调用这个数组里面的函数。关于这几个函数的分析见下篇博客。
int print_cpuinfo (void); /* test-only */


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 */
#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,
};

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)  //vfd也是一种显示器 和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 在start.s里面有定义,里面放的是start,这样gd就指向了gd——t的首地址
    //gd_t结构体在include/asm-arm/global_data.h 定义,里面有个类型为bd_t的结构体*bd;
    //gd也是在include/asm-arm/global_data.h这个文件中定义,如下
    //#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
    //这句意思是 定义gd,并在寄存器r8中保存gd。
    //先把计算后的值强制变换成gd_t类型的指针,然后再赋给gd
    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");
    //百度一下这句话就能搜到,意思就是让目前cache里面的数据无效,因为你还不知道里面是什么数据。

    memset ((void*)gd, 0, sizeof (gd_t));//这个函数有三个变量:a,b,c
    // 从a地址开始把b写入,一共写c个字节,这里就是清零
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    //bd类型为bd_t,这个结构体里面放了一些板子的信息,如波特率,IP地址等等。和上面类似,bd->bd就指向了bd_t这个结构体的首地址
    memset (gd->bd, 0, sizeof (bd_t));   //清零

    monitor_flash_len = _bss_start - _armboot_start;//根据韦东山书p260的图可知这就是代码段的长度。

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
        //挨个执行init_sequence指向的函数,里面的每个函数返回值都是0,hang是一个死循环,如过哪个返回不是0,说明出错。
    }
#ifndef CFG_NO_FLASH   //这里的flash是指norflash  nand指nandflash。
    /* configure available FLASH banks */
    size = flash_init ();  //初始化norflash 并返回大小
    display_flash_config (size); //输出norflash的信息。
#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);
    //addr指向lcd memory的起始地址,这个地址是4K,也就是页对齐。
    size = lcd_setmem (addr);
    gd->fb_base = addr;//fb-base是显示器帧地址首地址
#endif /* CONFIG_LCD */

    /* armboot_start is defined in the board-specific linker script */
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);//分配堆空间,并清零

#if (CONFIG_COMMANDS & CFG_CMD_NAND)//如果支持nandflash 初始化nand
    puts ("NAND:  ");
    nand_init();        /* go init the NAND */
#endif

#ifdef CONFIG_HAS_DATAFLASH //应该用不到
    AT91F_DataflashInit();
    dataflash_print_info();
#endif

    /* initialize environment */
    env_relocate ();//重定向环境变量 为了加快访问速度,将环境变量从flash拷贝到sdram中去。

#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");//读取环境变量给bd结构体。
//getenv_IPaddr 就是在getenv的基础上多了一个数据格式转换
    /* MAC Address 读mac地址给bd结构体 */
    {
        int i;
        ulong reg;
        char *s, *e;
        char tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));//getenv_r 返回i=64 tmp为mac地址
        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;
        }
//如果使用第二块网卡 获取第二块网卡地址并给bd结构体
#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 ();    /* 对IIC 键盘 声卡等一些设备初始化 */

#ifdef CONFIG_CMC_PU2             //应该不用
    load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */

    jumptable_init ();

/*

上面是初始化跳转表,所谓跳转表,就是给gd结构体的jt赋值,以后调用jt【】就是调用这些函数。下面只是截取 了一部分,这个函数在commen/export.c

gd->jt[XF_get_version] = (void *) get_version;
    gd->jt[XF_malloc] = (void *) malloc;
    gd->jt[XF_free] = (void *) free;
    gd->jt[XF_getenv] = (void *) getenv;
    gd->jt[XF_setenv] = (void *) setenv;
    gd->jt[XF_get_timer] = (void *) get_timer;
    gd->jt[XF_simple_strtoul] = (void *) simple_strtoul;

*/

    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);//网卡 目前还没仔细看
#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);//如果环境变量里面有loadaddr 则使用它
    }
#if (CONFIG_COMMANDS & CFG_CMD_NET) //如果支持网络
    if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));//把文件名字给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 ();//在commen目录下main.c文件
    }

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

void hang (void)
{
    puts ("### ERROR ### Please RESET the board ###\n");
    for (;;);
}

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
23
关闭 站长推荐上一条 /2 下一条