一,移植uboot-分析uboot启动流程
文档时间:2018-08-08
交叉编译器:arm-linux-gcc-4.3.2
Ubuntu版本:16.04
uboot版本:2013.10
uboot启动流程简要如下:
a,设置CPU为管理模式
b,关闭看门狗
c,关闭中断
d,设置时钟频率
e,进入lowlevel_init.S,初始化各个bank
f,进入board_init_f()函数
h,代码重定位,清除bss
i,跳转到board_init_r(),进入第二阶段
1,进入https://www.amazon.com/clouddrive/share/HtTEzbceyJDyHv7anDLboEjTe0OkFbYReMxRp3CF20n下载uboot源码
1.1,在Windows下解压uboot源码,建立source insight工程
可以选择将uboot文件夹下所有文件添加到source insight工程中,也可以选择添加,本工程在arch/arm/cpu目录下只添加:
arch/arm/cpu/arm920t //只添加这个目录下的所有文件
在board目录下只添加:
board/samsung/smdk2410 //只添加2410单板
2,通过FileZilla将Windows下的uboot压缩文件传到Ubuntu /home/aaron/work/u-boot目录下,然后编译,烧写
2.1,编译,烧写uboot
由于本工程中所用开发本为JZ2440,单板和SMDK2410很像,所以我们选择编译smdk2410,在Ubuntu中输入命令
cd work/u-boot tar xjf u-boot-2013.10.tar.bz2 cd u-boot-2013.10 make smdk2410_config //配置单板SMDK2410 make //编译生成u-boot.bin
将生成的u-boot.bin通过j-link烧写到JZ2440开发板上(开发板选择nor启动,否则无法烧写),烧写完成发现串口无任何输出,接下来分析uboot启动代码
3,首先查看arch\arm\cpu目录下的u-boot.lds链接文件
ENTRY(_start) //入口地址 SECTIONS { . = 0x00000000; //链接地址 . = ALIGN(4); .text :
u-boot最开始会进入到_start的位置,而_start的位置在arch/arm/cpu/arm920t/文件夹下
4,分析arch/arm/cpu/arm920t/start.S文件
.globl _start //声明_start全局符号 _start: b start_code //跳转到start_code处 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 .balignl 16,0xdeadbeef /* ************************************************************************* * * Startup Code (called from the ARM reset exception vector) * * do important init only if we don't start from memory! * relocate armboot to ram * setup stack * jump to second stage * ************************************************************************* */ .globl _TEXT_BASE _TEXT_BASE: #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE) .word CONFIG_SPL_TEXT_BASE #else .word CONFIG_SYS_TEXT_BASE #endif /* * These are defined in the board-specific linker script. * Subtracting _start from them lets the linker put their * relative position in the executable instead of leaving * them null. */ .globl _bss_start_ofs _bss_start_ofs: .word __bss_start - _start .globl _bss_end_ofs _bss_end_ofs: .word __bss_end - _start .globl _end_ofs _end_ofs: .word _end - _start #ifdef CONFIG_USE_IRQ /* IRQ stack memory (calculated at run-time) */ .globl IRQ_STACK_START IRQ_STACK_START: .word 0x0badc0de /* IRQ stack memory (calculated at run-time) */ .globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de #endif /* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: .word 0x0badc0de /* * the actual start code */ start_code: //设置cpsr寄存器,让CPU处于管理模式 /* * set the cpu to SVC32 mode */ mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) /* * relocate exception table */ ldr r0, =_start ldr r1, =0x0 mov r2, #16 copyex: subs r2, r2, #1 ldr r3, [r0], #4 str r3, [r1], #4 bne copyex #endif #ifdef CONFIG_S3C24X0 /* turn off the watchdog */ # if defined(CONFIG_S3C2400) //关闭看门狗 # define pWTCON 0x15300000 # define INTMSK 0x14400008 /* Interrupt-Controller base addresses */ # define CLKDIVN 0x14800014 /* clock divisor register */ #else # define pWTCON 0x53000000 # define INTMSK 0x4A000008 /* Interrupt-Controller base addresses */ # define INTSUBMSK 0x4A00001C # define CLKDIVN 0x4C000014 /* clock divisor register */ # endif ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] /* * mask all IRQs by setting all bits in the INTMR - default */ mov r1, #0xffffffff //关闭中断 ldr r0, =INTMSK str r1, [r0] # if defined(CONFIG_S3C2410) ldr r1, =0x3ff ldr r0, =INTSUBMSK str r1, [r0] # endif /* FCLK:HCLK:PCLK = 1:2:4 */ /* default FCLK is 120 MHz ! */ //设置时钟 ldr r0, =CLKDIVN mov r1, #3 str r1, [r0] #endif /* CONFIG_S3C24X0 */ /* * we do sys-critical inits only at reboot, * not when booting from ram! */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit //跳转到lowlevel_init.S,初始化各个bank #endif bl _main //跳转到_main /*------------------------------------------------------------------------------*/ .globl c_runtime_cpu_setup c_runtime_cpu_setup: mov pc, lr /* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit: /* * flush v4 I/D caches */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ mrc p15, 0, r0, c1, c0, 0 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) orr r0, r0, #0x00000002 @ set bit 2 (A) Align orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache mcr p15, 0, r0, c1, c0, 0 /* * before relocating, we have to setup RAM timing * because memory timing is board-dependend, you will * find a lowlevel_init.S in your board directory. */ mov ip, lr bl lowlevel_init //初始化blank mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
可以看出start.S里主要工作是:初始化异常向量表,设置SVC模式,关闭看门狗,关闭中断,设置时钟
SDRAM的设置在lowlevel_init.S(board/samsung/smdk2410)中 ,start.S工作完成之后,接下来就是调用_main了
5,分析/arch/arm/lib/crt0.S文件
ENTRY(_main) //_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 //进入第一个C函数 #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 //跳转到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 */ //清除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 //这两行是跳转到与底层led控制有关的c函数 /* 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! */ //跳转到第二阶段的c函数 /* we should not return here. */ #endif ENDPROC(_main)
relocate_code在arch/arm/lib/relocate.S里,主要讲的是代码的拷贝,这里不再详说
board_init_f()函数在arch/arm/lib/board.c里,board_init_f函数主要是根据配置对全局信息结构体gd和init_sequence中的函数进行初始化,init_sequence中函数包括
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, //在board/samsung/smdk2410/smdk2410.c中定义,主要设置时钟和GPIO #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, };
board_init_r()函数在arch/arm/lib/board.c里,该函数会对各个外设初始化、环境变量初始化等
在board_init_r函数里首先会执行board_init(); /* Setup chipselects */函数,在这个函数里会设置机器id和传给内核的入口参数地址
/* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100;
uboot启动过程到此就结束了