当前位置:   article > 正文

U-BOOT移植过程详解: u-boot.bin_uboot binman

uboot binman
    

        U-BOOT移植过程详解: u-boot.bin             

分类:             U-BOOT移植                   540人阅读     评论(0)     收藏     举报    

申明

  本着学习交流的原则, 将个人移植u-boot的过程做一个记录. 文章参考了csdn blog里面的很多内容, 有的已经记不得出处了, 只好把当时的摘要直接贴出来. 如果冒犯, 还请见谅. 如有侵权, 请与我邮件联系. 谢谢!


u-boot.bin

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

u-boot.bin的文件组成

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

all依赖于 $(ALL-y) 和 $(SUBDIR_EXAMPLES), 这里我只关注ALL-y, 如下:
  1. # Always append ALL so that arch config.mk's can add custom ones  
  2. <span style="color: rgb(255, 0, 0);">ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map</span>  
  3.   
  4. ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin  
  5. ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin  
  6. ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin  
  7. ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.img  
  8. ALL-$(CONFIG_TPL) += $(obj)tpl/u-boot-tpl.bin  
  9. ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin  
  10. ifneq ($(CONFIG_SPL_TARGET),)  
  11. ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))  
  12. endif  
  13.   
  14. # enable combined SPL/u-boot/dtb rules for tegra  
  15. ifneq ($(CONFIG_TEGRA),)  
  16. ifeq ($(CONFIG_OF_SEPARATE),y)  
  17. ALL-y += $(obj)u-boot-dtb-tegra.bin  
  18. else  
  19. ALL-y += $(obj)u-boot-nodtb-tegra.bin  
  20. endif  
  21. endif  
# Always append ALL so that arch config.mk's can add custom ones
<span style="color:#ff00;">ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map</span>

ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin
ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin
ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.img
ALL-$(CONFIG_TPL) += $(obj)tpl/u-boot-tpl.bin
ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin
ifneq ($(CONFIG_SPL_TARGET),)
ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))
endif

# enable combined SPL/u-boot/dtb rules for tegra
ifneq ($(CONFIG_TEGRA),)
ifeq ($(CONFIG_OF_SEPARATE),y)
ALL-y += $(obj)u-boot-dtb-tegra.bin
else
ALL-y += $(obj)u-boot-nodtb-tegra.bin
endif
endif

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

先忽略System.map, 在看下面一段
  1. $(obj)u-boot.srec:  $(obj)u-boot  
  2.         $(OBJCOPY) -O srec $< $@  
  3.   
  4. $(obj)u-boot.bin:   $(obj)u-boot  
  5.         $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@  
  6.         $(BOARD_SIZE_CHECK)  
$(obj)u-boot.srec:	$(obj)u-boot
		$(OBJCOPY) -O srec $< $@

$(obj)u-boot.bin:	$(obj)u-boot
		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
		$(BOARD_SIZE_CHECK)
它们都依赖于u-boot

那么在看看u-boot的依赖关系
  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.   
  14. $(obj)u-boot:   depend \  
  15.         $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds  
  16.         $(GEN_UBOOT)  
ifeq ($(CONFIG_SANDBOX),y)
GEN_UBOOT = \
		cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
			-Wl,--start-group $(__LIBS) -Wl,--end-group \
			$(PLATFORM_LIBS) -Wl,-Map -Wl,u-boot.map -o u-boot
else
GEN_UBOOT = \
		cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) \
			$(__OBJS) \
			--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
			-Map u-boot.map -o u-boot
endif

