一,移植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启动过程到此就结束了
    

 

posted @ 2018-08-08 22:09  Mango丶  阅读(722)  评论(0编辑  收藏  举报