• uboot的启动过程-FDT


    uboot的启动过程,省略了汇编部分之后,第一个执行函数是board_init_f(),在uboot/common目录的board_f.c中
     
    board_init_f函数,首先初始化了全局数据
    #ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
        /*
         * For some archtectures, global data is initialized and used before
         * calling this function. The data should be preserved. For others,
         * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
         * here to host global data until relocation.
         */
        gd_t data;
     
        gd = &data;
     
        /*
         * Clear global data before it is accessed at debug print
         * in initcall_run_list. Otherwise the debug print probably
         * get the wrong vaule of gd->have_console.
         */
        zero_global_data();
    #endif
     
    接下来,就是通过函数initcall_run_list,依次调用init_sequence_f列表里面的模块初始化函数。
        gd->flags = boot_flags;
        gd->have_console = 0;
     
        if (initcall_run_list(init_sequence_f))
            hang();
     
    #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && 
            !defined(CONFIG_EFI_APP)
        /* NOTREACHED - jump_to_copy() does not return */
        hang();
    #endif
     
    我手头的uboot源码中,init_sequence_f初始化列表如下,不同的版本会有些差别。注意这里的uboot-spl,就是第一阶段uboot。
      由uboot编译生成,对应于BL1阶段,也就是BL1的镜像,uboot-spl.bin。
    static init_fnc_t init_sequence_f[] = {
    #ifdef CONFIG_SANDBOX
        setup_ram_buf,
    #endif
        setup_mon_len,
    #ifdef CONFIG_OF_CONTROL
        fdtdec_setup,
    #endif
    #ifdef CONFIG_TRACE
        trace_early_init,
    #endif
        initf_malloc,
        initf_console_record,
    #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
        /* TODO: can this go into arch_cpu_init()? */
        probecpu,
    #endif
    #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
        x86_fsp_init,
    #endif
        arch_cpu_init,        /* basic arch cpu dependent setup */
        initf_dm,
        arch_cpu_init_dm,
        mark_bootstage,        /* need timer, go after init dm */
    #if defined(CONFIG_BOARD_EARLY_INIT_F)
        board_early_init_f,
    #endif
        /* TODO: can any of this go into arch_cpu_init()? */
    #if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
        get_clocks,        /* get CPU and bus clocks (etc.) */
    #if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) 
            && !defined(CONFIG_TQM885D)
        adjust_sdram_tbs_8xx,
    #endif
        /* TODO: can we rename this to timer_init()? */
        init_timebase,
    #endif
    #if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || 
            defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || 
            defined(CONFIG_SPARC)
        timer_init,        /* initialize timer */
    #endif
    #ifdef CONFIG_SYS_ALLOC_DPRAM
    #if !defined(CONFIG_CPM2)
        dpram_init,
    #endif
    #endif
    #if defined(CONFIG_BOARD_POSTCLK_INIT)
        board_postclk_init,
    #endif
    #if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
        get_clocks,
    #endif
        env_init,        /* initialize environment */
    #if defined(CONFIG_8xx_CPUCLK_DEFAULT)
        /* get CPU and bus clocks according to the environment variable */
        get_clocks_866,
        /* adjust sdram refresh rate according to the new clock */
        sdram_adjust_866,
        init_timebase,
    #endif
        init_baud_rate,        /* initialze baudrate settings */
        serial_init,        /* serial communications setup */
        console_init_f,        /* stage 1 init of console */
    #ifdef CONFIG_SANDBOX
        sandbox_early_getopt_check,
    #endif
    #ifdef CONFIG_OF_CONTROL
        fdtdec_prepare_fdt,
    #endif
        display_options,    /* say that we are here */
        display_text_info,    /* show debugging info if required */
    #if defined(CONFIG_MPC8260)
        prt_8260_rsr,
        prt_8260_clks,
    #endif /* CONFIG_MPC8260 */
    #if defined(CONFIG_MPC83xx)
        prt_83xx_rsr,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
        checkcpu,
    #endif
        print_cpuinfo,        /* display cpu info (and speed) */
    #if defined(CONFIG_MPC5xxx)
        prt_mpc5xxx_clks,
    #endif /* CONFIG_MPC5xxx */
    #if defined(CONFIG_DISPLAY_BOARDINFO)
        show_board_info,
    #endif
        INIT_FUNC_WATCHDOG_INIT
    #if defined(CONFIG_MISC_INIT_F)
        misc_init_f,
    #endif
        INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
        init_func_i2c,
    #endif
    #if defined(CONFIG_HARD_SPI)
        init_func_spi,
    #endif
        announce_dram_init,
        /* TODO: unify all these dram functions? */
    #if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || 
            defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
        dram_init,        /* configure available RAM banks */
    #endif
    #if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
        init_func_ram,
    #endif
    #ifdef CONFIG_POST
        post_init_f,
    #endif
        INIT_FUNC_WATCHDOG_RESET
    #if defined(CONFIG_SYS_DRAM_TEST)
        testdram,
    #endif /* CONFIG_SYS_DRAM_TEST */
        INIT_FUNC_WATCHDOG_RESET
     
    #ifdef CONFIG_POST
        init_post,
    #endif
        INIT_FUNC_WATCHDOG_RESET
        /*
         * Now that we have DRAM mapped and working, we can
         * relocate the code and continue running from DRAM.
         *
         * Reserve memory at end of RAM for (top down in that order):
         *  - area that won't get touched by U-Boot and Linux (optional)
         *  - kernel log buffer
         *  - protected RAM
         *  - LCD framebuffer
         *  - monitor code
         *  - board info struct
         */
        setup_dest_addr,
    #if defined(CONFIG_BLACKFIN)
        /* Blackfin u-boot monitor should be on top of the ram */
        reserve_uboot,
    #endif
    #if defined(CONFIG_SPARC)
        reserve_prom,
    #endif
    #if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
        reserve_logbuffer,
    #endif
    #ifdef CONFIG_PRAM
        reserve_pram,
    #endif
        reserve_round_4k,
    #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && 
            defined(CONFIG_ARM)
        reserve_mmu,
    #endif
    #ifdef CONFIG_DM_VIDEO
        reserve_video,
    #else
    # ifdef CONFIG_LCD
        reserve_lcd,
    # endif
        /* TODO: Why the dependency on CONFIG_8xx? */
    # if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && 
            !defined(CONFIG_ARM) && !defined(CONFIG_X86) && 
            !defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K)
        reserve_legacy_video,
    # endif
    #endif /* CONFIG_DM_VIDEO */
        reserve_trace,
    #if !defined(CONFIG_BLACKFIN)
        reserve_uboot,
    #endif
    #ifndef CONFIG_SPL_BUILD
        reserve_malloc,
        reserve_board,
    #endif
        setup_machine,
        reserve_global_data,
        reserve_fdt,
        reserve_arch,
        reserve_stacks,
        setup_dram_config,
        show_dram_config,
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
        setup_board_part1,
    #endif
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K)
        INIT_FUNC_WATCHDOG_RESET
        setup_board_part2,
    #endif
        display_new_sp,
    #ifdef CONFIG_SYS_EXTBDINFO
        setup_board_extra,
    #endif
        INIT_FUNC_WATCHDOG_RESET
        reloc_fdt,
        setup_reloc,
    #if defined(CONFIG_X86) || defined(CONFIG_ARC)
        copy_uboot_to_ram,
        clear_bss,
        do_elf_reloc_fixups,
    #endif
    #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
        jump_to_copy,
     
    首先,我们关注device tree的读入,FDT, flatted device tree,扁平设备树, 关于uboot的fdt,可以参考doc/README.fdt-control。
    在启动函数init_sequence_f列表中,与FDT相关的函数主要有三个,如下:
     
    static init_fnc_t init_sequence_f[] = {
    ...
    #ifdef CONFIG_OF_CONTROL
        fdtdec_setup, // 获取dtb的地址,并且验证dtb的合法性
    #endif
    ...
        reserve_fdt, // 为dtb分配新的内存地址空间
    ...
        reloc_fdt, // relocate dtb
    ...
    }
     
    fdtdec_setup函数中,首先根据宏定义的不同,而给全局的device_treegd->fdt_blob指针赋值,可能会有内部或者外部多种情况。
     
    int fdtdec_setup(void)
    {
    #if CONFIG_IS_ENABLED(OF_CONTROL)
    # ifdef CONFIG_OF_EMBED
        /* Get a pointer to the FDT */
        gd->fdt_blob = __dtb_dt_begin;
    // 当使用CONFIG_OF_EMBED的方式时,也就是dtb集成到uboot的bin文件中时,通过__dtb_dt_begin符号来获取dtb地址。
     
    # elif defined CONFIG_OF_SEPARATE
    #  ifdef CONFIG_SPL_BUILD
        /* FDT is at end of BSS unless it is in a different memory region */
        if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
            gd->fdt_blob = (ulong *)&_image_binary_end;
        else
            gd->fdt_blob = (ulong *)&__bss_end;
     
    #  else
        /* FDT is at end of image */
        gd->fdt_blob = (ulong *)&_end;
    //当使用CONFIG_OF_SEPARATE的方式时,也就是dtb追加到uboot的bin文件后面时,通过_end符号来获取dtb地址。
    #  endif
    # elif defined(CONFIG_OF_HOSTFILE)
        if (sandbox_read_fdt_from_file()) {
            puts("Failed to read control FDT
    ");
            return -1;
        }
    # endif
    # ifndef CONFIG_SPL_BUILD
        /* Allow the early environment to override the fdt address */
        gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
                            (uintptr_t)gd->fdt_blob);
    // 可以通过环境变量fdtcontroladdr来指定gd->fdt_blob,也就是指定fdt的地址。
    # endif
    #endif
        return fdtdec_prepare_fdt();
    }
    函数fdtdec_prepare_fdt,只是检查了一下fdt的数据头,是否正确。
    reserve_fdt、 reloc_fdt在分离dts的情况下,为fdt分配空间,重新指定内存中的地址
     
     
  • 相关阅读:
    Quora 用了哪些技术(转)
    Instagram的技术探索2(转)
    Sharding & IDs at Instagram(转)
    2010“架构师接龙”问答--杨卫华VS赵劼(转)
    架构师接龙 汇总(转)
    如何成为一名软件架构师(转)
    网站架构资料集(转)
    技术好重要吗?
    洞洞那么大-悲伤那么小
    教你玩转XSS漏洞
  • 原文地址:https://www.cnblogs.com/djw316/p/10115338.html
Copyright © 2020-2023  润新知