天天看點

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