1. uboot的配置分析
1).配置入口分析
首先分析配置:
从make mx6dl_sabresd_android_config可知配置项,搜索Makefile:
mx6solo_sabresd_android_config mx6dl_sabresd_config mx6dl_sabresd_mfg_config mx6dl_sabresd_android_config mx6q_sabresd_config mx6q_sabresd_android_config mx6q_sabresd_mfg_config mx6q_sabresd_iram_config : unconfig @[ -z "$(findstring iram_,$@)" ] || {echo "TEXT_BASE = 0x00907000" > $(obj)board/freescale/mx6q_sabresd/config.tmp ; echo "... with iram configuration" ; } @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 mx6q_sabresd freescale mx6
其中MKCONFIG就是mkconfig
展开后结果为:mkconfig mx6dl_sabresd_android arm arm_cortexa8 mx6q_sabresd freescale mx6
2). mkconfig
然后打开mkconfig查看:
APPEND=no # Default: Create new config file BOARD_NAME="" # Name to print in make output #循环查看参数并处理 while [ $# -gt 0 ] ; do case "$1" in --) shift ; break ;; -a) shift ; APPEND=yes ;; -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; *) break ;; esac done [ "${BOARD_NAME}" ] || BOARD_NAME="$1" #当参数数量小于4或者大于6个的时候退出 [ $# -lt 4 ] && exit 1 [ $# -gt 6 ] && exit 1 #这里就是配置时窗口显示的Configuring for mx6dl_sabresd_android board... echo "Configuring for ${BOARD_NAME} board..." # Create link to architecture specific headers # 根据不同的架构,将不同的文件进行软连接 if [ "$SRCTREE" != "$OBJTREE" ] ; then mkdir -p ${OBJTREE}/include mkdir -p ${OBJTREE}/include2 cd ${OBJTREE}/include2 rm -f asm ln -s ${SRCTREE}/include/asm-$2 asm LNPREFIX="../../include2/asm/" cd ../include rm -rf asm-$2 rm -f asm mkdir asm-$2 ln -s asm-$2 asm else cd ./include rm -f asm ln -s asm-$2 asm fi rm -f asm-$2/arch if [ -z "$6" -o "$6" = "NULL" ] ; then ln -s ${LNPREFIX}arch-$3 asm-$2/arch else ln -s ${LNPREFIX}arch-$6 asm-$2/arch fi if [ "$2" = "arm" ] ; then rm -f asm-$2/proc ln -s ${LNPREFIX}proc-armv asm-$2/proc fi #创建一个/include/config.mk,并将传进来的参数放入里面 echo "ARCH = $2" > config.mk echo "CPU = $3" >> config.mk echo "BOARD = $4" >> config.mk [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk #创建/include/config.h并将两个架构相关的头文件放入其中 if [ "$APPEND" = "yes" ] # Append to existing config file then echo >> config.h else > config.h # Create new config file fi echo "/* Automatically generated - do not edit */" >>config.h echo "#include <configs/$1.h>" >>config.h echo "#include <asm/config.h>" >>config.h exit 0
查看MKCONFIG可知,最后这五个会生成include/config.mk中
ARCH = arm
CPU = arm_cortexa8
BOARD = mx6q_sabresd
VENDOR = freescale
SOC = mx6
由此可以推出./board/freescale/mx6q_sabresd/u-boot.lds
由此可知入口为flash_header.S
3).编译过程分析
通过之前分析查看/include/config.mk
ARCH = arm
CPU = arm_cortexa8
BOARD = mx6q_sabresd
VENDOR = freescale
SOC = mx6
通过全局搜索可以找到/board/freescale/mx6q_sabresd/u-boot.lds为链接脚本文件
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x00000000; . = ALIGN(4); .text : { /* WARNING - the following is hand-optimized to fit within */ /* the sector layout of our flash chips! XXX FIXME XXX */ board/freescale/mx6q_sabresd/flash_header.o (.text.flasheader) cpu/arm_cortexa8/start.o board/freescale/mx6q_sabresd/libmx6q_sabresd.a (.text) lib_arm/libarm.a (.text) net/libnet.a (.text) drivers/mtd/libmtd.a (.text) drivers/mmc/libmmc.a (.text) . = DEFINED(env_offset) ? env_offset : .; common/env_embedded.o(.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .got : { *(.got) } . = .; __u_boot_cmd_start = .; .u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .; . = ALIGN(4); _end_of_copy = .; /* end_of ROM copy code here */ /* Extend to align to 0x1000, then put the Hab Data */ . = ALIGN(0x1000); __hab_data = .; . = . + 0x2000; __data_enc_key = .; /* actually, only 64bytes are needed, but this generates a size multiple of 512bytes, which is optimal for SD boot */ . = . + 0x200; __hab_data_end = .; /* End of Hab Data, Place it before BSS section */ __bss_start = .; .bss : { *(.bss) } _end = .; }
从这个文件可知,代码的入口为_start
text为代码段,rodata为只读数据段,u_boot_cmd为命令的存放空间。
发现第一个文件为board/freescale/mx6q_sabresd/flash_header.S,他是保存在(.text.flasheader)段中
2. uboot的第一阶段
从flash_header.S中可知
.section ".text.flasheader", "x" b _start
这个时候跳入了_start中了,其在cpu/arm_cortexa8/start.S当中
/*第一步:首先进行复位*/ .globl _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq _pad: .word 0x12345678 /* now 16*4=64 */ .global _end_vect _end_vect: .balignl 16,0xdeadbeef 。。。省略。。。 /*复位,设置CPSR寄存器*/ reset: /* * set the cpu to SVC32 mode */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr,r0 /*没有定义CONFIG_SKIP_LOWLEVEL_INIT ,所以进入cpu_init_crit */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit #endif 。。。省略。。。 cpu_init_crit: /* * Invalidate L1 I/D */ mov r0, #0 @ set up for MCR mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs mcr p15, 0, r0, c7, c5, 0 @ invalidate icache /*关闭mmu和catch*/ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002000 @ clear bits 13 (--V-) bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB mcr p15, 0, r0, c1, c0, 0 mov ip, lr @ persevere link reg across call bl lowlevel_init @这里是跳转到lowlevel_init去初始化一些基本的板级信息。 mov lr, ip @ restore link mov pc, lr @ back to my caller
通过全局搜索可知lowlevel_init在boardfreescalemx6q_sabresd目录中的lowlevel_init.S中,打开lowlevel_init.S
.globl lowlevel_init lowlevel_init: /* 禁止D-CACHE */ inv_dcache /*禁止L2Cache */ init_l2cc init_aips /*初始化时钟*/ init_clock /*跳回去*/ mov pc, lr
返回到start.S中,如下代码可知,返回到了cpu_init_crit调用之后的代码
#ifndef CONFIG_SKIP_RELOCATE_UBOOT /*比较_start 的值和_TEXT_BASE的值是否一致,如果不一致的话则进行拷贝, *在uboot的第一阶段是不一致的,因为_start为nor flash的地址值,而 *_TEST_BASE为RAM中确定的运行地址值 */ relocate: @ relocate U-Boot to RAM adr r0, _start @ r0 <- current position of code ldr r1, _TEXT_BASE @ test if we run from flash or RAM cmp r0, r1 @ don t reloc during debug beq stack_setup ldr r2, _armboot_start ldr r3, _bss_start sub r2, r3, r2 @ r2 <- size of armboot add r2, r0, r2 @ r2 <- source end address /*这里就是进行代码的拷贝了*/ copy_loop: @ copy 32 bytes at a time ldmia r0!, {r3 - r10} @ copy from source address [r0] stmia r1!, {r3 - r10} @ copy to target address [r1] cmp r0, r2 @ until source end addreee [r2] ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ /*重定位之后,设置堆栈,,初始化C语言环境 */ stack_setup: ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 @ leave 3 words for abort-stack and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d /* Clear BSS (if any). Is below tx (watch load addr - need space) */ clear_bss: ldr r0, _bss_start @ find start of bss segment ldr r1, _bss_end @ stop here mov r2, #0x00000000 @ clear value clbss_l: str r2, [r0] @ clear BSS location cmp r0, r1 @ are we at the end yet add r0, r0, #4 @ increment clear index pointer bne clbss_l @ keep clearing till at end #ifdef CONFIG_ARCH_MMU bl board_mmu_init #endif ldr pc, _start_armboot @ jump to C code /*从这里跳入uboot的第二阶段*/ _start_armboot: .word start_armboot
第一阶段流程总结:
flash_header.S b _start
start.S _start: b reset //复位
start.S cpu_init_crit //关闭mmu和catch
lowlevel_init.S lowlevel_init //关闭D-CACHE和L2Cache,初始化时钟
start.S relocate //查看是否需要代码进行重定位
start.S copy_loop //代码进行重定位
start.S stack_setup //设置堆栈,清BSS等初始化C语言环境
start.S start_armboot //跳入第二阶段
3. uboot的第二阶段
通过搜索可知第二阶段代码在:lib_arm/board.c中的start_armboot
void start_armboot (void) { init_fnc_t **init_fnc_ptr; char *s; #if defined(CONFIG_VFD) || defined(CONFIG_LCD) unsigned long addr; #endif /* Pointer is writable since we allocated a register for it */ gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)); /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); memset ((void*)gd, 0, sizeof (gd_t)); gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); memset (gd->bd, 0, sizeof (bd_t)); gd->flags |= GD_FLG_RELOC; monitor_flash_len = _bss_start - _armboot_start; /*这里的init_sequence是一个函数指针数组,他将分别对硬件进行初始化*/ for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) { hang (); } }
在lib_arm/board.c中查看所初始化的函数:
init_fnc_t *init_sequence[] = { #if defined(CONFIG_ARCH_CPU_INIT) arch_cpu_init, /* CPU基本的初始化:打开icache,dcache,清看门狗,和一些外设掉电 */ #endif board_init, /* 板子的基本信息:机器码=3980,LCD基本信息 */ #if defined(CONFIG_USE_IRQ) interrupt_init, /* set up exceptions */ #endif timer_init, /*初始化定时器*/ env_init, /* 初始化环境变量,所在文件为common/env_sf.c */ init_baudrate, /* 设置波特率 */ serial_init, /* 设置串口 */ console_init_f, /* 设置是否有无控制台 */ display_banner, /*打印一些基本信息给控制台*/ #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_SOFT_I2C) init_func_i2c, #endif dram_init, /* 设置DRAM的大小和地址 */ #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) arm_pci_init, #endif display_dram_config, /*打印配置的DRAM的基本信息*/ NULL, };
其中env_init为环境变量的初始化,所在文件为common/env_sf.c
int env_init(void) { /* SPI flash isn't usable before relocation */ gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = 1; return 0; }
default_environment则为默认环境变量在/common/env_common.c中
uchar default_environment[] = { #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "