u-boot.bin

这里的u-boot.bin指的是不包含SPL的stage2部分的代码. 它会被SPL搬移到RAM的某个地址处开始运行. 本篇下面提到的u-boot.bin时, 也是指的这个概念.

u-boot.bin的文件组成

当我们在uboot下执行make命令的时候, 它最核心的功能是执行Makefile中的all目标编译出相应的文件. 我们来看看这个all目标

[plain] view plain copy  在CODE上查看代码片派生到我的代码片

  1. all:        $(ALL-y) $(SUBDIR_EXAMPLES)

all依赖于$(ALL-y) 和 $(SUBDIR_EXAMPLES), 这里我只关注ALL-y, 如下:

[plain] view plain copy  在CODE上查看代码片派生到我的代码片

  1. # Always append ALL so that arch config.mk's can add custom ones
  2. ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map</span>
  3. ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin
  4. ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
  5. ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
  6. ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.img
  7. ALL-$(CONFIG_TPL) += $(obj)tpl/u-boot-tpl.bin
  8. ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin
  9. ifneq ($(CONFIG_SPL_TARGET),)
  10. ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))
  11. endif
  12. # enable combined SPL/u-boot/dtb rules for tegra
  13. ifneq ($(CONFIG_TEGRA),)
  14. ifeq ($(CONFIG_OF_SEPARATE),y)
  15. ALL-y += $(obj)u-boot-dtb-tegra.bin
  16. else
  17. ALL-y += $(obj)u-boot-nodtb-tegra.bin
  18. endif
  19. endif

注意红色部分的代码, 它表面all目标依赖 $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map

先忽略System.map, 在看下面一段

[plain] view plain copy  在CODE上查看代码片派生到我的代码片

  1. $(obj)u-boot.srec:  $(obj)u-boot
  2. $(OBJCOPY) -O srec $< $@
  3. $(obj)u-boot.bin:   $(obj)u-boot
  4. $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
  5. $(BOARD_SIZE_CHECK)

它们都依赖于u-boot

那么在看看u-boot的依赖关系

[plain] view plain copy  在CODE上查看代码片派生到我的代码片

  1. ifeq ($(CONFIG_SANDBOX),y)
  2. GEN_UBOOT = \
  3. cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
  4. -Wl,--start-group $(__LIBS) -Wl,--end-group \
  5. $(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot
  6. else
  7. GEN_UBOOT = \
  8. cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
  9. $(__OBJS) \
  10. --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
  11. -Map u-boot.map -o u-boot
  12. endif
  13. $(obj)u-boot:   depend \
  14. $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
  15. $(GEN_UBOOT)
  • depend: 参考附录中的depend
  • $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) : 各个子目录
  • $(LDSCRIPT) : 如下, 默认就是在arch/arm/cpu/下面的u-boot.lds
  • [plain] view plain copy

    1. # If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use
    2. # that (or fail if absent).  Otherwise, search for a linker script in a
    3. # standard location.
    4. LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))
    5. ifndef LDSCRIPT
    6. #LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
    7. ifdef CONFIG_SYS_LDSCRIPT
    8. # need to strip off double quotes
    9. LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))
    10. endif
    11. endif
    12. # If there is no specified link script, we look in a number of places for it
    13. ifndef LDSCRIPT
    14. ifeq ($(CONFIG_NAND_U_BOOT),y)
    15. LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
    16. ifeq ($(wildcard $(LDSCRIPT)),)
    17. LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
    18. endif
    19. endif
    20. ifeq ($(wildcard $(LDSCRIPT)),)
    21. LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
    22. endif
    23. ifeq ($(wildcard $(LDSCRIPT)),)
    24. LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds
    25. endif
    26. ifeq ($(wildcard $(LDSCRIPT)),)
    27. LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
    28. # We don't expect a Makefile here
    29. LDSCRIPT_MAKEFILE_DIR =
    30. endif
    31. ifeq ($(wildcard $(LDSCRIPT)),)
    32. $(error could not find linker script)
    33. endif
    34. endif
  • $(GEN_UBOOT) : 利用ld命令链接生成u-boot

