程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Mini2440之uboot移植之源码分析board_init_r(四)

board_init_r和board_init_f差不多,都是执行一个循环。这里是循环执行init_sequence_r[]里的函数指针。

一、board_init_r(common/board_r.c)

void board_init_r(gd_t *new_gd, ulong dest_addr)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    int i;
#endif

#ifdef CONFIG_AVR32
    mmu_init_r(dest_addr);
#endif

#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
    gd = new_gd;
#endif

#ifdef CONFIG_NEEDS_MANUAL_RELOC
    for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
        init_sequence_r[i] += gd->reloc_off;
#endif

    if (initcall_run_list(init_sequence_r))
        hang();

    /* NOTREACHED - run_main_loop() does not return */
    hang();
}

在上一篇博客中我们已经介绍了该函数调用表时会传入两个参数:

  • new_gd:为u-boot重定位后的新地址的gd结构;
  • dest_addr:u-boot重定位后的地址;

然后循环遍历init_sequence_r中的每一个函数,并执行。

二、init_sequence_r

/*
 * Over time we hope to remove these functions with code fragments and
 * stub funtcions, and instead call the relevant function directly.
 *
 * We also hope to remove most of the driver-related init and do it if/when
 * the driver is later used.
 *
 * TODO: perhaps reset the watchdog in the initcall function after each call?
 */
init_fnc_t init_sequence_r[] = {
    initr_trace,
    initr_reloc,
    /* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
    initr_caches,
    /* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
     *     A temporary mapping of IFC high region is since removed,
     *     so environmental variables in NOR flash is not availble
     *     until board_init() is called below to remap IFC to high
     *     region.
     */
#endif
    initr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
    initr_unlock_ram_in_cache,
#endif
    initr_barrier,
    initr_malloc,
    initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
    initr_noncached,
#endif
    bootstage_relocate,
#ifdef CONFIG_DM
    initr_dm,
#endif
    initr_bootstage,
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
    board_init,    /* Setup chipselects */
#endif
    /*
     * TODO: printing of the clock inforamtion of the board is now
     * implemented as part of bdinfo command. Currently only support for
     * davinci SOC's is added. Remove this check once all the board
     * implement this.
     */
#ifdef CONFIG_CLOCKS
    set_cpu_clk_info, /* Setup clock information */
#endif
#ifdef CONFIG_EFI_LOADER
    efi_memory_init,
#endif
    stdio_init_tables,
    initr_serial,
    initr_announce,
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    initr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
    initr_trap,
#endif
#ifdef CONFIG_ADDR_MAP
    initr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)
    board_early_init_r,
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_LOGBUFFER
    initr_logbuffer,
#endif
#ifdef CONFIG_POST
    initr_post_backlog,
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_SYS_DELAYED_ICACHE
    initr_icache_enable,
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
    /*
     * Do early PCI configuration _before_ the flash gets initialised,
     * because PCU ressources are crucial for flash access on some boards.
     */
    initr_pci,
#endif
#ifdef CONFIG_WINBOND_83C553
    initr_w83c553f,
#endif
#ifdef CONFIG_ARCH_EARLY_INIT_R
    arch_early_init_r,
#endif
    power_init_board,
#ifndef CONFIG_SYS_NO_FLASH
    initr_flash,
#endif
    INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86) || \
    defined(CONFIG_SPARC)
    /* initialize higher level parts of CPU like time base and timers */
    cpu_init_r,
#endif
#ifdef CONFIG_PPC
    initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
    initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
    initr_onenand,
#endif
#ifdef CONFIG_GENERIC_MMC
    initr_mmc,
#endif
#ifdef CONFIG_HAS_DATAFLASH
    initr_dataflash,
#endif
    initr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LEN
    initr_malloc_bootparams,
#endif
    INIT_FUNC_WATCHDOG_RESET
    initr_secondary_cpu,
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
    mac_read_from_eeprom,
#endif
    INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
    /*
     * Do pci configuration
     */
    initr_pci,
#endif
    stdio_add_devices,
    initr_jumptable,
#ifdef CONFIG_API
    initr_api,
#endif
    console_init_r,        /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
    show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
    arch_misc_init,        /* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_R
    misc_init_r,        /* miscellaneous platform-dependent init */
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
    initr_kgdb,
#endif
    interrupt_init,
#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)
    initr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || defined(CONFIG_M68K)
    timer_init,        /* initialize timer */
#endif
#if defined(CONFIG_STATUS_LED)
    initr_status_led,
#endif
    /* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NET
    initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
    board_late_init,
#endif
#if defined(CONFIG_CMD_AMBAPP)
    ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
    initr_ambapp_print,
#endif
#endif
#ifdef CONFIG_CMD_SCSI
    INIT_FUNC_WATCHDOG_RESET
    initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
    INIT_FUNC_WATCHDOG_RESET
    initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
    initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET
    INIT_FUNC_WATCHDOG_RESET
    initr_net,
#endif
#ifdef CONFIG_POST
    initr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
    initr_pcmcia,
#endif
#if defined(CONFIG_CMD_IDE)
    initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INIT
    INIT_FUNC_WATCHDOG_RESET
    /*
     * Some parts can be only initialized if all others (like
     * Interrupts) are up and running (i.e. the PC-style ISA
     * keyboard).
     */
    last_stage_init,
#endif
#ifdef CONFIG_CMD_BEDBUG
    INIT_FUNC_WATCHDOG_RESET
    initr_bedbug,
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
    initr_mem,
#endif
#ifdef CONFIG_PS2KBD
    initr_kbd,
#endif
#if defined(CONFIG_SPARC)
    prom_init,
#endif
    run_main_loop,
};

通过反汇编代码我们可以确定实际定义了哪些函数:

0007220c <init_sequence_r>:
   7220c:    0000eab0     .word    0x0000eab0     initr_trace
   72210:    0000eab8     .word    0x0000eab8     initr_reloc
   72214:    0000ec88     .word    0x0000ec88     initr_caches
   72218:    0000ead0     .word    0x0000ead0     initr_reloc_global_data
   7221c:    0000eaf8     .word    0x0000eaf8     initr_barrier
   72220:    0000ec6c     .word    0x0000ec6c     initr_malloc
   72224:    0000eb00     .word    0x0000eb00     initr_console_record
   72228:    0000ea8c     .word    0x0000ea8c     bootstage_relocate
   7222c:    0000ec58     .word    0x0000ec58     initr_bootstage
   72230:    0000111c     .word    0x0000111c     board_init
   72234:    000163c8     .word    0x000163c8     stdio_init_tables
   72238:    0000ec48     .word    0x0000ec48     initr_serial
   7223c:    0000eb10     .word    0x0000eb10     initr_announce
   72240:    0000eb08     .word    0x0000eb08     power_init_board
   72244:    0000ebcc     .word    0x0000ebcc     initr_flash
   72248:    0000ebb0     .word    0x0000ebb0     initr_nand
   7224c:    0000eb80     .word    0x0000eb80     initr_env
   72250:    0000eaa0     .word    0x0000eaa0     initr_secondary_cpu
   72254:    00016488     .word    0x00016488     stdio_add_devices
   72258:    0000eb70     .word    0x0000eb70     initr_jumptable
   7225c:    000146e0     .word    0x000146e0     console_init_r
   72260:    00000ae0     .word    0x00000ae0     interrupt_init
   72264:    0000eb60     .word    0x0000eb60     initr_enable_interrupts
   72268:    0000eb40     .word    0x0000eb40     initr_ethaddr
   7226c:    0000eb24     .word    0x0000eb24     initr_net
   72270:    0000eb18     .word    0x0000eb18     run_main_loop

三、各个函数指针

3.1 initr_trace(common/board_r.c)

static int initr_trace(void)
{
#ifdef CONFIG_TRACE
    trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE);
#endif

    return 0;
}

3.2 initr_reloc(common/board_r.c)

static int initr_reloc(void)
{
    /* tell others: relocation done */
    gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;

    return 0;
}

常量GD_FLG_RELOC 和GD_FLG_FULL_MALLOC_INIT定义如下:

/*
 * Global Data Flags - the top 16 bits are reserved for arch-specific 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 GD_FLG_POSTFAIL        0x00008    /* Critical POST test failed       */
#define GD_FLG_POSTSTOP        0x00010    /* POST seqeunce aborted       */
#define GD_FLG_LOGINIT        0x00020    /* Log Buffer has been initialized */
#define GD_FLG_DISABLE_CONSOLE    0x00040    /* Disable console (in & out)       */
#define GD_FLG_ENV_READY    0x00080    /* Env. imported into hash table   */
#define GD_FLG_SERIAL_READY    0x00100    /* Pre-reloc serial console ready  */
#define GD_FLG_FULL_MALLOC_INIT    0x00200    /* Full malloc() is ready       */
#define GD_FLG_SPL_INIT        0x00400    /* spl_init() has been called       */
#define GD_FLG_SKIP_RELOC    0x00800    /* Don't relocate */
#define GD_FLG_RECORD        0x01000    /* Record console */

设置gd->flags标志位第1位、第10位为1。

3.3 initr_caches(common/board_r.c)

static int initr_caches(void)
{
    /* Enable caches */
    enable_caches();
    return 0;
}

enable_caches()使能缓存,定义在arch/arm/lib/cache.c:

/*
 * Default implementation of enable_caches()
 * Real implementation should be in platform code
 */
__weak void enable_caches(void)
{
    puts("WARNING: Caches not enabled\n");
}

3.4 initr_reloc_global_data(common/board_r.c)

static int initr_reloc_global_data(void)
{
#ifdef __ARM__
    monitor_flash_len = _end - __image_copy_start;
#elif defined(CONFIG_NDS32)
    monitor_flash_len = (ulong)&_end - (ulong)&_start;
#elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2)
    monitor_flash_len = (ulong)&__init_end - gd->relocaddr;
#endif
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
    /*
     * The gd->cpu pointer is set to an address in flash before relocation.
     * We need to update it to point to the same CPU entry in RAM.
     * TODO: why not just add gd->reloc_ofs?
     */
    gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;

    /*
     * If we didn't know the cpu mask & # cores, we can save them of
     * now rather than 'computing' them constantly
     */
    fixup_cpu();
#endif
#ifdef CONFIG_SYS_EXTRA_ENV_RELOC
    /*
     * Some systems need to relocate the env_addr pointer early because the
     * location it points to will get invalidated before env_relocate is
     * called.  One example is on systems that might use a L2 or L3 cache
     * in SRAM mode and initialize that cache from SRAM mode back to being
     * a cache in cpu_init_r.
     */
    gd->env_addr += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;
#endif
#ifdef CONFIG_OF_EMBED
    /*
    * The fdt_blob needs to be moved to new relocation address
    * incase of FDT blob is embedded with in image
    */
    gd->fdt_blob += gd->reloc_off;
#endif
#ifdef CONFIG_EFI_LOADER
    efi_runtime_relocate(gd->relocaddr, NULL);
#endif

    return 0;
}

全局变量monitor_flash_len定义:

ulong monitor_flash_len;

其中_end和rel_dyn_end 值是一样的。

3.5 initr_barrier(common/board_r.c)

static int initr_barrier(void)
{
#ifdef CONFIG_PPC
    /* TODO: Can we not use dmb() macros for this? */
    asm("sync ; isync");
#endif
    return 0;
}

3.6 initr_malloc(common/board_r.c)

static int initr_malloc(void)
{
    ulong malloc_start;

#ifdef CONFIG_SYS_MALLOC_F_LEN
    debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
          gd->malloc_ptr / 1024);
