start.s源码分析

针对uboot版本:2010-03
平台:2410smdk
 
#include <config.h>
#include <version.h>
#include <status_led.h>
/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */
//.global声明一个符号可被其它文件引用,相当于声明了一个
//全局变量,.globl与.global相同。
//该部分为处理器的异常处理向量表。地址范围为
//0x0000 0000 ~ 0x0000 0020,刚好8条指令。

//声明全局变量 _start

.globl _start   /*系统复位位置,整个程序入口*/

_start: b       start_code   @0x00
@ARM上电后执行的第一条指令,也即复位向量,跳转到start_code
 ldr pc, _undefined_instruction @0x04
 ldr pc, _software_interrupt  @0x08
 ldr pc, _prefetch_abort  @0x0c
 ldr pc, _data_abort   @0x10
 ldr pc, _not_used   @0x14
 ldr pc, _irq    @0x18
 ldr pc, _fiq    @0x1c

//.word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并
//用伪操作中的expr初始化。.long与.int作用与之相同。
/*.word 表达式 ==> 就是在当前位置放一个word型的值,这个值就是"表达式"
;rWTCON: .word 0x15300000 就是在当前地址,即rWTCON处放一个值0x15300000*/


_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
 
/*
 *************************************************************************
 *
 * 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
 *
 *************************************************************************
 */
// TEXT_BASE在开发板相关的目录中的config.mk文件中定义, 它定义了
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
/*
 *保存变量的数据区,保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者
 其它的使用。
 *还有一些变量的长度是通过连接脚本里得到,实际上由编译器算出来的
 */
//TEXT_BASE定义在\board\smdk2410\config.mk中。
/*TEXT_BASE是代码执行的起始地址.编译产生的二进制文件必需下载到该地
址,因为所有的函数,全局变量等等定位都是以这个地址为参照的.
如果uboot中是TEXT_BASE就是设的0x33F80000, 那么必需download到这个地址的ram中才
能正常运行.
*/ 
_TEXT_BASE:  //_TEXT_BASE=TEXT_BASE.
.word TEXT_BASE   /*uboot映像在SDRAM中的重定位地址*/

// 标号_start在前面有定义

.globl _armboot_start   // /*在_armboot_start标号处,保存了_start的值*/
_armboot_start:     //_armboot_start=_start。
.word _start    /*_start是程序入口,链接完毕它的值应该是TEXT_BASE*/

/*
 * These are defined in the board-specific linker script.
 */
//__bss_start是uboot 的bss段起始地址,那么uboot映像的大小就是__bss_start - _start;
//实际上,_armboot_start并没有实际意义,它只是在"ldr r2, _armboot_start"中用來寻址_start的值而已,_bss_start也是一样的道理,真正有意义的应该是_start和 __bss_start本身。
.globl _bss_start  /*__bss_start是uboot 的bss段起始地址,*/
_bss_start:         /*uboot映像的大小就是__bss_start - _start*/
  .word __bss_start
.globl _bss_end
_bss_end:
  .word _end
#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

 

/*add for env_nand.c添加一个标志,判断是从nor还是nand启动*/
.extern  pbootflag
@pbootflag:  //1:NOR flash, 0:NAND flash


/* the actual start code 真正的实际启动开始代码*/
start_code:/*复位启动子程序*/
/*设置cpu运行在SVC32模式。共有7种模式*/
mrs r0,cpsr  /*复制当前程序状态寄存器cpsr到r0*/
bic r0,r0,#0x1f  //这里使用位清除指令,把中断全部清除,只置位模式控制位
                          //7种异常,共占0x00 - 0x16空间
/*ORR{条件}{S}  <dest>, <op 1>, <op 2>*/
       /*OR 将在两个操作数上进行逻辑或,把结果放置到目的寄存器中*/
orr r0,r0,#0xd3 /*选择新模式,(现在设为超级保护模式)*/

msr cpsr,r0  /*设置cpsr为超级保护模式*/
   /*通过设置ARM的CPSR寄存器,让CPU运行在操作系统模式,为后面进行其它操作作好准备*/

//如果定义了CONFIG_AT91RM9200DK,CONFIG_AT91RM9200EK,CONFIG_AT91RM9200DF中的任意一个
//,就会执行其中的语句.这里没有用。
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
/* 重定向异常向量表,对于该平台,该异常向量表已经烧在0x0地址,该操作主要是针对系统上电或或者复位时不是从0x0地址开始执行并且0x0地址没有异常向量表
*/
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

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)

