• Mini440之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/samaung/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)

    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)

    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分析)

  • 相关阅读:
    使用Mint-UI的Loadmore实现上拉加载更多和下拉刷新
    JavaScript的日常所得
    web网站性能优化整理
    ArrayBuffer
    Blob
    FormData
    FileReader
    websocket的实践
    Vue CLI 3的Vue.config.js
    css行高line-height的一些深入理解及应用
  • 原文地址:https://www.cnblogs.com/zyly/p/15600819.html
Copyright © 2020-2023  润新知