#endif
    /* The malloc area is immediately below the monitor copy in DRAM */
    malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
    mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
            TOTAL_MALLOC_LEN);
    return 0;
}

从board_init_f画出的内存图可知,u-boot重定位地址的下面就是预留的堆区。

设置malloc的起始地址,malloc_start设置为u-boot重定位后的地址-TOTAL_MALLOC_LEN,TOTAL_MALLOC_LEN之前有介绍4MB。

然后填充了三个全局变量并将堆区全部清零:

void mem_malloc_init(ulong start, ulong size)
{
    mem_malloc_start = start;
    mem_malloc_end = start + size;
    mem_malloc_brk = start;
 
    debug("using memory %#lx-%#lx for malloc()\n", mem_malloc_start,
          mem_malloc_end);
#ifdef CONFIG_SYS_MALLOC_CLEAR_ON_INIT  /* 定义这个宏则堆区初始化为0,否则不初始化 */
    memset((void *)mem_malloc_start, 0x0, size);
#endif
    malloc_bin_reloc();
}

 

3.7 initr_console_record(common/board_r.c)

static int initr_console_record(void)
{
#if defined(CONFIG_CONSOLE_RECORD)
    return console_record_init();
#else
    return 0;
#endif
}

3.8 bootstage_relocate(common/bootstage.c)

int bootstage_relocate(void)
{
    int i;

    /*
     * Duplicate all strings.  They may point to an old location in the
     * program .text section that can eventually get trashed.
     */
    for (i = 0; i < BOOTSTAGE_ID_COUNT; i++)
        if (record[i].name)
            record[i].name = strdup(record[i].name);

    return 0;
}

3.9 initr_bootstage(common/board_r.c)

static int initr_bootstage(void)
{
    /* We cannot do this before initr_dm() */
    bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

    return 0;
}

标记BOOTSTAGE_ID_START_UBOOT_R阶段信息。

3.10 board_init(board/samsung/smdk2410/smdk2410.c)

int board_init(void)
{
    /* arch number of SMDK2410-Board */
    gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

    /* adress of boot parameters */
    gd->bd->bi_boot_params = 0x30000100;

    icache_enable();
    dcache_enable();

    return 0;
}

gd->bd->bi_arch_number修改成SMDK2410的机器码,启动linux需要的,但实际测试,这个就算不设置也能够启动,但我们还是将其添加上(可在arch/arm/include/asm/mach-types.h中找到。

#define MACH_TYPE_SMDK2410             193

然后设置gd->bd->bi_boot_params,从0x30000100地址开始存放启动参数,内核启动时会从这里取出参数。

3.11 stdio_init_tables(common/sdtio.c)

int stdio_init_tables(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
    /* already relocated for current ARM implementation */
    ulong relocation_offset = gd->reloc_off;
    int i;

    /* relocate device name pointers */
    for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
        stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
                        relocation_offset);
    }
#endif /* CONFIG_NEEDS_MANUAL_RELOC */

    /* Initialize the list */
    INIT_LIST_HEAD(&(devs.list));

    return 0;
}

初始化了一个双向循环链表:

static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

3.12 initr_serial(common/board_r.c)注册串口驱动

static int initr_serial(void)
{
    serial_initialize();
    return 0;
}

serial_initialize定义在drivers/serial/serial.c文件:

/**
 * serial_initialize() - Register all compiled-in serial port drivers
 *
 * This function registers all serial port drivers that are compiled
 * into the U-Boot binary with the serial core, thus making them
 * available to U-Boot to use. Lastly, this function assigns a default
 * serial port to the serial core. That serial port is then used as a
 * default output.
 */
void serial_initialize(void)
{
    amirix_serial_initialize();
    arc_serial_initialize();
    arm_dcc_initialize();
    asc_serial_initialize();
    atmel_serial_initialize();
    au1x00_serial_initialize();
    bfin_jtag_initialize();
    bfin_serial_initialize();
    bmw_serial_initialize();
    clps7111_serial_initialize();
    cogent_serial_initialize();
    cpci750_serial_initialize();
    evb64260_serial_initialize();
    imx_serial_initialize();
    iop480_serial_initialize();
    jz_serial_initialize();
    leon2_serial_initialize();
    leon3_serial_initialize();
    lh7a40x_serial_initialize();
    lpc32xx_serial_initialize();
    marvell_serial_initialize();
    max3100_serial_initialize();
    mcf_serial_initialize();
    ml2_serial_initialize();
    mpc512x_serial_initialize();
    mpc5xx_serial_initialize();
    mpc8260_scc_serial_initialize();
    mpc8260_smc_serial_initialize();
    mpc85xx_serial_initialize();
    mpc8xx_serial_initialize();
    mxc_serial_initialize();
    mxs_auart_initialize();
    ns16550_serial_initialize();
    oc_serial_initialize();
    p3mx_serial_initialize();
    pl01x_serial_initialize();
    pxa_serial_initialize();
    s3c24xx_serial_initialize();
    s5p_serial_initialize();
    sa1100_serial_initialize();
    sandbox_serial_initialize();
    sconsole_serial_initialize();
    sh_serial_initialize();
    stm32_serial_initialize();
    uartlite_serial_initialize();
    zynq_serial_initialize();

    serial_assign(default_serial_console()->name);
}

串口设备注册:

void s3c24xx_serial_initialize(void)
{
    serial_register(&s3c24xx_serial0_device);
    serial_register(&s3c24xx_serial1_device);
    serial_register(&s3c24xx_serial2_device);
}
/**
 * serial_register() - Register serial driver with serial driver core
 * @dev:    Pointer to the serial driver structure
 *
 * This function registers the serial driver supplied via @dev with
 * serial driver core, thus making U-Boot aware of it and making it
 * available for U-Boot to use. On platforms that still require manual
 * relocation of constant variables, relocation of the supplied structure
 * is performed.
 */