OK, 这就是u-boot.bin相关的文件组成. 如果想知道到底编译了哪些目录, 可以根据Makefile仔细研究它到底依赖了哪些文件夹. 原理与上面类似.

代码分析

u-boot.lds: 它的位置在上文中我们分析了

  • 根据u-boot.lds中的规则, 与SPL阶段一样, CPUDIR/start.o被放在了最前面. 它与SPL阶段对应的是同一个文件arch/arm/cpu/armv7/start.S

start.S

与SPL中start.S的执行流程基本一致, 不同的地方是, 这里的start.S会负责处理异常中断.

ctr0.S

_main

[plain] view plain copy

  1. ENTRY(_main)
  2. /*
  3. * Set up initial C runtime environment and call board_init_f(0).
  4. */
  5. #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
  6. ldr sp, =(CONFIG_SPL_STACK)
  7. #else
  8. ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
  9. #endif
  10. bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
  11. sub sp, #GD_SIZE    /* allocate one GD above SP */
  12. bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
  13. mov r9, sp      /* GD is above SP */
  14. mov r0, #0
  15. bl  board_init_f
  • sp, gd相关, 参考SPL中的_main
  • bl board_init_f: 跳转到board_init_f
    • SPL最后也是跳转到board_init_f, 它们有什么不一样吗? 是的, 完全不一样. 由于SPL阶段与u-boot.bin阶段编译选项的不同, 会导致不同的c文件被编译. 这里的board_init_f实现函数与SPL阶段board_init_f的实现函数不是同一个.

[plain] view plain copy

  1. #if ! defined(CONFIG_SPL_BUILD)
  2. /*
  3. * Set up intermediate environment (new sp and gd) and call
  4. * relocate_code(addr_moni). Trick here is that we'll return
  5. * 'here' but relocated.
  6. */
  7. ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
  8. bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
  9. ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */
  10. sub r9, r9, #GD_SIZE        /* new GD is below bd */
  11. adr lr, here
  12. ldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off */
  13. add lr, lr, r0
  14. ldr r0, [r9, #GD_RELOCADDR]     /* r0 = gd->relocaddr */
  15. b   relocate_code
  16. here:
  17. /* Set up final (full) environment */
  18. bl  c_runtime_cpu_setup /* we still call old routine here */
  19. ldr r0, =__bss_start    /* this is auto-relocated! */
  20. ldr r1, =__bss_end      /* this is auto-relocated! */
  21. mov r2, #0x00000000     /* prepare zero to clear BSS */
  22. clbss_l:cmp r0, r1          /* while not at end of BSS */
  23. strlo   r2, [r0]        /* clear 32-bit BSS word */
  24. addlo   r0, r0, #4      /* move to next */
  25. blo clbss_l
  26. bl coloured_LED_init
  27. bl red_led_on
  28. /* call board_init_r(gd_t *id, ulong dest_addr) */
  29. mov     r0, r9                  /* gd_t */
  30. ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
  31. /* call board_init_r */
  32. ldr pc, =board_init_r   /* this is auto-relocated! */
  33. /* we should not return here. */
  34. #endif
  • #if ! defined(CONFIG_SPL_BUILD) : 说明只有在u-boot.bin阶段, 才会执行这段代码. 这里也与SPL阶段不一样
  • b relocate_code : 把代码relocate到编译地址处
  • ldr pc, =board_init_r: 调用board_init_r, 同样, 该函数实现的地方与SPL阶段的也不一样.

arch/arm/lib/board.c

board_init_f

[plain] view plain copy

  1. memset((void *)gd, 0, sizeof(gd_t));
  • gd的定义在board.c里面, 有一行: DECLARE_GLOBAL_DATA_PTR;
  • memset清零, 说明从这里开始, 重新对gd进行初始化.
  • 那我们在前面的代码很看到很多对gd的操作啊, 有什么用呢? 主要是在一些汇编代码里面引用了gd的相关变量. 哪些变量可能被引用到呢? 在这里 lib/asm-offsets.c

[plain] view plain copy

  1. #ifdef CONFIG_OF_EMBED
  2. /* Get a pointer to the FDT */
  3. gd->fdt_blob = _binary_dt_dtb_start;
  4. #elif defined CONFIG_OF_SEPARATE
  5. /* FDT is at end of image */
  6. gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
  7. #endif
  8. /* Allow the early environment to override the fdt address */
  9. gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
  10. (uintptr_t)gd->fdt_blob);
  • fdt相关, 类似于linux内核里面的dtb. 暂不分析

