uboot2010-09 arm1176 start.S分析

uboot的start.S是整个uboot的最开始的部分,最近正在学习uboot的移植,开发板是OK6410,使用了uboot中arm1176的start.S,位于arch/arm/cpu/arm1176,对这一文件进行了下简略的分析。


头文件及宏定义部分

/* 
 * config.hinclude目录下,是uboot配置中自动生成的文件,包含了相关配置的
 * 头文件。其中有一句#include <configs/smdk6400.h>,将重要的include/
 * configs/smdk6400.h文件联系了起来.
 */
#include <config.h> 

/* 
 * 包含了include/version_autogenerated.h文件,同样是由Makefile自动生
 * 成的文件,定义了uboot版本号的宏.
 */
#include <version.h>

/* 
 * asm不是uboot的原生目录, 是配置是创建的符号链接, 指向asm-arm, proc指向
 * proc-armv, 实际目录为include/asm-arm/proc-aarmv. 此处说明了配置时创
 * 建符号链接的作用. 这样设计提高了uboot的可移植性, 不同的配置创建的符号链
 * 接也不同.
 */
#ifdef CONFIG_ENABLE_MMU
#include <asm/proc/domain.h>
#endif

#if !defined(CONFIG_ENABLE_MMU) && !defined(CONFIG_SYS_PHY_UBOOT_BASE)
#define CONFIG_SYS_PHY_UBOOT_BASE   CONFIG_SYS_UBOOT_BASE
#endif

代码正文

/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */

/* 
 * 开始定义异常向量表, 需要依据CPU手册来设定. 每种异常也都要设定好否则发生对应
 * 异常时会使程序跑飞. uboot中并未细致处理各个异常, 毕竟只是衔接初始化和系统的
 * 一小段时间.
 */
.globl _start
_start: b   reset
#ifndef CONFIG_NAND_SPL
    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 */
#else
    . = _start + 64
#endif

.global _end_vect

/*
 * balignl是一个伪指令, 表示以16字节对齐, 若未对齐以deadbeaf来填充. 
 */
_end_vect:
    .balignl 16,0xdeadbeef
/*
 *************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * setup Memory and board specific bits prior to relocation.
 * relocate armboot to ram
 * setup stack
 *
 *************************************************************************
 */

_TEXT_BASE:
    .word   TEXT_BASE /* TEXT_BASE 是Makefile中指定的程序链接地址: 0x57e00000 */

/*
 * Below variable is very important because we use MMU in U-Boot.
 * Without it, we cannot run code correctly before MMU is ON.
 * by scsuh.
 */
_TEXT_PHY_BASE:
/* 在include/configs/smdk6400.h中定义的内存起始地址, 同样为0x57e00000 */
    .word   CONFIG_SYS_PHY_UBOOT_BASE

.globl _armboot_start
_armboot_start:
    .word _start

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start
_bss_start:
    .word __bss_start

.globl _bss_end
_bss_end:
    .word _end

/*
 * the actual reset code
 */

/* 
 * reset部分是uboot启动/复位后真正开始执行的代码, CPU在启动/复位后会首先进
 * 入reset模式, 经中断向量表跳转到此处开始执行.
 */
reset:

/* 
 * 开始操作cpsr寄存机, 将CPU设置为svc 32模式
 */
    mrs r0, cpsr
    bic r0, r0, #0x3f
    orr r0, r0, #0xd3
    msr cpsr, r0

/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */
    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
cpu_init_crit:
    /*
     * When booting from NAND - it has definitely been a reset, so, no need
     * to flush caches and disable the MMU
     */
/* 
 * CONFIG_NAND_SPL已被定义, 这一大段都会被跳过
 */
#ifndef CONFIG_NAND_SPL
    /*
     * 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

    /* Prepare to disable the MMU */
    adr r2, mmu_disable_phys
    sub r2, r2, #(CONFIG_SYS_PHY_UBOOT_BASE - TEXT_BASE)
    b   mmu_disable

    .align 5
    /* Run in a single cache-line */
mmu_disable:
    mcr p15, 0, r0, c1, c0, 0
    nop
    nop
    mov pc, r2
mmu_disable_phys:

#ifdef CONFIG_DISABLE_TCM
    /*
     * Disable the TCMs
     */
    mrc p15, 0, r0, c0, c0, 2   /* Return TCM details */
    cmp r0, #0
    beq skip_tcmdisable
    mov r1, #0
    mov r2, #1
    tst r0, r2
    mcrne   p15, 0, r1, c9, c1, 1   /* Disable Instruction TCM if present*/
    tst r0, r2, LSL #16
    mcrne   p15, 0, r1, c9, c1, 0   /* Disable Data TCM if present*/