void serial_register(struct serial_device *dev)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    if (dev->start)
        dev->start += gd->reloc_off;
    if (dev->stop)
        dev->stop += gd->reloc_off;
    if (dev->setbrg)
        dev->setbrg += gd->reloc_off;
    if (dev->getc)
        dev->getc += gd->reloc_off;
    if (dev->tstc)
        dev->tstc += gd->reloc_off;
    if (dev->putc)
        dev->putc += gd->reloc_off;
    if (dev->puts)
        dev->puts += gd->reloc_off;
#endif

    dev->next = serial_devices;
    serial_devices = dev;
}
static struct serial_device *serial_devices;
struct serial_device {
    /* enough bytes to match alignment of following func pointer */
    char    name[16];

    int    (*start)(void);
    int    (*stop)(void);
    void    (*setbrg)(void);
    int    (*getc)(void);
    int    (*tstc)(void);
    void    (*putc)(const char c);
    void    (*puts)(const char *s);
#if CONFIG_POST & CONFIG_SYS_POST_UART
    void    (*loop)(int);
#endif
    struct serial_device    *next;
};

这段代码执行完之后串口设备指针serial_devices指向如下图,可以看出这个一个单向链表结构:

3.13 initr_announce(common/board_r.c)

static int initr_announce(void)
{
    debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr);
    return 0;
}

3.14 power_init_board(common/board_r.c)

__weak int power_init_board(void)
{
    return 0;
}

3.15 initr_flash(common/board_r.c)初始化NOR FLASH

static int initr_flash(void)
{
    ulong flash_size = 0;
    bd_t *bd = gd->bd;

    puts("Flash: ");

    if (board_flash_wp_on())
        printf("Uninitialized - Write Protect On\n");
    else
        flash_size = flash_init();

    print_size(flash_size, "");
#ifdef CONFIG_SYS_FLASH_CHECKSUM
    /*
    * Compute and print flash CRC if flashchecksum is set to 'y'
    *
    * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
    */
    if (getenv_yesno("flashchecksum") == 1) {
        printf("  CRC: %08X", crc32(0,
            (const unsigned char *) CONFIG_SYS_FLASH_BASE,
            flash_size));
    }
#endif /* CONFIG_SYS_FLASH_CHECKSUM */
    putc('\n');

    /* update start of FLASH memory    */
#ifdef CONFIG_SYS_FLASH_BASE
    bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
#endif
    /* size of FLASH memory (final value) */
    bd->bi_flashsize = flash_size;

#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
    /* Make a update of the Memctrl. */
    update_flash_size(flash_size);
#endif


#if defined(CONFIG_OXC) || defined(CONFIG_RMU)
    /* flash mapped at end of memory map */
    bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
    bd->bi_flashoffset = monitor_flash_len;    /* reserved area for monitor */
#endif
    return 0;
}

flash_init用于初始化NOR FLASH。该函数在drivers\mtd\cfi_flash.c中定义:

unsigned long flash_init (void)
{
    unsigned long size = 0;
    int i;

#ifdef CONFIG_SYS_FLASH_PROTECTION
    /* read environment from EEPROM */
    char s[64];
    getenv_f("unlock", s, sizeof(s));
#endif

#ifdef CONFIG_CFI_FLASH /* for driver model */
    cfi_flash_init_dm();
#endif

    /* Init: no FLASHes known */
    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
        flash_info[i].flash_id = FLASH_UNKNOWN;

        /* Optionally write flash configuration register */
        cfi_flash_set_config_reg(cfi_flash_bank_addr(i),
                     cfi_flash_config_reg(i));

        if (!flash_detect_legacy(cfi_flash_bank_addr(i), i))
            flash_get_size(cfi_flash_bank_addr(i), i);
        size += flash_info[i].size;
        if (flash_info[i].flash_id == FLASH_UNKNOWN) {
#ifndef CONFIG_SYS_FLASH_QUIET_TEST
            printf ("## Unknown flash on Bank %d "
                "- Size = 0x%08lx = %ld MB\n",
                i+1, flash_info[i].size,
                flash_info[i].size >> 20);
#endif /* CONFIG_SYS_FLASH_QUIET_TEST */
        }
#ifdef CONFIG_SYS_FLASH_PROTECTION
        else if (strcmp(s, "yes") == 0) {
            /*
             * Only the U-Boot image and it's environment
             * is protected, all other sectors are
             * unprotected (unlocked) if flash hardware
             * protection is used (CONFIG_SYS_FLASH_PROTECTION)
             * and the environment variable "unlock" is
             * set to "yes".
             */
            if (flash_info[i].legacy_unlock) {
                int k;

                /*
                 * Disable legacy_unlock temporarily,
                 * since flash_real_protect would
                 * relock all other sectors again
                 * otherwise.
                 */
                flash_info[i].legacy_unlock = 0;

                /*
                 * Legacy unlocking (e.g. Intel J3) ->
                 * unlock only one sector. This will
                 * unlock all sectors.
                 */
                flash_real_protect (&flash_info[i], 0, 0);

                flash_info[i].legacy_unlock = 1;

                /*
                 * Manually mark other sectors as
                 * unlocked (unprotected)
                 */
                for (k = 1; k < flash_info[i].sector_count; k++)
                    flash_info[i].protect[k] = 0;
            } else {
                /*
                 * No legancy unlocking -> unlock all sectors
                 */
                flash_protect (FLAG_PROTECT_CLEAR,
                           flash_info[i].start[0],
                           flash_info[i].start[0]
                           + flash_info[i].size - 1,
                           &flash_info[i]);
            }
        }
#endif /* CONFIG_SYS_FLASH_PROTECTION */
    }

    flash_protect_default();
#ifdef CONFIG_FLASH_CFI_MTD
    cfi_mtd_init();
#endif

    return (size);
}

3.16 initr_nand(common/board_r.c)初始化NAND FLASH

static int initr_nand(void)
{
    puts("NAND:  ");
    nand_init();
    return 0;
}

