1. 程式人生 > >一,移植uboot,分析uboot啟動流程

一,移植uboot,分析uboot啟動流程

寫到 位置 ESS fff setup boa soft bec 進入

文檔時間: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啟動流程