skip_tcmdisable:
#endif
#endif

#ifdef CONFIG_PERIPORT_REMAP
    /* Peri port setup */
    ldr r0, =CONFIG_PERIPORT_BASE
    orr r0, r0, #CONFIG_PERIPORT_SIZE
    mcr p15,0,r0,c15,c2,4
#endif

    /*
     * Go setup Memory and board specific bits prior to relocation.
     */
/*
 * lowlevel_init位于board/samsung/smdk6400目录下, 包含了对应开发板的
 * CPU时钟设定, 关看门狗, SRAM和NAND初始化等底层操作. 这一步完成之后, 
 * 就可以进入到uboot的BL2部分从CPU的SRAM进行到DRAM开始运行了.
 */     
    bl  lowlevel_init       /* go setup pll,mux,memory */

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
/*
 * 代码搬移部分, 首先判断uboot的运行位置. 原理是将_start函数入口地址放入
 * r0中和放入r1中的链接地址进行比对, 当搬移完成后start函数入口地址便会等
 * 于链接地址. 此后会跳转到stack_setup进行栈区初始化.
 */
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:
    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 */


/* 
 * 开始设置MMU, 实现虚拟地址到物理地址的映射
 */
#ifdef CONFIG_ENABLE_MMU
enable_mmu:
    /* 通过CP15的C3寄存器使能MMU */
    /* enable domain access */
    ldr r5, =0x0000ffff          
    mcr p15, 0, r5, c3, c0, 0   /* load domain access register */

    /* 
     * 设置TTB, 即CP15的C2寄存器. TTB(Translation table base): 装换表基地址
     * 装换表是虚拟地址映射的关键, 分为表索引和表项两部分. 表索引对应虚拟地址,
     * 表项对应物理地址.
     */
    /* Set the TTB register */
    ldr r0, _mmu_table_base
    ldr r1, =CONFIG_SYS_PHY_UBOOT_BASE
    ldr r2, =0xfff00000
    bic r0, r0, r2
    orr r1, r0, r1
    mcr p15, 0, r1, c2, c0, 0

    /* 通过CP15的C1寄存器开启MMU */ 
    /* Enable the MMU */
    mrc p15, 0, r0, c1, c0, 0
    orr r0, r0, #1      /* Set CR_M to enable MMU */

    /* Prepare to enable the MMU */
    adr r1, skip_hw_init
    and r1, r1, #0x3fc
    ldr r2, _TEXT_BASE
    ldr r3, =0xfff00000
    and r2, r2, r3
    orr r2, r2, r1
    b   mmu_enable

    .align 5
    /* Run in a single cache-line */
mmu_enable:

    mcr p15, 0, r0, c1, c0, 0
    nop
    nop
    mov pc, r2
skip_hw_init:
#endif
    /* 在设置玩MMU之后, 就必须开始使用虚拟地址了 */

    / * 设置栈区和清理BSS段, 通过相关宏地址即可得出UBOOT对堆地址和空间大小的分配 */
    /* Set up the stack                         */
stack_setup:
    ldr r0, =CONFIG_SYS_UBOOT_BASE  /* base of copy in DRAM     */
    sub r0, r0, #CONFIG_SYS_MALLOC_LEN  /* malloc area                      */
    sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                        */
    sub sp, r0, #12     /* leave 3 words for abort-stack    */
    bic sp, sp, #7      /* 8-byte alignment for ABI compliance */

clear_bss:
    ldr r0, _bss_start      /* find start of bss segment        */
    ldr r1, _bss_end        /* stop here                        */
    mov     r2, #0          /* clear                            */

clbss_l:
    str r2, [r0]        /* clear loop...                    */
    add r0, r0, #4
    cmp r0, r1
    ble clbss_l

    /* 
     * ldr为一远跳转指令, 与运行地址无关, 与链接地址有关. 通过ldr  pc, _start_armboot这一指令
     * 即可载入arch\arm\lib\board.c中的_start_armboot函数, 进入uboot的BL2阶段了.
     */
#ifndef CONFIG_NAND_SPL
    ldr pc, _start_armboot  

_start_armboot:
    .word start_armboot
#else
    b   nand_boot
/*  .word nand_boot*/
#endif

#ifdef CONFIG_ENABLE_MMU
_mmu_table_base:
    .word mmu_table