初始化nand flash,并输出nand falsh信息。其中nand_init()定义在drivers/mtd/nand/nand.c文件中:

void nand_init(void)
{
#ifdef CONFIG_SYS_NAND_SELF_INIT
    board_nand_init();
#else
    int i;

    for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
        nand_init_chip(i);
#endif

    printf("%lu MiB\n", total_nand_size / 1024);

#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
    /*
     * Select the chip in the board/cpu specific driver
     */
    board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}

nand_init_chip定义:

#ifndef CONFIG_SYS_NAND_SELF_INIT
static void nand_init_chip(int i)
{
    struct mtd_info *mtd = &nand_info[i];
    struct nand_chip *nand = &nand_chip[i];
    ulong base_addr = base_address[i];
    int maxchips = CONFIG_SYS_NAND_MAX_CHIPS;

    if (maxchips < 1)
        maxchips = 1;

    mtd->priv = nand;
    nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;

    if (board_nand_init(nand))
        return;

    if (nand_scan(mtd, maxchips))
        return;

    nand_register(i);
}
#endif

board_nand_init在drivers/mtd/nand/s3c2410_nand.c文件中定义:

int board_nand_init(struct nand_chip *nand)
{
    u_int32_t cfg;
    u_int8_t tacls, twrph0, twrph1;
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
    struct s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();

    debug("board_nand_init()\n");

    writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);

    /* initialize hardware */
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
    tacls  = CONFIG_S3C24XX_TACLS;
    twrph0 = CONFIG_S3C24XX_TWRPH0;
    twrph1 =  CONFIG_S3C24XX_TWRPH1;
#else
    tacls = 4;
    twrph0 = 8;
    twrph1 = 8;
#endif

    cfg = S3C2410_NFCONF_EN;
    cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
    cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
    cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
    writel(cfg, &nand_reg->nfconf);

    /* initialize nand_chip data structure */
    nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
    nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

    nand->select_chip = NULL;

    /* read_buf and write_buf are default */
    /* read_byte and write_byte are default */
#ifdef CONFIG_NAND_SPL
    nand->read_buf = nand_read_buf;
#endif

    /* hwcontrol always must be implemented */
    nand->cmd_ctrl = s3c24x0_hwcontrol;

    nand->dev_ready = s3c24x0_dev_ready;

#ifdef CONFIG_S3C2410_NAND_HWECC
    nand->ecc.hwctl = s3c24x0_nand_enable_hwecc;
    nand->ecc.calculate = s3c24x0_nand_calculate_ecc;
    nand->ecc.correct = s3c24x0_nand_correct_data;
    nand->ecc.mode = NAND_ECC_HW;
    nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
    nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
    nand->ecc.strength = 1;
#else
    nand->ecc.mode = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_S3C2410_NAND_BBT
    nand->bbt_options |= NAND_BBT_USE_FLASH;
#endif

    debug("end of nand_init\n");

    return 0;
}

3.17 initr_env(common/board_r.c)

static int initr_env(void)
{
    /* initialize environment */
    if (should_load_env())
        env_relocate();
    else
        set_default_env(NULL);
#ifdef CONFIG_OF_CONTROL
    setenv_addr("fdtcontroladdr", gd->fdt_blob);
#endif

    /* Initialize from environment */
    load_addr = getenv_ulong("loadaddr", 16, load_addr);
#if defined(CONFIG_SYS_EXTBDINFO)
#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
#if defined(CONFIG_I2CFAST)
    /*
     * set bi_iic_fast for linux taking environment variable
     * "i2cfast" into account
     */
    {
        char *s = getenv("i2cfast");

        if (s && ((*s == 'y') || (*s == 'Y'))) {
            gd->bd->bi_iic_fast[0] = 1;
            gd->bd->bi_iic_fast[1] = 1;
        }
    }
#endif /* CONFIG_I2CFAST */
#endif /* CONFIG_405GP, CONFIG_405EP */
#endif /* CONFIG_SYS_EXTBDINFO */
    return 0;
}

其中should_load_env定义如下:

static int should_load_env(void)
{
#ifdef CONFIG_OF_CONTROL
    return fdtdec_get_config_int(gd->fdt_blob, "load-environment", 1);
#elif defined CONFIG_DELAY_ENVIRONMENT
    return 0;
#else
    return 1;
#endif
}

然后执行env_relocate:

void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
    env_reloc();
    env_htab.change_ok += gd->reloc_off;
#endif
    if (gd->env_valid == 0) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
        /* Environment not changable */
        set_default_env(NULL);
#else
        bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
        set_default_env("!bad CRC");
#endif
    } else {
        env_relocate_spec();
    }
}

这里介绍一下set_default_env:

void set_default_env(const char *s)
{
    int flags = 0;
    
    /* 我们的环境变量没配置过,正常是不会超出范围 */
    if (sizeof(default_environment) > ENV_SIZE) {
        puts("*** Error - default environment is too large\n\n");
        return;
    }
    /* 上面传进来的是"!bad CRC" */
    if (s) {
        if (*s == '!') {           /* 第一个字符是'!' */
            printf("*** Warning - %s, "
                "using default environment\n\n",
                s + 1);       /* 跳过!,打印我们看到的一样 */
        } else {
            flags = H_INTERACTIVE;
            puts(s);
        }
    } else {
        puts("Using default environment\n\n");
    }
 
    if (himport_r(&env_htab, (char *)default_environment,
            sizeof(default_environment), '\0', flags, 0,
            0, NULL) == 0)
        error("Environment import failed: errno = %d\n", errno);
 
    /* 标记使用默认环境变量和环境变量成功 */
    gd->flags |= GD_FLG_ENV_READY;
}

himport_r函数设置环境变量default_environment到Hash Table表中:

