--------------------------

本文以U-boot 2018.09源码 mips mt7621进行举例说明。

此预期的理论初始化流程适用于全U-boot和SPL(Secondary Program Loader)

这里解释下SPL,SPL是一种U-Boot功能。它将原始u-boot镜像分为两个独立的部分。第一部分用于初始化DRAM(动态随机存取存储器)和其他必要的外围设备,然后将第二部分加载到内存中,然后运行它。第二部分包含u-boot所有剩余的功能。第二部分称为"辅助程序”,第一部分称为"辅助程序加载器"。

所以uboot的启动是分为两级加载的。

目前,SPL部分大多使用单独的代码路径,但函数名和函数的功能都是相同的。某些板级或架构可能与此不符。至少大多数ARM框架的板级使用CONFIG_SPL_FRAMEWORK这个宏来控制这一点。

uboot的目录层次结构:

Directory Hierarchy:
====================/arch           Architecture specific files/arc         Files generic to ARC architecture/arm           Files generic to ARM architecture/m68k          Files generic to m68k architecture/microblaze       Files generic to microblaze architecture/mips           Files generic to MIPS architecture/nds32        Files generic to NDS32 architecture/nios2       Files generic to Altera NIOS2 architecture/openrisc     Files generic to OpenRISC architecture/powerpc      Files generic to PowerPC architecture/riscv     Files generic to RISC-V architecture/sandbox        Files generic to HW-independent "sandbox"/sh            Files generic to SH architecture/x86            Files generic to x86 architecture
/api            Machine/arch independent API for external apps
/board          Board dependent files
/cmd            U-Boot commands functions
/common         Misc architecture independent functions
/configs        Board default configuration files
/disk           Code for disk drive partition handling
/doc            Documentation (don't expect too much)
/drivers        Commonly used device drivers
/dts            Contains Makefile for building internal U-Boot fdt.
/examples       Example code for standalone applications, etc.
/fs         Filesystem code (cramfs, ext2, jffs2, etc.)
/include        Header Files
/lib            Library routines generic to all architectures
/Licenses       Various license files
/net            Networking code
/post           Power On Self Test
/scripts        Various build scripts and Makefiles
/test           Various unit test files
/tools          Tools to build S-Record or U-Boot images, etc.

常用比较重要的几个目录:

DTS配置文件:/arch/your_architecture/dts/xxxx.dts

板级实现/board/xxx

板子默认配置/configs/xxx_defconfig   各种功能宏

板级常规配置/include/configs/xxx.h

uboot固件编译的链接配置文件为u-boot.lds和u-boot-spl.lds,路径如下

suvine@ubuntu:~/workspace/source_code/mtk-openwrt-lede-4.2.1.0/bootloader/u-boot-mt7621-2018.09-gitb178829-20200526$ find ./ -name "u-boot.lds"
./arch/m68k/cpu/u-boot.lds
./arch/nds32/cpu/n1213/u-boot.lds
./arch/arm/cpu/armv8/u-boot.lds
./arch/arm/cpu/u-boot.lds
./arch/arm/mach-zynq/u-boot.lds
./arch/microblaze/cpu/u-boot.lds
./arch/powerpc/cpu/mpc83xx/u-boot.lds
./arch/powerpc/cpu/mpc85xx/u-boot.lds
./arch/powerpc/cpu/mpc86xx/u-boot.lds
./arch/sandbox/cpu/u-boot.lds
./arch/x86/cpu/u-boot.lds
./arch/nios2/cpu/u-boot.lds
./arch/xtensa/cpu/u-boot.lds
./arch/sh/cpu/u-boot.lds
./arch/arc/cpu/u-boot.lds
./arch/riscv/cpu/ax25/u-boot.lds
./arch/mips/cpu/u-boot.lds
./board/birdland/bav335x/u-boot.lds
./board/cssi/MCR3000/u-boot.lds
./board/cirrus/edb93xx/u-boot.lds
./board/compulab/cm_t335/u-boot.lds
./board/vscom/baltos/u-boot.lds
./board/qualcomm/dragonboard410c/u-boot.lds
./board/qualcomm/dragonboard820c/u-boot.lds
./board/ti/am335x/u-boot.lds
./u-boot.lds
suvine@ubuntu:~/workspace/source_code/mtk-openwrt-lede-4.2.1.0/bootloader/u-boot-mt7621-2018.09-gitb178829-20200526$ find ./ -name "u-boot-spl.lds"
./arch/arm/cpu/armv7/sunxi/u-boot-spl.lds
./arch/arm/cpu/armv8/u-boot-spl.lds
./arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds
./arch/arm/cpu/arm926ejs/orion5x/u-boot-spl.lds
./arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds
./arch/arm/cpu/u-boot-spl.lds
./arch/arm/cpu/arm1136/u-boot-spl.lds
./arch/arm/mach-at91/armv7/u-boot-spl.lds
./arch/arm/mach-at91/arm926ejs/u-boot-spl.lds
./arch/arm/mach-zynq/u-boot-spl.lds
./arch/arm/mach-omap2/u-boot-spl.lds
./arch/microblaze/cpu/u-boot-spl.lds
./arch/powerpc/cpu/mpc83xx/u-boot-spl.lds
./arch/powerpc/cpu/mpc85xx/u-boot-spl.lds
./arch/sandbox/cpu/u-boot-spl.lds
./arch/x86/cpu/u-boot-spl.lds
./arch/mips/cpu/u-boot-spl.lds
./tpl/u-boot-spl.lds
./spl/u-boot-spl.lds

U-boot的执行通常从特定于体系架构(可能是

特定于CPU的)start.S文件开始,例如:

-arch/arm/cpu/armv7/start.S

-arch/powerpc/cpu/mpc83xx/start.S

-arch/mips/cpu/start.S

我们例举arch/mips/cpu/start.S源码:


#ifndef CONFIG_SYS_INIT_SP_ADDR
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \CONFIG_SYS_INIT_SP_OFFSET)
#endif#ifdef CONFIG_32BIT
# define MIPS_RELOC 3
# define STATUS_SET 0
#endif#ifdef CONFIG_64BIT
# ifdef CONFIG_SYS_LITTLE_ENDIAN
#  define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \(((r_type) << 24) | ((r_type2) << 16) | ((r_type3) << 8) | (ssym))
# else
#  define MIPS64_R_INFO(ssym, r_type3, r_type2, r_type) \((r_type) | ((r_type2) << 8) | ((r_type3) << 16) | (ssym) << 24)
# endif
# define MIPS_RELOC MIPS64_R_INFO(0x00, 0x00, 0x12, 0x03)
# define STATUS_SET ST0_KX
#endif.set noreorder.macro init_wr selMTC0  zero, CP0_WATCHLO,\selmtc0  t1, CP0_WATCHHI,\selmfc0    t0, CP0_WATCHHI,\selbgez    t0, wr_donenop.endm.macro uhi_mips_exceptionmove    k0, t9      # preserve t9 in k0move k1, a0      # preserve a0 in k1li   t9, 15      # UHI exception operationli a0, 0       # Use hard register contextsdbbp    1       # Invoke UHI operation.endm.macro setup_stack_gdli  t0, -16PTR_LI   t1, CONFIG_SYS_INIT_SP_ADDRand  sp, t1, t0      # force 16 byte alignmentPTR_SUBU \sp, sp, GD_SIZE      # reserve space for gdand   sp, sp, t0      # force 16 byte alignmentmove   k0, sp          # save gd pointer
#if CONFIG_VAL(SYS_MALLOC_F_LEN)li  t2, CONFIG_VAL(SYS_MALLOC_F_LEN)PTR_SUBU \sp, sp, t2        # reserve space for early mallocand sp, sp, t0      # force 16 byte alignment
#endifmove  fp, sp/* Clear gd */move    t0, k0
1:PTR_S zero, 0(t0)blt  t0, t1, 1bPTR_ADDIU t0, PTRSIZE#if CONFIG_VAL(SYS_MALLOC_F_LEN)PTR_S    sp, GD_MALLOC_BASE(k0)  # gd->malloc_base offset
#endif.endmENTRY(_start)/* U-Boot entry point */b   resetmtc0   zero, CP0_COUNT # clear cp0 count for most accurate boot timing#if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG)/** Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to* access external NOR flashes. If the board boots from NOR flash the* internal BootROM does a blind read at address 0xB0000010 to read the* initial configuration for that EBU in order to access the flash* device with correct parameters. This config option is board-specific.*/.org 0x10.word CONFIG_SYS_XWAY_EBU_BOOTCFG.word 0x0
#endif
#if defined(CONFIG_MALTA)/** Linux expects the Board ID here.*/.org 0x10.word 0x00000420    # 0x420 (Malta Board with CoreLV).word 0x00000000
#endif#if defined(CONFIG_ROM_EXCEPTION_VECTORS)/** Exception vector entry points. When running from ROM, an exception* cannot be handled. Halt execution and transfer control to debugger,* if one is attached.*/.org 0x200/* TLB refill, 32 bit task */uhi_mips_exception.org 0x280/* XTLB refill, 64 bit task */uhi_mips_exception.org 0x300/* Cache error exception */uhi_mips_exception.org 0x380/* General exception */uhi_mips_exception.org 0x400/* Catch interrupt exceptions */uhi_mips_exception.org 0x480/* EJTAG debug exception */
1:  b   1bnop.org 0x500
#endifreset:
#if __mips_isa_rev >= 6mfc0  t0, CP0_CONFIG, 5and    t0, t0, MIPS_CONF5_VPbeqz   t0, 1fnopb  2fmfc0  t0, CP0_GLOBALNUMBER
#endif#ifdef CONFIG_ARCH_BMIPS
1:  mfc0    t0, CP0_DIAGNOSTIC, 3and    t0, t0, (1 << 31)
#else
1:  mfc0    t0, CP0_EBASEand    t0, t0, EBASE_CPUNUM
#endif/* Hang if this isn't the first CPU in the system */
2:  beqz    t0, 4fnop
3:  waitb   3bnop/* Init CP0 Status */
4:  mfc0    t0, CP0_STATUSand   t0, ST0_IMPLor  t0, ST0_BEV | ST0_ERL | STATUS_SETmtc0  t0, CP0_STATUS/** Check whether CP0 Config1 is implemented. If not continue* with legacy Watch register initialization.*/mfc0   t0, CP0_CONFIGbgez  t0, wr_legacynop/** Check WR bit in CP0 Config1 to determine if Watch registers* are implemented.*/mfc0 t0, CP0_CONFIG, 1andi   t0, (1 << 3)beqz  t0, wr_donenop/* Clear Watch Status bits and disable watch exceptions */li  t1, 0x7     # Clear I, R and W conditionsinit_wr    0init_wr    1init_wr    2init_wr    3init_wr    4init_wr    5init_wr    6init_wr    7b  wr_donenopwr_legacy:MTC0    zero, CP0_WATCHLOmtc0   zero, CP0_WATCHHIwr_done:/* Clear WP, IV and SW interrupts */mtc0   zero, CP0_CAUSE/* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */mtc0 zero, CP0_COMPARE#ifndef CONFIG_SKIP_LOWLEVEL_INITmfc0  t0, CP0_CONFIGand   t0, t0, MIPS_CONF_IMPLor    t0, t0, CONF_CM_UNCACHEDmtc0    t0, CP0_CONFIGehb
#endif#ifdef CONFIG_MIPS_CMPTR_LA   t9, mips_cm_mapjalr t9nop
#endif#ifdef CONFIG_MIPS_INIT_STACK_IN_SRAM
# ifdef CONFIG_MIPS_STACK_SRAM_INIT/* Configure the SRAM before it can be used */PTR_LA t9, mips_stack_sram_initjalr    t9nop
# endif/* Set up initial stack and global data */setup_stack_gd# ifdef CONFIG_DEBUG_UART/* Earliest point to set up debug uart */PTR_LA t9, debug_uart_initjalr t9nop
# endif
#endif#ifndef CONFIG_SKIP_LOWLEVEL_INIT
# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD/* Initialize any external memory */PTR_LA   t9, lowlevel_initjalr   t9nop
# endif/* Initialize caches... */PTR_LA t9, mips_cache_resetjalr    t9nop# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD/* Initialize any external memory */PTR_LA t9, lowlevel_initjalr   t9nop
# endif
#endif#ifndef CONFIG_MIPS_INIT_STACK_IN_SRAM/* Set up initial stack and global data */setup_stack_gd# ifdef CONFIG_DEBUG_UART/* Earliest point to set up debug uart */PTR_LA    t9, debug_uart_initjalr t9nop
# endif
#endifmove  a0, zero        # a0 <-- boot_flags = 0PTR_LA    t9, board_init_fjr  t9move  ra, zeroEND(_start)