[plain] view plain copy

  1. for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  2. if ((*init_fnc_ptr)() != 0) {
  3. hang ();
  4. }
  5. }
  • 依次调用init_sequence里面的函数, 如果某个函数执行失败, 即返回值不为0, 就会hang
  • 具体有哪些函数, 见下文.

[plain] view plain copy

  1. #ifdef CONFIG_OF_CONTROL
  2. /* For now, put this check after the console is ready */
  3. if (fdtdec_prepare_fdt()) {
  4. panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
  5. "doc/README.fdt-control");
  6. }
  7. #endif
  • fdt相关, 暂不分析

[plain] view plain copy

  1. #if defined(CONFIG_SYS_MEM_TOP_HIDE)
  2. /*
  3. * Subtract specified amount of memory to hide so that it won't
  4. * get "touched" at all by U-Boot. By fixing up gd->ram_size
  5. * the Linux kernel should now get passed the now "corrected"
  6. * memory size and won't touch it either. This should work
  7. * for arch/ppc and arch/powerpc. Only Linux board ports in
  8. * arch/powerpc with bootwrapper support, that recalculate the
  9. * memory size from the SDRAM controller setup will have to
  10. * get fixed.
  11. */
  12. gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
  13. #endif
  • 隐藏一块MEM, uboot不会touch它. 同样也可以做到让linux kernel不touch它.
  • 一般ppc或者powerpc体系架构才会用到这个