/*
 * Import linearized data into hash table.
 *
 * This is the inverse function to hexport(): it takes a linear list
 * of "name=value" pairs and creates hash table entries from it.
 *
 * Entries without "value", i. e. consisting of only "name" or
 * "name=", will cause this entry to be deleted from the hash table.
 *
 * The "flag" argument can be used to control the behaviour: when the
 * H_NOCLEAR bit is set, then an existing hash table will kept, i. e.
 * new data will be added to an existing hash table; otherwise, old
 * data will be discarded and a new hash table will be created.
 *
 * The separator character for the "name=value" pairs can be selected,
 * so we both support importing from externally stored environment
 * data (separated by NUL characters) and from plain text files
 * (entries separated by newline characters).
 *
 * To allow for nicely formatted text input, leading white space
 * (sequences of SPACE and TAB chars) is ignored, and entries starting
 * (after removal of any leading white space) with a '#' character are
 * considered comments and ignored.
 *
 * [NOTE: this means that a variable name cannot start with a '#'
 * character.]
 *
 * When using a non-NUL separator character, backslash is used as
 * escape character in the value part, allowing for example for
 * multi-line values.
 *
 * In theory, arbitrary separator characters can be used, but only
 * '\0' and '\n' have really been tested.
 */

int himport_r(struct hsearch_data *htab,
        const char *env, size_t size, const char sep, int flag,
        int crlf_is_lf, int nvars, char * const vars[])
{
    char *data, *sp, *dp, *name, *value;
    char *localvars[nvars];
    int i;

    /* Test for correct arguments.  */
    if (htab == NULL) {
        __set_errno(EINVAL);
        return 0;
    }

    /* we allocate new space to make sure we can write to the array */
    if ((data = malloc(size + 1)) == NULL) {
        debug("himport_r: can't malloc %zu bytes\n", size + 1);
        __set_errno(ENOMEM);
        return 0;
    }
    memcpy(data, env, size);
    data[size] = '\0';
    dp = data;

    /* make a local copy of the list of variables */
    if (nvars)
        memcpy(localvars, vars, sizeof(vars[0]) * nvars);

    if ((flag & H_NOCLEAR) == 0) {
        /* Destroy old hash table if one exists */
        debug("Destroy Hash Table: %p table = %p\n", htab,
               htab->table);
        if (htab->table)
            hdestroy_r(htab);
    }

    /*
     * Create new hash table (if needed).  The computation of the hash
     * table size is based on heuristics: in a sample of some 70+
     * existing systems we found an average size of 39+ bytes per entry
     * in the environment (for the whole key=value pair). Assuming a
     * size of 8 per entry (= safety factor of ~5) should provide enough
     * safety margin for any existing environment definitions and still
     * allow for more than enough dynamic additions. Note that the
     * "size" argument is supposed to give the maximum environment size
     * (CONFIG_ENV_SIZE).  This heuristics will result in
     * unreasonably large numbers (and thus memory footprint) for
     * big flash environments (>8,000 entries for 64 KB
     * envrionment size), so we clip it to a reasonable value.
     * On the other hand we need to add some more entries for free
     * space when importing very small buffers. Both boundaries can
     * be overwritten in the board config file if needed.
     */

    if (!htab->table) {
        int nent = CONFIG_ENV_MIN_ENTRIES + size / 8;

        if (nent > CONFIG_ENV_MAX_ENTRIES)
            nent = CONFIG_ENV_MAX_ENTRIES;

        debug("Create Hash Table: N=%d\n", nent);

        if (hcreate_r(nent, htab) == 0) {
            free(data);
            return 0;
        }
    }

    if (!size) {
        free(data);
        return 1;        /* everything OK */
    }
    if(crlf_is_lf) {
        /* Remove Carriage Returns in front of Line Feeds */
        unsigned ignored_crs = 0;
        for(;dp < data + size && *dp; ++dp) {
            if(*dp == '\r' &&
               dp < data + size - 1 && *(dp+1) == '\n')
                ++ignored_crs;
            else
                *(dp-ignored_crs) = *dp;
        }
        size -= ignored_crs;
        dp = data;
    }
    /* Parse environment; allow for '\0' and 'sep' as separators */
    do {
        ENTRY e, *rv;

        /* skip leading white space */
        while (isblank(*dp))
            ++dp;

        /* skip comment lines */
        if (*dp == '#') {
            while (*dp && (*dp != sep))
                ++dp;
            ++dp;
            continue;
        }

        /* parse name */
        for (name = dp; *dp != '=' && *dp && *dp != sep; ++dp)
            ;

        /* deal with "name" and "name=" entries (delete var) */
        if (*dp == '\0' || *(dp + 1) == '\0' ||
            *dp == sep || *(dp + 1) == sep) {
            if (*dp == '=')
                *dp++ = '\0';
            *dp++ = '\0';    /* terminate name */

            debug("DELETE CANDIDATE: \"%s\"\n", name);
            if (!drop_var_from_set(name, nvars, localvars))
                continue;

            if (hdelete_r(name, htab, flag) == 0)
                debug("DELETE ERROR ##############################\n");

            continue;
        }
        *dp++ = '\0';    /* terminate name */

        /* parse value; deal with escapes */
        for (value = sp = dp; *dp && (*dp != sep); ++dp) {
            if ((*dp == '\\') && *(dp + 1))
                ++dp;
            *sp++ = *dp;
        }
        *sp++ = '\0';    /* terminate value */
        ++dp;

        if (*name == 0) {
            debug("INSERT: unable to use an empty key\n");
            __set_errno(EINVAL);
            free(data);
            return 0;
        }

        /* Skip variables which are not supposed to be processed */
        if (!drop_var_from_set(name, nvars, localvars))
            continue;

        /* enter into hash table */
        e.key = name;
        e.data = value;

        hsearch_r(e, ENTER, &rv, htab, flag);
        if (rv == NULL)
            printf("himport_r: can't insert \"%s=%s\" into hash table\n",
                name, value);

        debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
            htab, htab->filled, htab->size,
            rv, name, value);
    } while ((dp < data + size) && *dp);    /* size check needed for text */
                        /* without '\0' termination */
    debug("INSERT: free(data = %p)\n", data);
    free(data);

    /* process variables which were not considered */
    for (i = 0; i < nvars; i++) {
        if (localvars[i] == NULL)
            continue;
        /*
         * All variables which were not deleted from the variable list
         * were not present in the imported env
         * This could mean two things:
         * a) if the variable was present in current env, we delete it
         * b) if the variable was not present in current env, we notify
         *    it might be a typo
         */
        if (hdelete_r(localvars[i], htab, flag) == 0)
            printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
        else
            printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
    }

    debug("INSERT: done\n");
    return 1;        /* everything OK */
}