#if defined(CONFIG_S3C2400)
#define pWTCON 0x15300000
#define INTMSK 0x14400008 /* Interupt-Controller base addresses */
#define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#define pWTCON 0x53000000  /*"看门狗定时器控制寄存器"的地址0x53000000*/ 
#define INTMSK 0x4A000008 /*"中断屏蔽寄存器"的地址:0x4A000008 */
#define INTSUBMSK 0x4A00001C /*针对INTMAK具体化的一个中断请求屏蔽寄存器,其地
                                                             址0x4A00001C */ 
#define LOCKTIME 0x4c000000  //锁时计数寄存器   
#define MPLLCON 0x4c000004  //MPLL寄存器
#define UPLLCON 0x4c000008  //UPLL寄存器
#define CLKDIVN 0x4C000014 /*CPU时钟分频控制寄存器,地址0x4C000014*/ 
#  define BWSCON 0x48000000  //可以从这个寄存器判断是从nor还是nand启动
#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, =0x7ff   //2410有11位
 ldr r0, =INTSUBMSK
 str r1, [r0]
 //add by farsight
 ldr r1,=0x50
 ldr r0,=0x56000054
 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_S3C2400 || CONFIG_S3C2410 */
 /*
  * we do sys-critical inits only at reboot,
  * not when booting from ram!
/*这些初始化代码在系统重启的时候执行,运行时热复位从RAM中启动不执行*/

  */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
 bl cpu_init_crit
#endif
#ifdef CONFIG_S3C2410#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*add 2010-2-4  添加的,获取启动信息,看是nor还是nand启动*/
 ldr r0,=BWSCON
 ldr r0,[r0]
 ands r0,r0,#6
 beq nand_boot

#if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
#ifndef CONFIG_S3C2410_NAND_BOOT
//NOR_BOOT :从nor启动时的重定向uboot代码
relocate: /* 把U-BOOT重新定位到RAM*/
         //r0=0;
adr r0, _start /* r0是代码的当前位置*/
//r1=TEXT_BASE = 0x33F80000
ldr r1, _TEXT_BASE /*测试判断是从FLASH启动,还是RAM  */
cmp     r0, r1     /*比较R0、R1,调试的时候不需要重定位。 */
beq     stack_setup  /*如果R0等于R1,跳到重定位代码。*/

//如果不是从RAM运行的话,则将代码拷贝到_TEXT_BASE标识的RAM中。
/*准备重新定义代码。*/
ldr r2, _armboot_start//_armboot_start=_start
ldr r3, _bss_start  //代码段结束地址,bbs段起始地址
sub r2, r3, r2 /* r2得到armboot的大小*/
add r2, r0, r2 /* r2得到要复制代码的末尾地址*/
//拷贝过程
copy_loop:/*重新定位代码*/
ldmia r0!, {r3-r10} /*从源地址[r0]复制,r0指向_start(=0)*/
stmia r1!, {r3-r10} /*复制到目的地址[r1],r1指向_TEXT_BASE(=0x33F80000)*/
cmp r0, r2 /* 复制数据块直到源数据末尾地址[r2]*/
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
 bl stack_setup