$(obj)u-boot:	depend \
		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
		$(GEN_UBOOT)
  • depend: 参考附录中的depend
  • $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) : 各个子目录
  • $(LDSCRIPT) : 如下, 默认就是在arch/arm/cpu/下面的u-boot.lds
    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.   
    5.   
    6. LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))  
    7.   
    8.   
    9. ifndef LDSCRIPT  
    10. <span style="white-space: pre;">    </span>#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug  
    11. <span style="white-space: pre;">    </span>ifdef CONFIG_SYS_LDSCRIPT  
    12. <span style="white-space: pre;">        </span># need to strip off double quotes  
    13. <span style="white-space: pre;">        </span>LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))  
    14. <span style="white-space: pre;">    </span>endif  
    15. endif  
    16.   
    17.   
    18. # If there is no specified link script, we look in a number of places for it  
    19. ifndef LDSCRIPT  
    20. <span style="white-space: pre;">    </span>ifeq ($(CONFIG_NAND_U_BOOT),y)  
    21. <span style="white-space: pre;">        </span>LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds  
    22. <span style="white-space: pre;">        </span>ifeq ($(wildcard $(LDSCRIPT)),)  
    23. <span style="white-space: pre;">            </span>LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds  
    24. <span style="white-space: pre;">        </span>endif  
    25. <span style="white-space: pre;">    </span>endif  
    26. <span style="white-space: pre;">    </span>ifeq ($(wildcard $(LDSCRIPT)),)  
    27. <span style="white-space: pre;">        </span>LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds  
    28. <span style="white-space: pre;">    </span>endif  
    29. <span style="white-space: pre;">    </span>ifeq ($(wildcard $(LDSCRIPT)),)  
    30. <span style="white-space: pre;">        </span>LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds  
    31. <span style="white-space: pre;">    </span>endif  
    32. <span style="white-space: pre;">    </span>ifeq ($(wildcard $(LDSCRIPT)),)  
    33. <span style="white-space: pre;">        </span>LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds  
    34. <span style="white-space: pre;">        </span># We don't expect a Makefile here  
    35. <span style="white-space: pre;">        </span>LDSCRIPT_MAKEFILE_DIR =  
    36. <span style="white-space: pre;">    </span>endif  
    37. <span style="white-space: pre;">    </span>ifeq ($(wildcard $(LDSCRIPT)),)  
    38. $(error could not find linker script)  
    39. <span style="white-space: pre;">    </span>endif  
    40. endif  
    # If board code explicitly specified LDSCRIPT or CONFIG_SYS_LDSCRIPT, use
    # that (or fail if absent).  Otherwise, search for a linker script in a
    # standard location.
    
    
    LDSCRIPT_MAKEFILE_DIR = $(dir $(LDSCRIPT))
    
    
    ifndef LDSCRIPT
    <span style="white-space: pre;">	</span>#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
    <span style="white-space: pre;">	</span>ifdef CONFIG_SYS_LDSCRIPT
    <span style="white-space: pre;">		</span># need to strip off double quotes
    <span style="white-space: pre;">		</span>LDSCRIPT := $(subst ",,$(CONFIG_SYS_LDSCRIPT))
    <span style="white-space: pre;">	</span>endif
    endif
    
    
    # If there is no specified link script, we look in a number of places for it
    ifndef LDSCRIPT
    <span style="white-space: pre;">	</span>ifeq ($(CONFIG_NAND_U_BOOT),y)
    <span style="white-space: pre;">		</span>LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
    <span style="white-space: pre;">		</span>ifeq ($(wildcard $(LDSCRIPT)),)
    <span style="white-space: pre;">			</span>LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
    <span style="white-space: pre;">		</span>endif
    <span style="white-space: pre;">	</span>endif
    <span style="white-space: pre;">	</span>ifeq ($(wildcard $(LDSCRIPT)),)
    <span style="white-space: pre;">		</span>LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
    <span style="white-space: pre;">	</span>endif
    <span style="white-space: pre;">	</span>ifeq ($(wildcard $(LDSCRIPT)),)
    <span style="white-space: pre;">		</span>LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds
    <span style="white-space: pre;">	</span>endif
    <span style="white-space: pre;">	</span>ifeq ($(wildcard $(LDSCRIPT)),)
    <span style="white-space: pre;">		</span>LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
    <span style="white-space: pre;">		</span># We don't expect a Makefile here
    <span style="white-space: pre;">		</span>LDSCRIPT_MAKEFILE_DIR =
    <span style="white-space: pre;">	</span>endif
    <span style="white-space: pre;">	</span>ifeq ($(wildcard $(LDSCRIPT)),)
    $(error could not find linker script)
    <span style="white-space: pre;">	</span>endif
    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
  1. ENTRY(_main)  
  2.   
  3. /*  
  4.  * Set up initial C runtime environment and call board_init_f(0).  
  5.  */  
  6.   
  7. #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)  
  8.     ldr sp, =(CONFIG_SPL_STACK)  
  9. #else  
  10.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  
  11. #endif  
  12.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
  13.     sub sp, #GD_SIZE    /* allocate one GD above SP */  
  14.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
  15.     mov r9, sp      /* GD is above SP */  
  16.     mov r0, #0  
  17.     bl  board_init_f  
ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	sp, =(CONFIG_SPL_STACK)
#else
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	sub	sp, #GD_SIZE	/* allocate one GD above SP */
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	mov	r9, sp		/* GD is above SP */
	mov	r0, #0
	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的实现函数不是同一个.
  1. #if ! defined(CONFIG_SPL_BUILD)  
  2.   
  3. /*  
  4.  * Set up intermediate environment (new sp and gd) and call  
  5.  * relocate_code(addr_moni). Trick here is that we'll return  
  6.  * 'here' but relocated.  
  7.  */  
  8.   
  9.     ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */  
  10.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
  11.     ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */  
  12.     sub r9, r9, #GD_SIZE        /* new GD is below bd */  
  13.   
  14.     adr lr, here  
  15.     ldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off */  
  16.     add lr, lr, r0  
  17.     ldr r0, [r9, #GD_RELOCADDR]     /* r0 = gd->relocaddr */  
  18.     b   relocate_code  
  19. here:  
  20.   
  21. /* Set up final (full) environment */  
  22.   
  23.     bl  c_runtime_cpu_setup /* we still call old routine here */  
  24.   
  25.     ldr r0, =__bss_start    /* this is auto-relocated! */  
  26.     ldr r1, =__bss_end      /* this is auto-relocated! */  
  27.   
  28.     mov r2, #0x00000000     /* prepare zero to clear BSS */  
  29.   
  30. clbss_l:cmp r0, r1          /* while not at end of BSS */  
  31.     strlo   r2, [r0]        /* clear 32-bit BSS word */  
  32.     addlo   r0, r0, #4      /* move to next */  
  33.     blo clbss_l  
  34.   
  35.     bl coloured_LED_init  
  36.     bl red_led_on  
  37.   
  38.     /* call board_init_r(gd_t *id, ulong dest_addr) */  
  39.     mov     r0, r9                  /* gd_t */  
  40.     ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */  
  41.     /* call board_init_r */  
  42.     ldr pc, =board_init_r   /* this is auto-relocated! */  
  43.   
  44.     /* we should not return here. */  
  45.   
  46. #endif  
#if ! defined(CONFIG_SPL_BUILD)

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */

	ldr	sp, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */
	bic	sp, sp, #7	/* 8-byte alignment for ABI compliance */
	ldr	r9, [r9, #GD_BD]		/* r9 = gd->bd */
	sub	r9, r9, #GD_SIZE		/* new GD is below bd */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code
here:

/* Set up final (full) environment */

	bl	c_runtime_cpu_setup	/* we still call old routine here */

	ldr	r0, =__bss_start	/* this is auto-relocated! */
	ldr	r1, =__bss_end		/* this is auto-relocated! */

	mov	r2, #0x00000000		/* prepare zero to clear BSS */

clbss_l:cmp	r0, r1			/* while not at end of BSS */
	strlo	r2, [r0]		/* clear 32-bit BSS word */
	addlo	r0, r0, #4		/* move to next */
	blo	clbss_l

	bl coloured_LED_init
	bl red_led_on

	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
	ldr	pc, =board_init_r	/* this is auto-relocated! */

	/* we should not return here. */

#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
  1. memset((void *)gd, 0, sizeof(gd_t));  
memset((void *)gd, 0, sizeof(gd_t));
  • gd的定义在board.c里面, 有一行: DECLARE_GLOBAL_DATA_PTR;
  • memset清零, 说明从这里开始, 重新对gd进行初始化.
  • 那我们在前面的代码很看到很多对gd的操作啊, 有什么用呢? 主要是在一些汇编代码里面引用了gd的相关变量. 哪些变量可能被引用到呢? 在这里 lib/asm-offsets.c
  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);  
#ifdef CONFIG_OF_EMBED
	/* Get a pointer to the FDT */
	gd->fdt_blob = _binary_dt_dtb_start;
#elif defined CONFIG_OF_SEPARATE
	/* FDT is at end of image */
	gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
#endif
	/* Allow the early environment to override the fdt address */
	gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
						(uintptr_t)gd->fdt_blob);
  • fdt相关, 类似于linux内核里面的dtb. 暂不分析
  1. for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {  
  2.     if ((*init_fnc_ptr)() != 0) {  
  3.         hang ();  
  4.     }  
  5. }  
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
  • 依次调用init_sequence里面的函数, 如果某个函数执行失败, 即返回值不为0, 就会hang
  • 具体有哪些函数, 见下文.
  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  
#ifdef CONFIG_OF_CONTROL
	/* For now, put this check after the console is ready */
	if (fdtdec_prepare_fdt()) {
		panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
			"doc/README.fdt-control");
	}