调试输出信息如下:

Destroy Hash Table: 33f9a890 table = 00000000
Create Hash Table: N=75
INSERT: table 33f9a890, filled 1/79 rv 33b11238 ==> name="bootdelay" value="5"
INSERT: table 33f9a890, filled 2/79 rv 33b110f8 ==> name="baudrate" value="115200"
INSERT: table 33f9a890, filled 3/79 rv 33b110a8 ==> name="ipaddr" value="10.0.0.110"
INSERT: table 33f9a890, filled 4/79 rv 33b11260 ==> name="serverip" value="10.0.0.1"
INSERT: table 33f9a890, filled 5/79 rv 33b114f4 ==> name="netmask" value="255.255.255.0"
INSERT: free(data = 33b11008)
INSERT: done

3.18 initr_secondary_cpu(common/board_r.c)

static int initr_secondary_cpu(void)
{
    /*
     * after non-volatile devices & environment is setup and cpu code have
     * another round to deal with any initialization that might require
     * full access to the environment or loading of some image (firmware)
     * from a non-volatile device
     */
    /* TODO: maybe define this for all archs? */
    cpu_secondary_init_r();

    return 0;
}

3.19 stdio_add_devices(common/sdtio.c)

int stdio_add_devices(void)
{
#ifdef CONFIG_DM_KEYBOARD   // 定义键盘
    struct udevice *dev;
    struct uclass *uc;
    int ret;

    /*
     * For now we probe all the devices here. At some point this should be
     * done only when the devices are required - e.g. we have a list of
     * input devices to start up in the stdin environment variable. That
     * work probably makes more sense when stdio itself is converted to
     * driver model.
     *
     * TODO(sjg@chromium.org): Convert changing uclass_first_device() etc.
     * to return the device even on error. Then we could use that here.
     */
    ret = uclass_get(UCLASS_KEYBOARD, &uc);
    if (ret)
        return ret;

    /* Don't report errors to the caller - assume that they are non-fatal */
    uclass_foreach_dev(dev, uc) {
        ret = device_probe(dev);
        if (ret)
            printf("Failed to probe keyboard '%s'\n", dev->name);
    }
#endif
#ifdef CONFIG_SYS_I2C
    i2c_init_all();
#else
#if defined(CONFIG_HARD_I2C)
    i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#endif
#ifdef CONFIG_DM_VIDEO              // 定义图像
    struct udevice *vdev;
# ifndef CONFIG_DM_KEYBOARD
    int ret;
# endif

    for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
         vdev;
         ret = uclass_next_device(&vdev))
        ;
    if (ret)
        printf("%s: Video device failed (ret=%d)\n", __func__, ret);
#else
# if defined(CONFIG_LCD)
    drv_lcd_init ();
# endif
# if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
    drv_video_init ();
# endif
#endif /* CONFIG_DM_VIDEO */
#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
    drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
    drv_logbuff_init ();
#endif
    drv_system_init ();
    serial_stdio_init ();
#ifdef CONFIG_USB_TTY
    drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
    drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE
    drv_jtag_console_init ();
#endif
#ifdef CONFIG_CBMEM_CONSOLE
    cbmemc_init();
#endif

    return 0;
}

各种驱动初始化,但是我们都没有定义。只有两个默认函数。

第一个,驱动系统初始化,同时注册好标准IO:

static void drv_system_init (void)
{
    struct stdio_dev dev;
 
    memset (&dev, 0, sizeof (dev));
 
    strcpy (dev.name, "serial");        /* 和驱动一样,设备名字很重要 */
    dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
    dev.putc = stdio_serial_putc;
    dev.puts = stdio_serial_puts;
    dev.getc = stdio_serial_getc;
    dev.tstc = stdio_serial_tstc;
    stdio_register (&dev);        /* 注册输入,输出 */
 
#ifdef CONFIG_SYS_DEVICE_NULLDEV   /* 没定义 */
    memset (&dev, 0, sizeof (dev));
 
    strcpy (dev.name, "nulldev");
    dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
    dev.putc = nulldev_putc;
    dev.puts = nulldev_puts;
    dev.getc = nulldev_input;
    dev.tstc = nulldev_input;
 
    stdio_register (&dev);
#endif
}
int stdio_register(struct stdio_dev *dev)
{
    return stdio_register_dev(dev, NULL);
}
 
int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp)
{
    struct stdio_dev *_dev;
 
    _dev = stdio_clone(dev);    /* 前面的是局部变量,这里克隆一份,弄成动态申请的 */
    if(!_dev)
        return -ENODEV;
    list_add_tail(&(_dev->list), &(devs.list));    /* 加入设备链表中 */
    if (devp)
        *devp = _dev;
 
    return 0;
}
 
/* 克隆就是动态拷贝一份 */
struct stdio_dev* stdio_clone(struct stdio_dev *dev)
{
    struct stdio_dev *_dev;
 
    if(!dev)
        return NULL;
 
    _dev = calloc(1, sizeof(struct stdio_dev));
 
    if(!_dev)
        return NULL;
 
    memcpy(_dev, dev, sizeof(struct stdio_dev));
 