nand_boot:
#ifdef CONFIG_S3C2410_NAND_BOOT
@ reset NAND
  mov r1, #NAND_CTL_BASE
  ldr r2, =0xf830 @ initial value
  str r2, [r1, #oNFCONF]
  ldr r2, [r1, #oNFCONF]
  bic r2, r2, #0x800 @ enable chip
  str r2, [r1, #oNFCONF]
  mov r2, #0xff @ RESET command
  strb r2, [r1, #oNFCMD]

  mov r3, #0 @ wait
nand1:
  add r3, r3, #0x1
  cmp r3, #0xa
  blt nand1
nand2:
  ldr r2, [r1, #oNFSTAT] @ wait ready
  tst r2, #0x1
  beq nand2
  ldr r2, [r1, #oNFCONF]
  orr r2, r2, #0x800 @ disable chip
  str r2, [r1, #oNFCONF]
@ get read to call C functions (for nand_read())
  ldr sp, DW_STACK_START @ setup stack pointer
  mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
  ldr r0, =TEXT_BASE   //置第1个参数: UBOOT在RAM中的起始地址

  mov r1, #0x0     //设置第2个参数:NAND闪存的起始地址

  mov r2, #0x30000  // 设置第3个参数: U-BOOT的长度(196KB)

  bl nand_read_ll  //调用nand_read_ll(),把NAND闪存中的数据读入到RAM中


  tst r0, #0x0  // 如果函数的返回值为0,表示执行成功

  beq ok_nand_read  //执行内存比较,把RAM中的前4K内容与NAND闪存中的前4K内容进行比较, 如果完全相同, 则表示搬移成功
bad_nand_read:
loop2: b loop2 @ infinite loop

ok_nand_read:
@ env in nand  //这时坏境变量应该存于nand,设置标志位
  ldr r0, =pbootflag
  mov r1, #0x0
  str r1, [r0]
@ verify
  mov r0, #0
  ldr r1, =TEXT_BASE
  mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
  ldr r3, [r0], #4
  ldr r4, [r1], #4
  teq r3, r4
  bne notmatch
  subs r2, r2, #4
  beq stack_setup
  bne go_next
notmatch:
loop3: b loop3 @ infinite loop  //不匹配,死循环
#endif @ CONFIG_S3C2410_NAND_BOOT
 /* 初始化堆栈*/
stack_setup:
ldr r0, _TEXT_BASE /*上面是128kib重定位的u-boot*/
/*在smdk2410.h中定义 #define CFG_MALLOC_LEN (CFG_ENV_SIZE + 2048*1024)
                    #define CFG_ENV_SIZE     0x10000
   #define CFG_GBL_DATA_SIZE 128 */
sub r0, r0, #CFG_MALLOC_LEN /*向下是内存分配malloc空间*/
sub r0, r0, #CFG_GBL_DATA_SIZE /*然后是bdinfo结构体地址空间*/
#ifdef CONFIG_USE_IRQ  //在 smdk2410.h中定义。
    /*在smdk2410.h中定义#define CONFIG_STACKSIZE_IRQ (8*1024)
                                                 #define CONFIG_STACKSIZE_FIQ (4*1024) */
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /*为 abort-stack 预留3个字,得到最终sp指针初始值*/
//清除bss段
clear_bss:
ldr r0, _bss_start /*找到bss 段起始地址。*/
ldr r1, _bss_end /* bss 段末尾地址。*/
mov r2, #0x00000000 /* 清零。*/

clbss_l:str r2, [r0] /*bss 段地址空间清零循环。。。*/
      add r0, r0, #4
      cmp r0, r1
      ble clbss_l   
/*跳转到start_armboot函数入口,_start_armboot字保存函数入口指针*/
ldr pc, _start_armboot

//_start_armboot=start_armboot
//pc=start_armboot;
//去执行void start_armboot (void),在lib_arm/boarb.c中。
_start_armboot: .word start_armboot


/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/

//功能:设置CP15寄存器 这里完成的功能:失效Icache和Dcache,禁能MMU和cache
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
//关键的初始化子程序。
cpu_init_crit:
/*  flush v4 I/D caches  | 失效指令cache和数据cache       */
mov r0, #0
//使I/D cache失效:将寄存器r0的数据传送到协处理器p15的c7中。C7寄存器
//位对应cp15中的cache控制寄存器
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
//使TLB操作寄存器失效:将r0数据送到cp15的c8、c7中。C8对应TLB操作
//寄存器
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

/*
* disable MMU stuff and caches
*/
/*   disable MMU stuff and caches |   禁能MMU和cache       */
mrc p15, 0, r0, c1, c0, 0 //先把c1和c0寄存器的各位置0(r0 = 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
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)

#else
bl lowlevel_init  //位于board/smdk2440/lowlevel_init.S:用于完成芯片存储器的初始化,
                             //执行完成后返回
#endif
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*
*************************************************************************
*
* 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 ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/

.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
ldmia r2, {r2 - r3} @ get pc, cpsr
add r0, sp, #S_FRAME_SIZE @ restore sp_SVC

add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp
.endm

.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
add     r8, sp, #S_PC
stmdb   r8, {sp, lr}^                   @ Calling SP, LR
str     lr, [r8, #0]                    @ Save calling PC
mrs     r6, spsr
str     r6, [r8, #4]                    @ Save CPSR
str     r0, [r8, #8]                    @ Save OLD_R0
mov r0, sp
.endm

.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm

.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

str lr, [r13] @ save caller lr / spsr
mrs lr, spsr
str     lr, [r13, #4]

mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13
mov lr, pc
movs pc, lr
.endm

.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm

.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.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
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

#ifdef CONFIG_USE_IRQ

.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs

.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs

#else

.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


本文来自CSDN博客,转载请标明出处: http://blog.csdn.net/funy_liu/archive/2009/12/23/5060161.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值