这些为第一阶段的源码,以汇编语言为主,在这里面3个函数会被调用,他们的目的和限制描述如下:

lowlevel_init():
    - purpose: essential init to permit execution to reach board_init_f()
    - no global_data or BSS
    - there is no stack (ARMv7 may have one but it will soon be removed)
    - must not set up SDRAM or use console
    - must only do the bare minimum to allow execution to continue to
        board_init_f()
    - this is almost never needed
    - return normally from this function

例如mips架构mt7621:

void lowlevel_init(void)
{void __iomem *base;#if !defined(CONFIG_SPL) || defined(CONFIG_TPL_BUILD) || \(!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))/* Initialize Coherent Processing System (CPS) related components */mt7621_cps_init();/* Set SPI clock to system bus / (5 + 2) */base = (void __iomem *) CKSEG1ADDR(MT7621_SPI_BASE);clrsetbits_le32(base + MT7621_SPI_SPACE_REG,REG_MASK(FS_CLK_SEL),REG_SET_VAL(FS_CLK_SEL, 5));/* Change CPU ratio from 1/0xA to 1/1 */base = (void __iomem *) CKSEG1ADDR(MT7621_RBUS_BASE);writel(REG_SET_VAL(CPU_FDIV, 1) | REG_SET_VAL(CPU_FFRAC, 1),base + MT7621_RBUS_DYN_CFG0_REG);
#endif#ifndef CONFIG_TPL_BUILD/* Get CPU clock first so we can use delay functions */get_cpu_freq(0);/* Do DRAMC & DDR initialization */mt7621_dram_init();/* Change CPU PLL from 500MHz to CPU_PLL */base = (void __iomem *) CKSEG1ADDR(MT7621_SYSCTL_BASE);clrsetbits_le32(base + MT7621_SYS_CLKCFG0_REG,REG_MASK(CPU_CLK_SEL), REG_SET_VAL(CPU_CLK_SEL, 1));/* Get final CPU clock */gd->cpu_clk = 0;get_cpu_freq(0);/* Setup USB xHCI */mt7621_xhci_config();/* Do memory test */
#ifdef CONFIG_MT7621_MEMTESTmemtest(gd->ram_size);
#endif
#endif
}