    return _dev;
}

第二个,注册系统中的所有串口到驱动链表:

void serial_stdio_init(void)
{
    struct stdio_dev dev;
    struct serial_device *s = serial_devices;
 
    while (s) {
        memset(&dev, 0, sizeof(dev));
 
        strcpy(dev.name, s->name);
        dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
 
        dev.start = serial_stub_start;
        dev.stop = serial_stub_stop;
        dev.putc = serial_stub_putc;
        dev.puts = serial_stub_puts;
        dev.getc = serial_stub_getc;
        dev.tstc = serial_stub_tstc;
        dev.priv = s;
 
        stdio_register(&dev);
 
        s = s->next;
    }
}

3.20 initr_jumptable(common/board_r.c)

static int initr_jumptable(void)
{
    jumptable_init();
    return 0;
}

初始化跳转表common/exports.c:

void jumptable_init(void)
{
    gd->jt = malloc(sizeof(struct jt_funcs));    /* 申请跳转表的内存 */
#include <_exports.h>        //注意这个头文件在函数里面,所以它里面的内容就是函数的内容
}

3.21 console_init_r(common/sonsole.c)

int console_init_r(void)
{
    struct stdio_dev *inputdev = NULL, *outputdev = NULL;
    int i;
    struct list_head *list = stdio_get_list();    // 得到设备链表
    struct list_head *pos;
    struct stdio_dev *dev;

#ifdef CONFIG_SPLASH_SCREEN
    /*
     * suppress all output if splash screen is enabled and we have
     * a bmp to display. We redirect the output from frame buffer
     * console to serial console in this case or suppress it if
     * "silent" mode was requested.
     */
    if (getenv("splashimage") != NULL) {
        if (!(gd->flags & GD_FLG_SILENT))
            outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
    }
#endif

    /* Scan devices looking for input and output devices */
    list_for_each(pos, list) {
        dev = list_entry(pos, struct stdio_dev, list);

        if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
            inputdev = dev;
        }
        if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
            outputdev = dev;
        }
        if(inputdev && outputdev)
            break;
    }

    /* Initializes output console first */
    if (outputdev != NULL) {
        console_setfile(stdout, outputdev);
        console_setfile(stderr, outputdev);
#ifdef CONFIG_CONSOLE_MUX
        console_devices[stdout][0] = outputdev;
        console_devices[stderr][0] = outputdev;
#endif
    }

    /* Initializes input console */
    if (inputdev != NULL) {
        console_setfile(stdin, inputdev);
#ifdef CONFIG_CONSOLE_MUX
        console_devices[stdin][0] = inputdev;
#endif
    }

#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
    stdio_print_current_devices();
#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */

    /* Setting environment variables */
    for (i = 0; i < 3; i++) {
        setenv(stdio_names[i], stdio_devices[i]->name);
    }

    gd->flags |= GD_FLG_DEVINIT;    /* device initialization completed */

#if 0
    /* If nothing usable installed, use only the initial console */
    if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
        return 0;
#endif
    print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL);
    return 0;
}

将stdin,stdout,stderr与具体的终端设备绑定起来。

3.22 interrupt_init(arch/arm/lib/interrupts.c)

int interrupt_init(void)
{
    return 0;
}

3.23 initr_enable_interrupts(common/board_r.c)

static int initr_enable_interrupts(void)
{
    enable_interrupts();
    return 0;
}

enable_interrupts实际是个空函数。

3.24 initr_ethaddr(common/board_r.c)

static int initr_ethaddr(void)
{
    bd_t *bd = gd->bd;

    /* kept around for legacy kernels only ... ignore the next section */
    eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
#ifdef CONFIG_HAS_ETH1
    eth_getenv_enetaddr("eth1addr", bd->bi_enet1addr);
#endif
#ifdef CONFIG_HAS_ETH2
    eth_getenv_enetaddr("eth2addr", bd->bi_enet2addr);
#endif
#ifdef CONFIG_HAS_ETH3
    eth_getenv_enetaddr("eth3addr", bd->bi_enet3addr);
#endif
#ifdef CONFIG_HAS_ETH4
    eth_getenv_enetaddr("eth4addr", bd->bi_enet4addr);
#endif
#ifdef CONFIG_HAS_ETH5
    eth_getenv_enetaddr("eth5addr", bd->bi_enet5addr);
#endif
    return 0;
}

3.25 initr_net(common/board_r.c)

static int initr_net(void)
{
    puts("Net:   ");
    eth_initialize();
#if defined(CONFIG_RESET_PHY_R)
    debug("Reset Ethernet PHY\n");
    reset_phy();
#endif
    return 0;
}

3.26 run_main_loop

到此,board_init_r也就分析完了,最后就是进入u-boot的大循环run_main_loop了,这个里面就是启动内核或者处理用户输入的命令,这部分后面再详细分析一下。

四、总结

board_init_r函数主要做的工作就是准备中断,初始化需要用到的硬件资源,总结下来,大致如下:

  • 注册串口驱动;
  • 初始化NOR FALSH;
  • 初始化NAND FLASH;
  • 注册各种驱动(如果有相关宏定义),默认注册标准IO,注册系统中的所有串口到驱动链表;
  • 初始化跳表
  • 初始化网卡;
  • 执行run_main_loop

最终更改了gd部分成员变量:

flags

指示标志,如设备已经初始化啦

GD_FLG_SERIAL_READY|GD_FLG_RELOC|GD_FLG_FULL_MALLOC_INIT|GD_FLG_ENV_READY

0x00100|0x00001|0x00200|0x00080

jt

jump table

动态申请分配得到

参考文章:

[1]u-boot2020.04移植(6、board_init_r)

[2]uboot1: 启动流程和移植框架

[3]从零开始之uboot、移植uboot2017.01(七、board_init_r分析)

posted @ 2021-11-24 23:15  大奥特曼打小怪兽  阅读(783)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步