#endif
  • fdt相关, 暂不分析
  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  
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
	/*
	 * Subtract specified amount of memory to hide so that it won't
	 * get "touched" at all by U-Boot. By fixing up gd->ram_size
	 * the Linux kernel should now get passed the now "corrected"
	 * memory size and won't touch it either. This should work
	 * for arch/ppc and arch/powerpc. Only Linux board ports in
	 * arch/powerpc with bootwrapper support, that recalculate the
	 * memory size from the SDRAM controller setup will have to
	 * get fixed.
	 */
	gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif
  • 隐藏一块MEM, uboot不会touch它. 同样也可以做到让linux kernel不touch它.
  • 一般ppc或者powerpc体系架构才会用到这个
  1.     addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  
  2.   
  3. #ifdef CONFIG_LOGBUFFER  
  4. #ifndef CONFIG_ALT_LB_ADDR  
  5.     /* reserve kernel log buffer */  
  6.     addr -= (LOGBUFF_RESERVE);  
  7.     debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,  
  8.         addr);  
  9. #endif  
  10. #endif  
  11.   
  12. #ifdef CONFIG_PRAM  
  13.     /*  
  14.      * reserve protected RAM  
  15.      */  
  16.     reg = getenv_ulong("pram", 10, CONFIG_PRAM);  
  17.     addr -= (reg << 10);      /* size is in kB */  
  18.     debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);  
  19. #endif /* CONFIG_PRAM */  
  20.   
  21. #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))  
  22.     /* reserve TLB table */  
  23.     gd->arch.tlb_size = 4096 * 4;  
  24.     addr -= gd->arch.tlb_size;  
  25.   
  26.     /* round down to next 64 kB limit */  
  27.     addr &= ~(0x10000 - 1);  
  28.   
  29.     gd->arch.tlb_addr = addr;  
  30.     debug("TLB table from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size);  
  31. #endif  
  32.   
  33.     /* round down to next 4 kB limit */  
  34.     addr &= ~(4096 - 1);  
  35.     debug("Top of RAM usable for U-Boot at: %08lx\n", addr);  
  36.   
  37. #ifdef CONFIG_LCD  
  38. #ifdef CONFIG_FB_ADDR  
  39.     gd->fb_base = CONFIG_FB_ADDR;  
  40. #else  
  41.     /* reserve memory for LCD display (always full pages) */  
  42.     addr = lcd_setmem(addr);  
  43.     gd->fb_base = addr;  
  44. #endif /* CONFIG_FB_ADDR */  
  45. #endif /* CONFIG_LCD */  
  46.   
  47.     /*  
  48.      * reserve memory for U-Boot code, data & bss  
  49.      * round down to next 4 kB limit  
  50.      */  
  51.     addr -= gd->mon_len;  
  52.     addr &= ~(4096 - 1);  
  53.   
  54.     debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);  
  55.   
  56. #ifndef CONFIG_SPL_BUILD  
  57.     /*  
  58.      * reserve memory for malloc() arena  
  59.      */  
  60.     addr_sp = addr - TOTAL_MALLOC_LEN;  
  61.     debug("Reserving %dk for malloc() at: %08lx\n",  
  62.             TOTAL_MALLOC_LEN >> 10, addr_sp);  
  63.     /*  
  64.      * (permanently) allocate a Board Info struct  
  65.      * and a permanent copy of the "global" data  
  66.      */  
  67.     addr_sp -= sizeof (bd_t);  
  68.     bd = (bd_t *) addr_sp;  
  69.     gd->bd = bd;  
  70.     debug("Reserving %zu Bytes for Board Info at: %08lx\n",  
  71.             sizeof (bd_t), addr_sp);  
  72.   
  73. #ifdef CONFIG_MACH_TYPE  
  74.     gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */  
  75. #endif  
  76.   
  77.     addr_sp -= sizeof (gd_t);  
  78.     id = (gd_t *) addr_sp;  
  79.     debug("Reserving %zu Bytes for Global Data at: %08lx\n",  
  80.             sizeof (gd_t), addr_sp);  
  81.   
  82. #if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)  
  83.     /*  
  84.      * If the device tree is sitting immediate above our image then we  
  85.      * must relocate it. If it is embedded in the data section, then it  
  86.      * will be relocated with other data.  
  87.      */  
  88.     if (gd->fdt_blob) {  
  89.         fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);  
  90.   
  91.         addr_sp -= fdt_size;  
  92.         new_fdt = (void *)addr_sp;  
  93.         debug("Reserving %zu Bytes for FDT at: %08lx\n",  
  94.               fdt_size, addr_sp);  
  95.     }  
  96. #endif  
  97.   
  98.     /* setup stackpointer for exeptions */  
  99.     gd->irq_sp = addr_sp;  
  100. #ifdef CONFIG_USE_IRQ  
  101.     addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);  
  102.     debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",  
  103.         CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);  
  104. #endif  
  105.     /* leave 3 words for abort-stack    */  
  106.     addr_sp -= 12;  
  107.   
  108.     /* 8-byte alignment for ABI compliance */  
  109.     addr_sp &= ~0x07;  
  110. #else  
  111.     addr_sp += 128; /* leave 32 words for abort-stack   */  
  112.     gd->irq_sp = addr_sp;  
  113. #endif  
  114.     interrupt_init();  
  115.   
  116.     debug("New Stack Pointer is: %08lx\n", addr_sp);  
  117.   
  118. #ifdef CONFIG_POST  
  119.     post_bootmode_init();  
  120.     post_run(NULL, POST_ROM | post_bootmode_get(0));  
  121. #endif  
  122.   
  123.     gd->bd->bi_baudrate = gd->baudrate;  
  124.     /* Ram ist board specific, so move it to board code ... */  
  125.     dram_init_banksize();  
  126.     display_dram_config();  /* and display it */  
  127.   
  128.     gd->relocaddr = addr;  
  129.     gd->start_addr_sp = addr_sp;  
  130.     gd->reloc_off = addr - _TEXT_BASE;  
  131.     debug("relocation Offset is: %08lx\n", gd->reloc_off);  
  132.     if (new_fdt) {  
  133.         memcpy(new_fdt, gd->fdt_blob, fdt_size);  
  134.         gd->fdt_blob = new_fdt;  
  135.     }  
  136.     memcpy(id, (void *)gd, sizeof(gd_t));  
	addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;