board_init_f():
    - purpose: set up the machine ready for running board_init_r():
        i.e. SDRAM and serial UART
    - global_data is available
    - stack is in SRAM
    - BSS is not available, so you cannot use global/static variables,
        only stack variables and global_data

Non-SPL-specific notes:
    - dram_init() is called to set up DRAM. If already done in SPL this
        can do nothing

SPL-specific notes:
    - you can override the entire board_init_f() function with your own
        version as needed.
    - preloader_console_init() can be called here in extremis
    - should set up SDRAM, and anything needed to make the UART work
    - these is no need to clear BSS, it will be done by crt0.S
    - must return normally from this function (don't call board_init_r()
        directly)

board_init_f函数里面BBS会被清除,对于SPL如果定义了CONFIG_SPL_STACK_R宏stack 和 global_data会定位在CONFIG_SPL_STACK_R_ADDR这个地址。非SPL,U-Boot被重新定位为在内存顶部。

common/board_f.c   board_init_f:

void board_init_f(ulong boot_flags)
{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) && !CONFIG_IS_ENABLED(X86_64) && \!defined(CONFIG_ARC)/* NOTREACHED - jump_to_copy() does not return */hang();
#endif
}//初始化序列
static const init_fnc_t init_sequence_f[] = {setup_mon_len,
#ifdef CONFIG_OF_CONTROLfdtdec_setup,
#endif
#ifdef CONFIG_TRACEtrace_early_init,
#endifinitf_malloc,log_init,initf_bootstage,    /* uses its own timer, so does not need DM */initf_console_record,
#if defined(CONFIG_HAVE_FSP)arch_fsp_init,
#endifarch_cpu_init,        /* basic arch cpu dependent setup */mach_cpu_init,      /* SoC/machine dependent CPU setup */initf_dm,arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)board_early_init_f,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)/* get CPU and bus clocks according to the environment variable */get_clocks,     /* get CPU and bus clocks (etc.) */
#endif
#if !defined(CONFIG_M68K)timer_init,        /* initialize timer */
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)board_postclk_init,
#endifenv_init,     /* initialize environment */init_baud_rate,     /* initialze baudrate settings */serial_init,       /* serial communications setup */console_init_f,        /* stage 1 init of console */display_options,   /* say that we are here */display_text_info,    /* show debugging info if required */
#if defined(CONFIG_PPC) || defined(CONFIG_SH) || defined(CONFIG_X86)checkcpu,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo,       /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DTB_RESELECT)embedded_dtb_select,
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)show_board_info,
#endifINIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)misc_init_f,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_I2C)init_func_i2c,
#endif
#if defined(CONFIG_VID) && !defined(CONFIG_SPL)init_func_vid,
#endif
#if defined(CONFIG_HARD_SPI)init_func_spi,
#endifannounce_dram_init,dram_init,     /* configure available RAM banks */
#ifdef CONFIG_POSTpost_init_f,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)testdram,
#endif /* CONFIG_SYS_DRAM_TEST */INIT_FUNC_WATCHDOG_RESET#ifdef CONFIG_POSTinit_post,
#endifINIT_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,
#ifdef CONFIG_PRAMreserve_pram,
#endifreserve_round_4k,
#ifdef CONFIG_ARMreserve_mmu,
#endifreserve_video,reserve_trace,reserve_uboot,reserve_malloc,reserve_board,setup_machine,reserve_global_data,reserve_fdt,reserve_bootstage,reserve_arch,reserve_stacks,dram_init_banksize,show_dram_config,
#if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \defined(CONFIG_SH)setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)INIT_FUNC_WATCHDOG_RESETsetup_board_part2,
#endifdisplay_new_sp,
#ifdef CONFIG_OF_BOARD_FIXUPfix_fdt,
#endifINIT_FUNC_WATCHDOG_RESETreloc_fdt,reloc_bootstage,setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)copy_uboot_to_ram,do_elf_reloc_fixups,clear_bss,
#endif
#if defined(CONFIG_XTENSA)clear_bss,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \!CONFIG_IS_ENABLED(X86_64)jump_to_copy,
#endifNULL,
};
//第二级跳转
static int jump_to_copy(void)
{if (gd->flags & GD_FLG_SKIP_RELOC)return 0;/** x86 is special, but in a nice way. It uses a trampoline which* enables the dcache if possible.** For now, other archs use relocate_code(), which is implemented* similarly for all archs. When we do generic relocation, hopefully* we can make all archs enable the dcache prior to relocation.*/
#if defined(CONFIG_X86) || defined(CONFIG_ARC)/** SDRAM and console are now initialised. The final stack can now* be setup in SDRAM. Code execution will continue in Flash, but* with the stack in SDRAM and Global Data in temporary memory* (CPU cache)*/arch_setup_gd(gd->new_gd);board_init_f_r_trampoline(gd->start_addr_sp);
#elserelocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr);
#endifreturn 0;
}
//mips跳转实现
void relocate_code(ulong start_addr_sp, gd_t *new_gd, ulong relocaddr)
{unsigned long addr, length, bss_len;uint8_t *buf, *bss_start;unsigned int type;long off;/** Ensure that we're relocating by an offset which is a multiple of* 64KiB, ie. doesn't change the least significant 16 bits of any* addresses. This allows us to discard R_MIPS_LO16 relocs, saving* space in the U-Boot binary & complexity in handling them.*/off = relocaddr - (unsigned long)__text_start;if (off & 0xffff)panic("Mis-aligned relocation\n");/* Copy U-Boot to RAM */length = __image_copy_end - __text_start;memcpy((void *)relocaddr, __text_start, length);/* Now apply relocations to the copy in RAM */buf = __rel_start;addr = relocaddr;while (true) {type = read_uint(&buf);if (type == R_MIPS_NONE)break;addr += read_uint(&buf) << 2;apply_reloc(type, (void *)addr, off);}/* Ensure the icache is coherent */flush_cache(relocaddr, length);/* Clear the .bss section */bss_start = (uint8_t *)((unsigned long)__bss_start + off);bss_len = (unsigned long)&__bss_end - (unsigned long)__bss_start;memset(bss_start, 0, bss_len);/* Jump to the relocated U-Boot */asm volatile("move   $29, %0\n"" move    $4, %1\n""  move    $5, %2\n""  move    $31, $0\n"" jr  %3": /* no outputs */: "r"(start_addr_sp),"r"(new_gd),"r"(relocaddr),"r"((unsigned long)board_init_r + off));/* Since we jumped to the new U-Boot above, we won't get here */unreachable();
}