[plain] view plain copy

  1. addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
  2. #ifdef CONFIG_LOGBUFFER
  3. #ifndef CONFIG_ALT_LB_ADDR
  4. /* reserve kernel log buffer */
  5. addr -= (LOGBUFF_RESERVE);
  6. debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
  7. addr);
  8. #endif
  9. #endif
  10. #ifdef CONFIG_PRAM
  11. /*
  12. * reserve protected RAM
  13. */
  14. reg = getenv_ulong("pram", 10, CONFIG_PRAM);
  15. addr -= (reg << 10);      /* size is in kB */
  16. debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
  17. #endif /* CONFIG_PRAM */
  18. #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
  19. /* reserve TLB table */
  20. gd->arch.tlb_size = 4096 * 4;
  21. addr -= gd->arch.tlb_size;
  22. /* round down to next 64 kB limit */
  23. addr &= ~(0x10000 - 1);
  24. gd->arch.tlb_addr = addr;
  25. debug("TLB table from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size);
  26. #endif
  27. /* round down to next 4 kB limit */
  28. addr &= ~(4096 - 1);
  29. debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
  30. #ifdef CONFIG_LCD
  31. #ifdef CONFIG_FB_ADDR
  32. gd->fb_base = CONFIG_FB_ADDR;
  33. #else
  34. /* reserve memory for LCD display (always full pages) */
  35. addr = lcd_setmem(addr);
  36. gd->fb_base = addr;
  37. #endif /* CONFIG_FB_ADDR */
  38. #endif /* CONFIG_LCD */
  39. /*
  40. * reserve memory for U-Boot code, data & bss
  41. * round down to next 4 kB limit
  42. */
  43. addr -= gd->mon_len;
  44. addr &= ~(4096 - 1);
  45. debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
  46. #ifndef CONFIG_SPL_BUILD
  47. /*
  48. * reserve memory for malloc() arena
  49. */
  50. addr_sp = addr - TOTAL_MALLOC_LEN;
  51. debug("Reserving %dk for malloc() at: %08lx\n",
  52. TOTAL_MALLOC_LEN >> 10, addr_sp);
  53. /*
  54. * (permanently) allocate a Board Info struct
  55. * and a permanent copy of the "global" data
  56. */
  57. addr_sp -= sizeof (bd_t);
  58. bd = (bd_t *) addr_sp;
  59. gd->bd = bd;
  60. debug("Reserving %zu Bytes for Board Info at: %08lx\n",
  61. sizeof (bd_t), addr_sp);
  62. #ifdef CONFIG_MACH_TYPE
  63. gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
  64. #endif
  65. addr_sp -= sizeof (gd_t);
  66. id = (gd_t *) addr_sp;
  67. debug("Reserving %zu Bytes for Global Data at: %08lx\n",
  68. sizeof (gd_t), addr_sp);
  69. #if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)
  70. /*
  71. * If the device tree is sitting immediate above our image then we
  72. * must relocate it. If it is embedded in the data section, then it
  73. * will be relocated with other data.
  74. */
  75. if (gd->fdt_blob) {
  76. fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
  77. addr_sp -= fdt_size;
  78. new_fdt = (void *)addr_sp;
  79. debug("Reserving %zu Bytes for FDT at: %08lx\n",
  80. fdt_size, addr_sp);
  81. }
  82. #endif
  83. /* setup stackpointer for exeptions */
  84. gd->irq_sp = addr_sp;
  85. #ifdef CONFIG_USE_IRQ
  86. addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
  87. debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
  88. CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
  89. #endif
  90. /* leave 3 words for abort-stack    */
  91. addr_sp -= 12;
  92. /* 8-byte alignment for ABI compliance */
  93. addr_sp &= ~0x07;
  94. #else
  95. addr_sp += 128; /* leave 32 words for abort-stack   */
  96. gd->irq_sp = addr_sp;
  97. #endif
  98. interrupt_init();
  99. debug("New Stack Pointer is: %08lx\n", addr_sp);
  100. #ifdef CONFIG_POST
  101. post_bootmode_init();
  102. post_run(NULL, POST_ROM | post_bootmode_get(0));
  103. #endif
  104. gd->bd->bi_baudrate = gd->baudrate;
  105. /* Ram ist board specific, so move it to board code ... */
  106. dram_init_banksize();
  107. display_dram_config();  /* and display it */
  108. gd->relocaddr = addr;
  109. gd->start_addr_sp = addr_sp;
  110. gd->reloc_off = addr - _TEXT_BASE;
  111. debug("relocation Offset is: %08lx\n", gd->reloc_off);
  112. if (new_fdt) {
  113. memcpy(new_fdt, gd->fdt_blob, fdt_size);
  114. gd->fdt_blob = new_fdt;
  115. }
  116. memcpy(id, (void *)gd, sizeof(gd_t));
  • 这一段主要是在做内存分配动作.

    • addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; 从RAM的顶部地址开始
    • LOGBUFF_RESERVE : Reserving %dk for kernel logbuffer
    • pram : Reserving %ldk for protected RAM
    • tlb_addr: reserve TLB table(16K), 然后会把地址对齐到64K处.
    • addr &= ~(4096 - 1): 做完上面的内存分配动作之后, 在保留4KB的空间. 干嘛用还不清楚.
    • relocaddr: 在接来下的RAM就是U-boot可以用的了 : Top of RAM usable for U-Boot
    • LCD
      • 如果用户定义了CONFIG_FB_ADDR, 那这里就不为LCD保留显存了
      • 如果用户定义了CONFIG_LCD, 又没有定义CONFIG_FB_ADDR, 则为LCD保留一块显存
    • Code, data, bss : reserve memory for U-Boot code, data & bss
    • malloc : reserve memory for malloc() arena, 突然想起了堆和栈的区别, 网上查了一下, 用户自己分配和释放的属于堆区. 貌似这个地方就是堆区哦.
    • bd : Board Info struct
    • gd: Global Data
    • fdt
    • irq_sp : IRQ & FIQ 栈指针. 向下生长
    • start_addr_sp : 系统栈指针. 主要是在C函数调用过程中, 函数参数, 返回地址的入栈出栈操作.
    • reloc_off : gd->reloc_off = addr - _TEXT_BASE;
      • relocate offset, 这里的意思暂时没弄懂
  • gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ 这个赋值动作, 记得老版本的uboot是在BOARDDIR下面做的.
  • dram_init_banksize : 需要在BOARDDIR下面实现, 告诉系统有几块RAM, 每一块的大小是多少.

init_sequence

[plain] view plain copy

  1. init_fnc_t *init_sequence[] = {
  2. arch_cpu_init,      /* basic arch cpu dependent setup */
  3. mark_bootstage,
  4. #ifdef CONFIG_OF_CONTROL
  5. fdtdec_check_fdt,
  6. #endif
  7. #if defined(CONFIG_BOARD_EARLY_INIT_F)
  8. board_early_init_f,
  9. #endif
  10. timer_init,     /* initialize timer */
  11. #ifdef CONFIG_BOARD_POSTCLK_INIT
  12. board_postclk_init,
  13. #endif
  14. #ifdef CONFIG_FSL_ESDHC
  15. get_clocks,
  16. #endif
  17. env_init,       /* initialize environment */
  18. init_baudrate,      /* initialze baudrate settings */
  19. serial_init,        /* serial communications setup */
  20. console_init_f,     /* stage 1 init of console */
  21. display_banner,     /* say that we are here */
  22. #if defined(CONFIG_DISPLAY_CPUINFO)
  23. print_cpuinfo,      /* display cpu info (and speed) */
  24. #endif
  25. #if defined(CONFIG_DISPLAY_BOARDINFO)
  26. checkboard,     /* display board info */
  27. #endif
  28. #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
  29. init_func_i2c,
  30. #endif
  31. dram_init,      /* configure available RAM banks */
  32. NULL,
  33. };
  • arch_cpu_init

    • 一般厂商会实现, 根据实际需要初始化CPU相关的一些东西
    • 如果没有其他实现, 就会用board.c中的weak实现.
  • mark_bootstage
    • Record the board_init_f() bootstage (after arch_cpu_init())
  • fdtdec_check_fdt : fdt相关, 暂不分析
  • board_early_init_f
    • 一般在BOARDDIR下面实现, 初始化必要的硬件
  • timer_init
    • 时钟初始化
  • board_postclk_init
  • get_clocks
  • env_init
    • 以nandflash为例, 此时还没有对nandflash进行初始化, 所以这个函数的实现不会从nand中去读取实际保存的变量. 只是简单标记env_valid为1
    • env_common.c中的env_relocate() will do the real validation
  • init_baudrate
    • 初始化gd->baudrate
    • gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
  • serial_init
    • uboot的serial子系统相关
  • console_init_f
    • stage 1 init of console
    • Called before relocation - use serial functions
  • print_cpuinfo
    • display cpu info (and speed)
  • checkboard
    • display board info
  • dram_init
    • 初始化gd->ram_size
    • 接下来的code会做内存分配, 需要用到这个值. 注意, 如果有多块DRAM, 起始地址不一样, 那这里的ram_size应该只是其中1块的大小.
      • 比如BANK1: 0x20000000 64M;  BANK2: 0x40000000 64M; 那这个ram_size应该是64M, 而不是128M. 具体原因, 可以看上文中的内存分配动作

board_init_r

[plain] view plain copy

  1. gd->flags |= GD_FLG_RELOC;   /* tell others: relocation done */
  • 做过relocate之后, 才调用的board_init_r

[plain] view plain copy

  1. board_init();   /* Setup chipselects */
  • board_init需要在BOARDDIR中实现.

[plain] view plain copy

  1. serial_initialize();
  • uboot的serial子系统相关. 完成实际的串口初始化工作

[plain] view plain copy

  1. /* The Malloc area is immediately below the monitor copy in DRAM */
  2. malloc_start = dest_addr - TOTAL_MALLOC_LEN;
  3. mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
  • dest_addr是_main的汇编代码传递进来的参数 GD_RELOCADDR.
  • GD_RELOCADDR是在board_init_f阶段被赋值的.

[plain] view plain copy

  1. power_init_board();
  • 可以选择性的在BOARDDIR下实现.
  • 如果没有实现, 则会使用board.c中的weak实现

[plain] view plain copy

  1. nand_init();
  • nandflash初始化, 会调用mtd/nand/nand.c中的nand_init

[plain] view plain copy

  1. mmc_initialize
  • sd卡初始化, 会调用drivers/mmc/mmc.c中的mmc_initialize

[plain] view plain copy

  1. env_relocate
  • board_init_f->init_sequence中的env_init其实没有做什么实质性动作, 因为当时nand还没有初始化
  • 所以这里的env_relocate会调用common/env_common.c中的env_relocate, 继而开始做实质性的env初始动作. 也就是从nandflash中读取我们自己设置的环境变量

[plain] view plain copy

  1. stdio_init
  • 调用common/stdio.c中的stdio_init, 做一些IO相关的初始化

    • lcd, video, keyboard, nc, jtag等等

[plain] view plain copy

  1. jumptable_init
  • 调用include/_exports.h中定义的各种通用的操作函数

    • get_version, getc, malloc, udelay等等

[plain] view plain copy

  1. console_init_r();   /* fully init console as a device */
  • 控制台最终初始化

[plain] view plain copy

  1. #ifdef CONFIG_BOARD_LATE_INIT
  2. board_late_init();
  3. #endif
  • 可以选择性的在BOARDDIR中定义board_late_init, 做一些最后的初始化动作

[plain] view plain copy

  1. #if defined(CONFIG_CMD_NET)
  2. puts("Net:   ");
  3. eth_initialize(gd->bd);
  4. #if defined(CONFIG_RESET_PHY_R)
  5. debug("Reset Ethernet PHY\n");
  6. reset_phy();
  7. #endif
  8. #endif
  • 在BOARDDIR中实现eth_initialize, 初始化网络
  • 在BOARDDIR中实现reset_phy, 复位phy.

[plain] view plain copy

  1. for (;;) {
  2. main_loop();
  3. }
  • 进入common/main.c中的main_loop

    • 如果没有按下空格键, uboot会执行bootcmd中的命令
    • 如果按下空格键, 则会进入控制台, 与用户交互, 执行命令

总结

stage1 vs stage2

stage1也就是SPL, stage2也就是本篇所指的u-boot.bin, 主要有以下不同点

  • u-boot.bin在start.S中会对异常中断进行响应
  • u-boot.bin中的board_init_f实现与SPL阶段不一样
  • u-boot.bin中的board_init_r实现与SPL阶段不一样

global_data

u-boot.bin会对全局数据gd先清理, 然后在重新初始化.

需要实现的函数

  • dram_init_banksize:  BOARDDIR下实现

    • 告诉系统有几块RAM, 每一块的大小是多少.
  • board_early_init_f : BOARDDIR下实现
  • board_init : BOARDDIR下实现
  • eth_initialize : BOARDDIR下实现

u-boot之u-boot.bin的生成相关推荐

  1. ARM(IMX6U)裸机之I.MX6ULL启动头文件详解(内部BOOT ROM、IVT + Boot data + DCD + led.bin)

    参考:Linux之ARM(IMX6U)裸机之I.MX6ULL镜像烧写以及启动头文件的详解 作者:一只青木呀 发布时间: 2020-08-09 17:10:00 网址:https://blog.csdn ...

  2. Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据

    一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 问题二 ...

  3. idea swagger生成接口文档_Spring Boot(九)Swagger2自动生成接口文档和Mock模拟数据...

    一.简介 在当下这个前后端分离的技术趋势下,前端工程师过度依赖后端工程师的接口和数据,给开发带来了两大问题: 问题一.后端接口查看难:要怎么调用?参数怎么传递?有几个参数?参数都代表什么含义? 问题二 ...

  4. Spring Boot JPA实体类idea自动生成 其一-https://www.jianshu.com/p/44bb7e25f5c7

    Spring Boot JPA实体类idea自动生成 其一 marioplus12 2018.09.17 19:29* 字数 138 阅读 762评论 0喜欢 2 view -> Tool Wi ...

  5. 解决spring boot logging在两个目录生成日志文件且max-history不生效

    解决spring boot logging在两个目录生成日志文件且max-history不生效 文章目录 解决spring boot logging在两个目录生成日志文件且max-history不生效 ...

  6. spring boot示例_Spring Boot REST示例

    spring boot示例 Spring Boot is an awesome module from Spring Framework. Once you are used to it, then ...

  7. Pandora Boot和spring Boot

    在阿里集团内部,几乎所有的应用都用到了各式各样的中间件,比如HSF.TDDL.Diamond等等.本身中间件之间可能就有版本依赖的问题,比如你的应用HSF和Diamond分别依赖了同名jar包的不同版 ...

  8. Spring Boot 入门——Spring Boot 简介||微服务简介

    Spring Boot 入门 1.Spring Boot 简介 Spring Boot来简化Spring应用开发,约定大于配置, 去繁从简,just run就能创建一个独立的,产品级别的应用 简化Sp ...

  9. spring boot注释_Spring Boot中的@SpringBootConfiguration注释

    spring boot注释 Spring Boot中的 @SpringBootConfiguration注释是一个类级别的注释,它指示此类提供了应用程序配置. 通常,具有main()方法的类最适合此注 ...

  10. spring boot程序_Spring Boot –现代Java应用程序的基础

    spring boot程序 Spring Boot是Spring.io中一个相对较新的项目. 其目的是简化创建新的基于Spring Framework的项目,并通过应用一些约定来统一其配置. 这种关于 ...

最新文章

  1. PAT甲级题目翻译+答案 AcWing(并查集)
  2. 《Cloudera hadoop大数据平台实战指南》此书2019年1月已上市
  3. bootstraptable 加载完成_bootstrap table onLoadSuccess加载服务端数据成功事件
  4. gesturedetector.java_android使用gesturedetector手势识别示例分享
  5. uva 11536——Smallest Sub-Array
  6. const修饰指针和引用的用法【转贴】
  7. 基础知识回顾——通用序列操作
  8. 值得收藏的图片网站,设计素材不愁,还能承包你一年壁纸
  9. Python接口自动化之Token详解及应用
  10. PAT 1013 数素数
  11. 毕设题目:Matlab智能算法VRP(车辆路径规划)
  12. nupkg 本地安装_使用Nuget安装脱机软件包nupkg
  13. CxImage功能强大的图形处理程序
  14. 系统集成项目管理工程师考试大纲和复习知识点
  15. html的取消和选中,checkbox 选中和取消切换问题
  16. 【论文笔记】ASNet:基于生成对抗网络(GAN)的无监督单模和多模配准网络(范敬凡老师)
  17. java图片打包下载_java 批量下载图片,批量打包文件并下载
  18. 威联通[vNAS內置虚拟机]体验评测 让企业实现无限可能
  19. 这33篇区块链必读论文, 读过5篇以上的竟不到1%
  20. 常用电平标准——LVTTL、LVCMOS、LVDS等

热门文章

  1. listview选中高亮
  2. 平方根升余弦滚降滤波器matlab函数,平方根升余弦滚降数字滤波器的设计和实现.pdf...
  3. MySQL数据库---数据库管理
  4. 转-python面试题目集锦(100道部分附答案)
  5. 微型计算机原理王道生,微型计算机电路基础大纲2010年
  6. C语言入栈算法,栈的入栈、出栈、获取栈顶的c语言算法
  7. slf4j没有在linux中生成日志,logback+SLF4J 没打印日志
  8. mysql decimal被四舍五入_MySQL之ROUND函数四舍五入的陷阱
  9. 一个适用于visual studio 2005的一个js日历控件--zhuan
  10. 转载 openlayers 3.0 教程