天天看点

u-boot-1.1.6之cpu/arm920t/start.s分析

#include <config.h>

#include <version.h>

 //global声明一个符号可被其他文档引用,相当于声明了一个全局变量,.globl和.global相同。

 //该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。

.globl _start      //u-boot启动入口

_start: b       reset    //复位向量并且跳转到reset

 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     //中断向量

 // .word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long和.int作用与之相同。

_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  // .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign的作用同.align。

 // .align {alignment} {,fill} {,max}

 //  其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0填充。max是填充字节数最大值,假如填充字节数超过max,

 //  就不进行对齐,例如:

 //  .align 4 

 .balignl 16,0xdeadbeef

 // TEXT_BASE在研发板相关的目录中的config.mk文档中定义, 他定义了

 // 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址

_TEXT_BASE:

 .word TEXT_BASE

 // 声明 _armboot_start 并用 _start 来进行初始化,在board/u-boot.lds中定义。

.globl _armboot_start

_armboot_start:

 .word _start

  // 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在和板相关的u-boot.lds中。

 // _bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在

 // 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时

 // 地址的影响. _bss_end也是同样的道理.

.globl _bss_start

_bss_start:

 .word __bss_start  // 同上

.globl _bss_end

_bss_end:

 .word _end #ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START

IRQ_STACK_START:

 .word 0x0badc0de

.globl FIQ_STACK_START

FIQ_STACK_START:

 .word 0x0badc0de

#endif

//  MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd

//  使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样能够最好地完成对CRSP或SPSR的修改

//  MSR {} CPSR_|SPSR_,Rm 或是 MSR {} CPSR_f|SPSR_f,#

//  MRS和MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分

//   bic r0,r1,r2  ;r0:=r1 and not r2

//   orr ro,r1,r2  ;r0:=r1 or r2

//  这几条指令执行完毕后,进入SVC32模式,该模式主要用来处理软件中断(SWI)

reset:

 mrs r0,cpsr    //将CPSR状态寄存器读取,保存到R0中

 bic r0,r0,#0x1f

 orr r0,r0,#0xd3

 msr cpsr,r0    //将R0写入状态寄存器中

 //关闭看门狗

#if defined(CONFIG_S3C2400)

# define pWTCON  0x15300000

# define INTMSK  0x14400008 

# define CLKDIVN 0x14800014 

#elif defined(CONFIG_S3C2410)

# define pWTCON  0x53000000

# define INTMSK  0x4A000008 

# define INTSUBMSK 0x4A00001C

# define CLKDIVN 0x4C000014 

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

 ldr     r0, =pWTCON

 mov     r1, #0x0

 str     r1, [r0]  

 //关闭所有中断

 mov r1, #0xffffffff

 ldr r0, =INTMSK

 str r1, [r0]

# if defined(CONFIG_S3C2410)

 ldr r1, =0x3ff

 ldr r0, =INTSUBMSK

 str r1, [r0]

# endif  

 ldr r0, =CLKDIVN

 mov r1, #3

 str r1, [r0]

#endif   

  // B 转移指令,跳转到指令中指定的目的地址

 // BL 带链接的转移指令,像B相同跳转并把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程式的调用

 // 该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

 bl cpu_init_crit

#endif #ifndef CONFIG_SKIP_RELOCATE_UBOOT

 //调试阶段的代码是直接在RAM中运行的,而最后需要把这些代码固化到Flash中,因此U-Boot需要自己从Flash转移到

 //RAM中运行,这也是重定向的目的所在。

 //通过adr指令得到当前代码的地址信息:假如U-boot是从RAM开始运行,则从adr,r0,_start得到的地址信息为

 //r0=_start=_TEXT_BASE=TEXT_BASE=0xa3000000;假如U-boot从Flash开始运行,即从处理器对应的地址运行,

 //则r0=0x0000,这时将会执行copy_loop标识的那段代码了。

 // _TEXT_BASE 定义在board/smdk2410/config.mk中

relocate:      

 adr r0, _start    

 ldr r1, _TEXT_BASE  

 cmp     r0, r1                  

 beq     stack_setup  //重新定位代码

 ldr r2, _armboot_start

 ldr r3, _bss_start

 sub r2, r3, r2    

 add r2, r0, r2     copy_loop:

 ldmia r0!, {r3-r10}  

 stmia r1!, {r3-r10}  

 cmp r0, r2    

 ble copy_loop

#endif   

 //初始化堆栈

stack_setup:

 ldr r0, _TEXT_BASE    

 sub r0, r0, #CFG_MALLOC_LEN  

 sub r0, r0, #CFG_GBL_DATA_SIZE  

#ifdef CONFIG_USE_IRQ

 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

 sub sp, r0, #12      clear_bss:

 ldr r0, _bss_start     

 ldr r1, _bss_end     

 mov  r2, #0x00000000    clbss_l:str r2, [r0]     

 add r0, r0, #4

 cmp r0, r1

 ble clbss_l #if 0

 ldr     r0, =pWTCON

 mov     r1, #0x0

 str     r1, [r0]  

 mov r1, #0xffffffff

 ldr r0, =INTMR

 str r1, [r0]  

 ldr r0, =CLKDIVN

 mov r1, #3

 str r1, [r0]

#endif  //跳转到start_armboot函数入口,_start_armboot字保存函数入口指针

 ldr pc, _start_armboot _start_armboot: .word start_armboot //start_armboot函数在lib_arm/board.c中实现

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

 //初始化CACHE

 mov r0, #0

 mcr p15, 0, r0, c7, c7, 0 

 mcr p15, 0, r0, c8, c7, 0   

  //关闭MMU和CACHE

 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  

 //初始化RAM时钟。因为内存时钟是依赖开发板硬件的,所以在board的相应目录下可以找到memsetup.s文件

 mov ip, lr

 bl lowlevel_init  //lowlevel_init子程序在board/smdk2410/memsetup.s中实现

 mov lr, ip

 mov pc, lr

#endif @

@ 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  .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

 .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

 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