可见board_init_f函数做了一系列的初始化,初始化失败会hang住;成功会跳转执行board_init_r,至此正式进入u-boot的第二阶段。

board_init_r():
    - purpose: main execution, common code
    - global_data is available
    - SDRAM is available
    - BSS is available, all static/global variables can be used
    - execution eventually continues to main_loop()

Non-SPL-specific notes:
    - U-Boot is relocated to the top of memory and is now running from
        there.

SPL-specific notes:
    - stack is optionally in SDRAM, if CONFIG_SPL_STACK_R is defined and
        CONFIG_SPL_STACK_R_ADDR points into SDRAM
    - preloader_console_init() can be called here - typically this is
        done by selecting CONFIG_SPL_BOARD_INIT and then supplying a
        spl_board_init() function containing this call
    - loads U-Boot or (in falcon mode) Linux

common/board_r.c   board_init_r:

void board_init_r(gd_t *new_gd, ulong dest_addr)
{/** Set up the new global data pointer. So far only x86 does this* here.* TODO(sjg@chromium.org): Consider doing this for all archs, or* dropping the new_gd parameter.*/
#if CONFIG_IS_ENABLED(X86_64)arch_setup_gd(new_gd);
#endif#ifdef CONFIG_NEEDS_MANUAL_RELOCint i;
#endif#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)gd = new_gd;
#endifgd->flags &= ~GD_FLG_LOG_READY;#ifdef CONFIG_NEEDS_MANUAL_RELOCfor (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)init_sequence_r[i] += gd->reloc_off;
#endifif (initcall_run_list(init_sequence_r))hang();/* NOTREACHED - run_main_loop() does not return */hang();
}
//初始化序列
static init_fnc_t init_sequence_r[] = {initr_trace,initr_reloc,/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARMinitr_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 available*   until board_init() is called below to remap IFC to high*    region.*/
#endifinitr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)initr_unlock_ram_in_cache,
#endifinitr_barrier,initr_malloc,log_init,initr_bootstage,  /* Needs malloc() but has its own timer */initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORYinitr_noncached,
#endifbootstage_relocate,
#ifdef CONFIG_OF_LIVEinitr_of_live,
#endif
#ifdef CONFIG_DMinitr_dm,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \defined(CONFIG_SANDBOX)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_CLOCKSset_cpu_clk_info, /* Setup clock information */
#endif
#ifdef CONFIG_EFI_LOADERefi_memory_init,
#endifstdio_init_tables,initr_serial,initr_announce,INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOCinitr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)initr_trap,
#endif
#ifdef CONFIG_ADDR_MAPinitr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)board_early_init_r,
#endifINIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_POSTinitr_post_backlog,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)/** Do early PCI configuration _before_ the flash gets initialised,* because PCU resources are crucial for flash access on some boards.*/initr_pci,
#endif
#ifdef CONFIG_ARCH_EARLY_INIT_Rarch_early_init_r,
#endifpower_init_board,
#ifdef CONFIG_MTD_NOR_FLASHinitr_flash,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86)/* initialize higher level parts of CPU like time base and timers */cpu_init_r,
#endif
#ifdef CONFIG_PPCinitr_spi,
#endif
#ifdef CONFIG_CMD_NANDinitr_nand,
#endif
#ifdef CONFIG_NMBM_MTDinitr_nmbm,
#endif
#ifdef CONFIG_CMD_ONENANDinitr_onenand,
#endif
#ifdef CONFIG_MMCinitr_mmc,
#endifinitr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LENinitr_malloc_bootparams,
#endifINIT_FUNC_WATCHDOG_RESETinitr_secondary_cpu,
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)mac_read_from_eeprom,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)/** Do pci configuration*/initr_pci,
#endifstdio_add_devices,initr_jumptable,
#ifdef CONFIG_APIinitr_api,
#endifconsole_init_r,       /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATEconsole_announce_r,show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INITarch_misc_init,     /* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_Rmisc_init_r,       /* miscellaneous platform-dependent init */
#endifINIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDBinitr_kgdb,
#endifinterrupt_init,
#ifdef CONFIG_ARMinitr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_M68K)timer_init,       /* initialize timer */
#endif
#if defined(CONFIG_LED_STATUS)initr_status_led,
#endif/* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NETinitr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INITboard_late_init,
#endif
#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)INIT_FUNC_WATCHDOG_RESETinitr_scsi,
#endif
#ifdef CONFIG_BITBANGMIIinitr_bbmii,
#endif
#ifdef CONFIG_CMD_NETINIT_FUNC_WATCHDOG_RESETinitr_net,
#endif
#ifdef CONFIG_POSTinitr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_IDE)initr_pcmcia,
#endif
#if defined(CONFIG_IDE) && !defined(CONFIG_BLK)initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INITINIT_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_BEDBUGINIT_FUNC_WATCHDOG_RESETinitr_bedbug,
#endif
#if defined(CONFIG_PRAM)initr_mem,
#endifrun_main_loop,
};
//主loop
void main_loop(void)
{const char *s;bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");#ifdef CONFIG_VERSION_VARIABLEenv_set("ver", version_string);  /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */cli_init();run_preboot_environment_command();#if defined(CONFIG_UPDATE_TFTP)update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */s = bootdelay_process();if (cli_process_fdt(&s))cli_secure_boot_cmd(s);autoboot_command(s);cli_loop();panic("No CLI available");
}

