u-boot 中board.c的分析

来源:互联网 发布:无需网络的手机游戏大全 编辑:程序博客网 时间:2024/05/22 05:02

U-Boot源代码阅读笔记(三)—— 对board.c的分析
以arm为例,文件位于lib_arm/board.c,主要分析start_armboot等相关函数

 

global data数据结构定义,位于文件 include/asm-arm/global_data.h
#ifndef    __ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
/*
 * The following data structure is placed in some memory wich is
 * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
 * some locked parts of the data cache) to allow for a minimum set of
 * global variables during system initialization (until we have set
 * up the memory controller so that we can use RAM).
 *
 * Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t)
 * CFG_GBL_DATA_SIZE在config文件中定义,start.S中会根据这个值分配栈空间给global_data,参见对start.S的分析stack_setup部分
 */

typedef    struct    global_data {
    bd_t        *bd;    /* board info, 参见 include/asm-arm/u-boot.h */
    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? */
    unsigned long    fb_base;    /* base address of frame buffer */
#ifdef CONFIG_VFD
    unsigned char    vfd_type;    /* display type */
#endif
    unsigned long    cpu_clk;    /* CPU clock in Hz!        */
    unsigned long    bus_clk;
    unsigned long    ram_size;    /* RAM size */
    unsigned long    reset_status;    /* reset status register at boot */
    void        **jt;        /* jump table */
} gd_t;

/*
 * Global Data Flags
 */
#define    GD_FLG_RELOC    0x00001        /* Code was relocated to RAM        */
#define    GD_FLG_DEVINIT    0x00002        /* Devices have been initialized    */
#define    GD_FLG_SILENT    0x00004        /* Silent mode                */

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")    /* 定义gd为gd_t类型指针,存储在寄存器r8中 */
/* register:表示变量对于执行速度非常重要,因此应该放在机器的寄存器中(寄存器独立于内存,通常在处理器芯片上) */
/* volatile:用于指定变量的值可以由外部过程异步修改,例如中断例程 */

#endif /* __ASM_GBL_DATA_H */

 

 

board info数据结构定义,位于文件 include/asm-arm/u-boot.h
#ifndef _U_BOOT_H_
#define _U_BOOT_H_    1

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;    /* environment struct */
    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];    /* 每个DRAM bank的起始地址和大小,CONFIG_NR_DRAM_BANKS 定义DRAM的bank数 */
} bd_t;

#define bi_env_data bi_env->data
#define bi_env_crc  bi_env->crc

#endif    /* _U_BOOT_H_ */


init sequence
/*
 * All attempts to come up with a "common" initialization sequence
 * that works for all boards and architectures failed: some of the
 * requirements are just _too_ different. To get rid of the resulting
 * mess of board dependent #ifdef'ed code we now make the whole
 * initialization sequence configurable to the user.
 *
 * The requirements for any new initalization function is simple: it
 * receives a pointer to the "global data" structure as it's only
 * argument, and returns an integer return code, where 0 means
 * "continue" and != 0 means "fatal error, hang the system".
 */
typedef int (init_fnc_t) (void);

init_fnc_t *init_sequence[] = {
    cpu_init,        /* basic cpu dependent setup */
    init_baudrate,        /* initialze baudrate settings */
    serial_init,        /* serial communications setup */
    board_init,        /* basic board dependent setup */
    interrupt_init,        /* set up exceptions */
    env_init,        /* initialize environment */
    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) || defined (CONFIG_CMC_PU2)
    checkboard,
#endif
    NULL,
};

 

start_armboot
void start_armboot (void)
{
    DECLARE_GLOBAL_DATA_PTR;    /* 声明全局数据指针 */

    ulong size;
    init_fnc_t **init_fnc_ptr;    /* init sequence */
    char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
    unsigned long addr;
#endif

    /* Pointer is writable since we allocated a register for it */ —— gd为gd_t类型指针,存储在寄存器r8中
    gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));    /* global data地址,栈空间分配参见start.S stack_setup部分 */
    /* compiler optimization barrier needed for GCC >= 3.4 */
    __asm__ __volatile__("": : :"memory");
    /* 内联汇编语句__asm__("":::"memory")向GCC声明,在此内联汇编语句出现的位置内存内容可能改变了,
    所以GCC在编译的时候,会将此因素考虑进去,而不会对代码进行优化及重新排序等操作,这样GCC会老老实实的生成汇编代码 */

    memset ((void*)gd, 0, sizeof (gd_t));
    gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));    /* board info 地址*/
    memset (gd->bd, 0, sizeof (bd_t));

    monitor_flash_len = _bss_start - _armboot_start;    /* .text段和.data段的总长 */

    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {    /* 按照initialization sequence进行初始化 */
        if ((*init_fnc_ptr)() != 0) {

/* where 0 means "continue" and != 0 means "fatal error, hang the system". */
            hang ();
        }
    }

    puts("Init flash.../n");
    /* configure available FLASH banks */
    size = flash_init ();    /* init nor flash */
    display_flash_config (size);

#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, defined in start.S */
    addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);    /* round up to nearest full page */
    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);

#if (CONFIG_COMMANDS & CFG_CMD_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");

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

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        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;
        }
    }

    devices_init ();    /* get the devices list going. */

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

    jumptable_init ();    /* init jump table */

    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);    /* load address */
    }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
    if ((s = getenv ("bootfile")) != NULL) {
        copy_filename (BootFile, s, sizeof (BootFile));    /* net boot file */
    }
#endif    /* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
    board_late_init ();    /* init your board */
#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 */
}

文章出处:http://www.diybl.com/course/3_program/shell/shelljs/2008729/134250_2.html
文章出处:http://www.diybl.com/course/3_program/shell/shelljs/2008729/134250.html