#endif

#ifndef CONFIG_NAND_SPL
/*
 * we assume that cache operation is done before. (eg. cleanup_before_linux())
 * actually, we don't need to do anything about cache if not use d-cache in
 * U-Boot. So, in this function we clean only MMU. by scsuh
 *
 * void theLastJump(void *kernel, int arch_num, uint boot_params);
 */
#ifdef CONFIG_ENABLE_MMU
    .globl theLastJump
theLastJump:
    mov r9, r0
    ldr r3, =0xfff00000
    ldr r4, _TEXT_PHY_BASE
    adr r5, phy_last_jump
    bic r5, r5, r3
    orr r5, r5, r4
    mov pc, r5
phy_last_jump:
    /*
     * disable MMU stuff
     */
    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

    mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */

    mov r0, #0
    mov pc, r9
#endif


/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE    72

#define S_OLD_R0    68
#define S_PSR       64
#define S_PC        60
#define S_LR        56
#define S_SP        52

#define S_IP        48
#define S_FP        44
#define S_R10       40
#define S_R9        36
#define S_R8        32
#define S_R7        28
#define S_R6        24
#define S_R5        20
#define S_R4        16
#define S_R3        12
#define S_R2        8
#define S_R1        4
#define S_R0        0

#define MODE_SVC 0x13
#define I_BIT    0x80

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 */

    .macro  bad_save_user_regs
    /* carve out a frame on current user stack */
    sub sp, sp, #S_FRAME_SIZE
    /* Save user registers (now in svc mode) r0-r12 */
    stmia   sp, {r0 - r12}

    ldr r2, _armboot_start
    sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
    /* set base 2 words into abort stack */
    sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
    /* get values for "aborted" pc and cpsr (into parm regs) */
    ldmia   r2, {r2 - r3}
    /* grab pointer to old stack */
    add r0, sp, #S_FRAME_SIZE

    add r5, sp, #S_SP
    mov r1, lr
    /* save sp_SVC, lr_SVC, pc, cpsr */
    stmia   r5, {r0 - r3}
    /* save current stack into r0 (param register) */
    mov r0, sp
    .endm

    .macro get_bad_stack
    /* setup our mode stack (enter in banked mode) */
    ldr r13, _armboot_start
    /* move past malloc pool */
    sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
    /* move to reserved a couple spots for abort stack */
    sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8)

    /* save caller lr in position 0 of saved stack */
    str lr, [r13]
    /* get the spsr */
    mrs lr, spsr
    /* save spsr in position 1 of saved stack */
    str lr, [r13, #4]

    /* prepare SVC-Mode */
    mov r13, #MODE_SVC
    @ msr   spsr_c, r13
    /* switch modes, make sure moves will execute */
    msr spsr, r13
    /* capture return pc */
    mov lr, pc
    /* jump to next instruction & switch modes. */
    movs    pc, lr
    .endm

    .macro get_bad_stack_swi
    /* space on current stack for scratch reg. */
    sub r13, r13, #4
    /* save R0's value. */
    str r0, [r13]
    /* get data regions start */
    ldr r0, _armboot_start
    /* move past malloc pool */
    sub r0, r0, #(CONFIG_SYS_MALLOC_LEN)
    /* move past gbl and a couple spots for abort stack */
    sub r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8)
    /* save caller lr in position 0 of saved stack */
    str lr, [r0]
    /* get the spsr */
    mrs r0, spsr
    /* save spsr in position 1 of saved stack */
    str lr, [r0, #4]
    /* restore r0 */
    ldr r0, [r13]
    /* pop stack entry */
    add r13, r13, #4
    .endm

/*
 * exception handlers
 */
    .align  5
undefined_instruction:
    get_bad_stack
    bad_save_user_regs
    bl  do_undefined_instruction

    .align  5
software_interrupt:
    get_bad_stack_swi
    bad_save_user_regs
    bl  do_software_interrupt

    .align  5
prefetch_abort:
    get_bad_stack
    bad_save_user_regs
    bl  do_prefetch_abort

    .align  5
data_abort:
    get_bad_stack
    bad_save_user_regs
    bl  do_data_abort

    .align  5
not_used:
    get_bad_stack
    bad_save_user_regs
    bl  do_not_used

    .align  5
irq:
    get_bad_stack
    bad_save_user_regs
    bl  do_irq

    .align  5
fiq:
    get_bad_stack
    bad_save_user_regs
    bl  do_fiq
#endif /* CONFIG_NAND_SPL */
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值