board_init_r此函数经过一些列初始化后进入main_loop,同样初始化失败也会hang住,进入main_loop后终端输入打断就会进行cmd交互否则等待超时时间后加载kernel镜像启动kernel

编译方法:

$ CROSS_COMPILE=ppc_4xx-
    $ export CROSS_COMPILE

make NAME_defconfig

make all

常见命令说明:

Monitor Commands - Overview:
============================go  - start application at address 'addr'
run - run commands in an environment variable
bootm   - boot application image from memory
bootp   - boot image via network using BootP/TFTP protocol
bootz   - boot zImage from memory
tftpboot- boot image via network using TFTP protocoland env variables "ipaddr" and "serverip"(and eventually "gatewayip")
tftpput - upload a file via network using TFTP protocol
rarpboot- boot image via network using RARP/TFTP protocol
diskboot- boot from IDE devicebootd   - boot default, i.e., run 'bootcmd'
loads   - load S-Record file over serial line
loadb   - load binary file over serial line (kermit mode)
md  - memory display
mm  - memory modify (auto-incrementing)
nm  - memory modify (constant address)
mw  - memory write (fill)
cp  - memory copy
cmp - memory compare
crc32   - checksum calculation
i2c - I2C sub-system
sspi    - SPI utility commands
base    - print or set address offset
printenv- print environment variables
setenv  - set environment variables
saveenv - save environment variables to persistent storage
protect - enable or disable FLASH write protection
erase   - erase FLASH memory
flinfo  - print FLASH memory information
nand    - NAND memory operations (see doc/README.nand)
bdinfo  - print Board Info structure
iminfo  - print header information for application image
coninfo - print console devices and informations
ide - IDE sub-system
loop    - infinite loop on address range
loopw   - infinite write loop on address range
mtest   - simple RAM test
icache  - enable or disable instruction cache
dcache  - enable or disable data cache
reset   - Perform RESET of the CPU
echo    - echo args to console
version - print monitor version
help    - print online help
?   - alias for 'help'