#ifdef CONFIG_LOGBUFFER
#ifndef CONFIG_ALT_LB_ADDR
	/* reserve kernel log buffer */
	addr -= (LOGBUFF_RESERVE);
	debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
		addr);
#endif
#endif

#ifdef CONFIG_PRAM
	/*
	 * reserve protected RAM
	 */
	reg = getenv_ulong("pram", 10, CONFIG_PRAM);
	addr -= (reg << 10);		/* size is in kB */
	debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
	/* reserve TLB table */
	gd->arch.tlb_size = 4096 * 4;
	addr -= gd->arch.tlb_size;

	/* round down to next 64 kB limit */
	addr &= ~(0x10000 - 1);

	gd->arch.tlb_addr = addr;
	debug("TLB table from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size);
#endif

	/* round down to next 4 kB limit */
	addr &= ~(4096 - 1);
	debug("Top of RAM usable for U-Boot at: %08lx\n", addr);

#ifdef CONFIG_LCD
#ifdef CONFIG_FB_ADDR
	gd->fb_base = CONFIG_FB_ADDR;
#else
	/* reserve memory for LCD display (always full pages) */
	addr = lcd_setmem(addr);
	gd->fb_base = addr;
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */

	/*
	 * reserve memory for U-Boot code, data & bss
	 * round down to next 4 kB limit
	 */
	addr -= gd->mon_len;
	addr &= ~(4096 - 1);

	debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD
	/*
	 * reserve memory for malloc() arena
	 */
	addr_sp = addr - TOTAL_MALLOC_LEN;
	debug("Reserving %dk for malloc() at: %08lx\n",
			TOTAL_MALLOC_LEN >> 10, addr_sp);
	/*
	 * (permanently) allocate a Board Info struct
	 * and a permanent copy of the "global" data
	 */
	addr_sp -= sizeof (bd_t);
	bd = (bd_t *) addr_sp;
	gd->bd = bd;
	debug("Reserving %zu Bytes for Board Info at: %08lx\n",
			sizeof (bd_t), addr_sp);

#ifdef CONFIG_MACH_TYPE
	gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif

	addr_sp -= sizeof (gd_t);
	id = (gd_t *) addr_sp;
	debug("Reserving %zu Bytes for Global Data at: %08lx\n",
			sizeof (gd_t), addr_sp);

#if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)
	/*
	 * If the device tree is sitting immediate above our image then we
	 * must relocate it. If it is embedded in the data section, then it
	 * will be relocated with other data.
	 */
	if (gd->fdt_blob) {
		fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

		addr_sp -= fdt_size;
		new_fdt = (void *)addr_sp;
		debug("Reserving %zu Bytes for FDT at: %08lx\n",
		      fdt_size, addr_sp);
	}
#endif

	/* setup stackpointer for exeptions */
	gd->irq_sp = addr_sp;
#ifdef CONFIG_USE_IRQ
	addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
	debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
		CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
	/* leave 3 words for abort-stack    */
	addr_sp -= 12;

	/* 8-byte alignment for ABI compliance */
	addr_sp &= ~0x07;
#else
	addr_sp += 128;	/* leave 32 words for abort-stack   */
	gd->irq_sp = addr_sp;
#endif
	interrupt_init();

	debug("New Stack Pointer is: %08lx\n", addr_sp);

#ifdef CONFIG_POST
	post_bootmode_init();
	post_run(NULL, POST_ROM | post_bootmode_get(0));
#endif

	gd->bd->bi_baudrate = gd->baudrate;
	/* Ram ist board specific, so move it to board code ... */
	dram_init_banksize();
	display_dram_config();	/* and display it */

	gd->relocaddr = addr;
	gd->start_addr_sp = addr_sp;
	gd->reloc_off = addr - _TEXT_BASE;
	debug("relocation Offset is: %08lx\n", gd->reloc_off);
	if (new_fdt) {
		memcpy(new_fdt, gd->fdt_blob, fdt_size);
		gd->fdt_blob = new_fdt;
	}
	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
  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. };  
