一,移植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進行初始化,由於本人對於gd裏面的一些成員含義也不是很理解,所以這裏不做詳細分析
board_init_r()函數在arch/arm/lib/board.c裏,該函數會對各個外設初始化、環境變量初始化等
uboot啟動過程到此就結束了
一,移植uboot,分析uboot啟動流程