常见环境变量:

Environment Variables are set using "setenv", printed using
"printenv", and saved to Flash using "saveenv". Using "setenv"
without a value can be used to delete a variable from the
environment. As long as you don't save the environment you are
working with an in-memory copy. In case the Flash area containing the
environment is erased by accident, a default environment is provided.Some configuration options can be set using Environment Variables.List of environment variables (most likely not complete):baudrate    - see CONFIG_BAUDRATEbootdelay  - see CONFIG_BOOTDELAYbootcmd   - see CONFIG_BOOTCOMMANDbootargs    - Boot arguments when booting an RTOS imagebootfile - Name of the image to load with TFTPbootm_low  - Memory range available for image processing in the bootmcommand can be restricted. This variable is given asa hexadecimal number and defines lowest address allowedfor use by the bootm command. See also "bootm_size"environment variable. Address defined by "bootm_low" isalso the base of the initial memory mapping for the Linuxkernel -- see the description of CONFIG_SYS_BOOTMAPSZ andbootm_mapsize.bootm_mapsize - Size of the initial memory mapping for the Linux kernel.This variable is given as a hexadecimal number and itdefines the size of the memory region starting at baseaddress bootm_low that is accessible by the Linux kernelduring early boot.  If unset, CONFIG_SYS_BOOTMAPSZ is usedas the default value if it is defined, and bootm_size isused otherwise.bootm_size   - Memory range available for image processing in the bootmcommand can be restricted. This variable is given asa hexadecimal number and defines the size of the regionallowed for use by the bootm command. See also "bootm_low"environment variable.updatefile  - Location of the software update file on a TFTP server, usedby the automatic software update feature. Please refer todocumentation in doc/README.update for more details.autoload  - if set to "no" (any string beginning with 'n'),"bootp" will just load perform a lookup of theconfiguration from the BOOTP server, but not try toload any image using TFTPautostart    - if set to "yes", an image loaded using the "bootp","rarpboot", "tftpboot" or "diskboot" commands willbe automatically started (by internally calling"bootm")If set to "no", a standalone image passed to the"bootm" command will be copied to the load address(and eventually uncompressed), but NOT be started.This can be used to load and uncompress arbitrarydata.fdt_high    - if set this restricts the maximum address that theflattened device tree will be copied into upon boot.For example, if you have a system with 1 GB memoryat physical address 0x10000000, while Linux kernelonly recognizes the first 704 MB as low memory, youmay need to set fdt_high as 0x3C000000 to have thedevice tree blob be copied to the maximum addressof the 704 MB low memory, so that Linux kernel canaccess it during the boot procedure.If this is set to the special value 0xFFFFFFFF thenthe fdt will not be copied at all on boot.  For thisto work it must reside in writable memory, havesufficient padding on the end of it for u-boot toadd the information it needs into it, and the memorymust be accessible by the kernel.fdtcontroladdr- if set this is the address of the control flatteneddevice tree used by U-Boot when CONFIG_OF_CONTROL isdefined.i2cfast  - (PPC405GP|PPC405EP only)if set to 'y' configures Linux I2C driver for fastmode (400kHZ). This environment variable is used ininitialization code. So, for changes to be effectiveit must be saved and board must be reset.initrd_high - restrict positioning of initrd images:If this variable is not set, initrd images will becopied to the highest possible address in RAM; thisis usually what you want since it allows formaximum initrd size. If for some reason you want tomake sure that the initrd image is loaded below theCONFIG_SYS_BOOTMAPSZ limit, you can set this environmentvariable to a value of "no" or "off" or "0".Alternatively, you can set it to a maximum upperaddress to use (U-Boot will still check that itdoes not overwrite the U-Boot stack and data).For instance, when you have a system with 16 MBRAM, and want to reserve 4 MB from use by Linux,you can do this by adding "mem=12M" to the value ofthe "bootargs" variable. However, now you must makesure that the initrd image is placed in the first12 MB as well - this can be done withsetenv initrd_high 00c00000If you set initrd_high to 0xFFFFFFFF, this is anindication to U-Boot that all addresses are legalfor the Linux kernel, including addresses in flashmemory. In this case U-Boot will NOT COPY theramdisk at all. This may be useful to reduce theboot time on your system, but requires that thisfeature is supported by your Linux kernel.ipaddr  - IP address; needed for tftpboot commandloadaddr   - Default load address for commands like "bootp","rarpboot", "tftpboot", "loadb" or "diskboot"loads_echo    - see CONFIG_LOADS_ECHOserverip - TFTP server IP address; needed for tftpboot commandbootretry  - see CONFIG_BOOT_RETRY_TIMEbootdelaykey    - see CONFIG_AUTOBOOT_DELAY_STRbootstopkey  - see CONFIG_AUTOBOOT_STOP_STRethprime  - controls which interface is used first.ethact - controls which interface is currently active.For example you can do the following=> setenv ethact FEC=> ping 192.168.0.1 # traffic sent on FEC=> setenv ethact SCC=> ping 10.0.0.1 # traffic sent on SCCethrotate - When set to "no" U-Boot does not go through allavailable network interfaces.It just stays at the currently selected interface.netretry    - When set to "no" each network operation willeither succeed or fail without retrying.When set to "once" the network operation willfail when all the available network interfacesare tried once without success.Useful on scripts which control the retry operationthemselves.npe_ucode - set load address for the NPE microcodesilent_linux  - If set then Linux will be told to boot silently, bychanging the console to be empty. If "yes" it will bemade silent. If "no" it will not be made silent. Ifunset, then it will be made silent if the U-Boot consoleis silent.tftpsrcp   - If this is set, the value is used for TFTP'sUDP source port.tftpdstp  - If this is set, the value is used for TFTP's UDPdestination port instead of the Well Know Port 69.tftpblocksize - Block size to use for TFTP transfers; if not set,we use the TFTP server's default block sizetftptimeout - Retransmission timeout for TFTP packets (in milli-seconds, minimum value is 1000 = 1 second). Defineswhen a packet is considered to be lost so it has tobe retransmitted. The default is 5000 = 5 seconds.Lowering this value may make downloads succeedfaster in networks with high packet loss rates orwith unreliable TFTP servers.tftptimeoutcountmax - maximum count of TFTP timeouts (nounit, minimum value = 0). Defines how many timeoutscan happen during a single file transfer before thattransfer is aborted. The default is 10, and 0 means'no timeouts allowed'. Increasing this value may helpdownloads succeed with high packet loss rates, or withunreliable TFTP servers or client hardware.vlan        - When set to a value < 4095 the traffic overEthernet is encapsulated/received over 802.1qVLAN tagged frames.bootpretryperiod    - Period during which BOOTP/DHCP sends retries.Unsigned value, in milliseconds. If not set, the period willbe either the default (28000), or a value based onCONFIG_NET_RETRY_COUNT, if defined. This value hasprecedence over the valu based on CONFIG_NET_RETRY_COUNT.