init_fnc_t *init_sequence[] = {
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mark_bootstage,
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
	timer_init,		/* initialize timer */
#ifdef CONFIG_BOARD_POSTCLK_INIT
	board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment */
	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */
	NULL,
};

  • 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
  1. gd->flags |= GD_FLG_RELOC;   /* tell others: relocation done */  
gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
  • 做过relocate之后, 才调用的board_init_r
  1. board_init();   /* Setup chipselects */  
board_init();	/* Setup chipselects */
  • board_init需要在BOARDDIR中实现.
  1. serial_initialize();  
serial_initialize();
  • uboot的serial子系统相关. 完成实际的串口初始化工作
  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);  
/* The Malloc area is immediately below the monitor copy in DRAM */
	malloc_start = dest_addr - TOTAL_MALLOC_LEN;
	mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
  • dest_addr是_main的汇编代码传递进来的参数 GD_RELOCADDR.
  • GD_RELOCADDR是在board_init_f阶段被赋值的.
  1. power_init_board();  
power_init_board();
  • 可以选择性的在BOARDDIR下实现.
  • 如果没有实现, 则会使用board.c中的weak实现
  1. nand_init();  
nand_init();
  • nandflash初始化, 会调用mtd/nand/nand.c中的nand_init
  1. mmc_initialize  