常见问题:

Ubuntu20.04在进行arm-linux-gcc交叉编译时遇到的一个问题:
error while loading shared libraries: libmpfr.so.4: cannot open shared object file: No such file or directory

加载共享库时出错:libmpfr.so.4:无法打开共享对象文件:没有这样的文件或目录

解决方法:
创建符号链接

sudo ln -s /usr/lib/x86_64-linux-gnu/libmpfr.so.6 /usr/lib/x86_64-linux-gnu/libmpfr.so.4

常见调试手段:

1、printf打印跟踪

2、打开DBUG宏,include/log.h里面定义DEBUG宏开关#define DEBUG后uboot会输入大量的log信息,由前文所述,两个阶段的初始化序列失败都会hang住,打开此宏会定位到哪个模块出了问题,然后再修改,调试。

开DEBUG宏可能出错

很明显链接SPL时bbs_mem overflowed,修改#define CONFIG_SPL_BSS_MAX_SIZE        0x2000 大小为0x4000 编译OK。

Uboot 板级初始化流程and so on相关推荐

  1. linux板级初始化

    最近拿到了明远智睿 的EK314开发板,以前主要用2440,眼界过于狭隘,借此机会练习下. http://lornyin.top/?p=106 原文地址 首先看看它的板级文件 /arch/arm/ma ...

  2. 全志A64 U-BOOT起始串口初始化流程详解

    串口执行流程,首先是/common/board_f.c中 先调用 void board_init_f(ulong boot_flags) 该函数是汇编代码进入C代码前在_main中调用的地址重定向前的 ...

  3. at91sam9260ek的板级、irq初始化-小试牛刀

    话不多说,先上代码. //code path:arch/arm/mach-at91/board-sam9260ek.c MACHINE_START(AT91SAM9260EK, "Atmel ...

  4. Uboot 2017.01 启动流程分析

    前言 2017.01 UBoot包含两个阶段的启动,一个是SPL启动,一个是正常的启动我们称为第二阶段Uboot.当然,我们也可以选择使用SPL和不使用. 在编译的过程中,是先编译第二阶段Uboot, ...

  5. i.MX6 u-boot 怎么确定板级头文件

    /*********************************************************************** i.MX6 u-boot 怎么确定板级头文件* 说明: ...

  6. 从0移植uboot (二) _uboot启动流程分析

    经过了上一篇的配置,我们已经执行make就可以编译出一个uboot.bin,但这还不够,首先,此时的uboot并不符合三星芯片对bootloader的格式要求,同时,此时的uboot.bin也没有结合 ...

  7. uboot 分析之 启动流程

    uboot的启动流程: 看一幅图: 1.第一阶段:start.s的内容: 点击(此处)折叠或打开 #include <config.h> @该文件是第二步中mkconfig文件执行时创建的 ...

  8. 从0移植uboot (二) _启动流程分析

    来源:Linux社区  作者:xiaojiang1025  : http://www.linuxidc.com/Linux/2017-02/141019.htm 经过了上一篇的配置,我们已经执行mak ...

  9. 【原创】MIPS中断系统的板级验证及实例测试

    "五一"假期前后这约五天时间,终于将MIPS中断系统进行了板级验证及实例测试.因为老师给的交叉编译工具不会用,所以测试代码完全用MIPS汇编编写.使用MARS而没有用QtSpim, ...

最新文章

  1. 继SqlPager之后推出一款可用于前台页面的分页控件--UrlPager
  2. SQLServer 常见高CPU利用率原因
  3. elasticsearch最大节点数_ElasticSearch这些概念要明白
  4. 第六章 Web开发实战1——HTTP服务
  5. cannot load php5,Cannot load php5apache2_4.dll into server解决办法
  6. Python实现AES加密进行PKCS5Padding的填充
  7. 求翻转数循环结构C语言,[LeetCode Easy题快一起刷起来] 1. 两数之和 7. 整数翻转
  8. 【面向对象】第四单元总结——UML
  9. Qt信号阻塞和断开信号槽
  10. linux转发邮件,转发Linux服务器上的传入邮件?
  11. Hadoop学习入门(二)——部署关键问题1:OpenSSH 密钥管理(1)
  12. yacc 简易计算机规则,YACC 使用说明——计算器实例.pdf
  13. 瑞星:愚人节Conficker蠕虫未在我国爆发
  14. 谁才是中国企业服务的教父?
  15. 人工智能:爬山法、随机重启爬山法、模拟退火算法、遗传算法、启发式搜索方法解决八数码和八皇后问题
  16. 保利威视自定义右键菜单设置
  17. 【光线追踪系列十四】蒙特卡洛积分与重要性采样
  18. 中老年人谨防跟腱断裂
  19. STM32----中断优先级设置
  20. Xxl Job Helloworld

热门文章

  1. 关于区块链、Web3.0、智能合约、DApp、DAO一文解释清楚
  2. 【Mo 人工智能技术博客】python玩转信号处理与机器学习入门
  3. Flask项目实战——10—(前台板块页面搭建、文本编辑页面搭建、发布帖子信息前验证权限、帖子模型搭建、发布帖子功能、帖子信息渲染到前后台页面)
  4. 基于深度学习的语义匹配
  5. 利用鲍伊-迪克测试法测试饱和蒸汽以确保适当灭菌消毒
  6. ESP32-C3入门教程 WiFi篇⑨——WiFi配网失败常见问题与解决办法(找不到WiFi AP | WiFi密码错误 | 距离AP过远 RSSI判断)
  7. 西南科技大学Linux实验名称:实验二 Linux环境网络管理
  8. SpringBoot集成mysql-connector-java数据库驱动
  9. 【LeetCode Python实现】908. 最小差值 I(简单)
  10. 让Android控件随着屏幕旋转自由转移至任何地方(附demo)