mmc_initialize
  • sd卡初始化, 会调用drivers/mmc/mmc.c中的mmc_initialize
  1. env_relocate  
env_relocate
  • board_init_f->init_sequence中的env_init其实没有做什么实质性动作, 因为当时nand还没有初始化
  • 所以这里的env_relocate会调用common/env_common.c中的env_relocate, 继而开始做实质性的env初始动作. 也就是从nandflash中读取我们自己设置的环境变量
  1. stdio_init  
stdio_init
  • 调用common/stdio.c中的stdio_init, 做一些IO相关的初始化
    • lcd, video, keyboard, nc, jtag等等
  1. jumptable_init  
jumptable_init
  • 调用include/_exports.h中定义的各种通用的操作函数
    • get_version, getc, malloc, udelay等等
  1. console_init_r();   /* fully init console as a device */  
console_init_r();	/* fully init console as a device */
  • 控制台最终初始化
  1. #ifdef CONFIG_BOARD_LATE_INIT  
  2.     board_late_init();  
  3. #endif  
#ifdef CONFIG_BOARD_LATE_INIT
	board_late_init();
#endif
  • 可以选择性的在BOARDDIR中定义board_late_init, 做一些最后的初始化动作
  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  
#if defined(CONFIG_CMD_NET)
	puts("Net:   ");
	eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
	debug("Reset Ethernet PHY\n");
	reset_phy();
#endif
#endif
  • 在BOARDDIR中实现eth_initialize, 初始化网络
  • 在BOARDDIR中实现reset_phy, 复位phy. 
  1. for (;;) {  
  2.     main_loop();  
  3. }  
	for (;;) {
		main_loop();
	}
  • 进入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下实现
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/822531
推荐阅读
相关标签
  

闽ICP备14008679号