天天看點

mini2440---start.S注釋

mini2440---start.S注釋 

#include <common.h>

#include <config.h>

.globl _start//@_start是GNU彙編器的預設入口标簽========系統複位位置,整個程式入口

_start: b start_code//ARM體系結構規定在上電複位後的起始位置,必須有8條連續的跳轉指令,通過硬體實作。

//相當于中斷向量表

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為GNU ARM彙編特有的僞操,作為配置設定一段字記憶體單元(配置設定的單元為字對齊的),可以使用.word把标志符作為常量使用。

//如_fiq:.word fiq即把fiq存入記憶體變量_fiq中,也即是把fiq放到位址_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

.balignl 16,0xdeadbeef  //0x3c=60   4*(8+7)=60   //‘.balign 16’向後移動位置計數器直至計數器的值等于16的倍數。且使用0xdeadbeef來填充空白區

                       //該數字是個魔數。通常用于在啟動時讀取它并修改它為0,并與原值比較

                       //以判斷它是從nor nand啟動

_TEXT_BASE:

//

_TEXT_BASE:          //代碼重定位後所在的位址

.word TEXT_BASE

.globl _armboot_start

_armboot_start:

.word _start

//在_armboot_start标号處,儲存了_start的值,也就是說,_armboot_start是存放_start的位址。

.globl _bss_start//@__bss_start定義在和開發闆相關的u-boot.lds中,_bss_start儲存的是__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

//上面這段代碼,主要儲存一些全局變量,用于BOOT程式從FLASH拷貝到RAM,或者其它的使用。

start_code:

mrs r0,cpsr      

bic r0,r0,#0x1f  

orr r0,r0,#0xd3    1101,0011

msr cpsr, r0 //11關中斷,0,thumb模式位

@ bl coloured_LED_init

@ bl red_LED_on

//AT91RM9200 cpu

//#include <common.h>  CONFIG_AT91RM9200DK,有沒有定義,看包含的頭檔案

//#include <config.h>

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)  //未定義

ldr r0, =_start

ldr r1, =0x0

mov r2, #16

copyex:

subs r2, r2, #1//sub帶上了s用來更改進位标志,對于sub來說,若發生借位則C标志置0,沒有則為1,這跟adds指令相反!要注意。

ldr r3, [r0], #4

str r3, [r1], #4

bne copyex

#endif

//========針對S3C2400和S3C2410進行特殊處理==========

#ifdef CONFIG_S3C24X0

//S3C2440A datasheet.pdf

# if defined(CONFIG_S3C2400)//未定義

#  define pWTCON 0x15300000//關閉看門狗定時器的自動複位功能并屏蔽所有中斷,上電後看門狗為開,中斷為關

#  define INTMSK 0x14400008

#  define CLKDIVN 0x14800014

#else//執行

#  define pWTCON 0x53000000

#  define INTMSK 0x4A000008

#  define INTSUBMSK 0x4A00001C

#  define CLKDIVN 0x4C000014

# endif

#define CLK_CTL_BASE 0x4C000000

#define MDIV_405 0x7f << 12

#define PSDIV_405 0x21

#define MDIV_200 0xa1 << 12

#define PSDIV_200 0x31

//關閉看門狗

ldr r0, =pWTCON

mov r1, #0x0

str r1, [r0]//對于S3C2440和S3C2410的WTCON寄存器的[0]控制允許或禁止看門狗定時器的複位輸出功能,設定為“0”禁止複位功能。

//到C第二階段有enable_interrupts (); 來使能中斷  

//關閉總中斷

mov r1, #0xffffffff     關閉所有中斷服務

ldr r0, =INTMSK

str r1, [r0]

//關閉子中斷

# if defined(CONFIG_S3C2410)//十一個。。。。。。未定義

ldr r1, =0x7ff//INTMSK寄存器的32位和INTSUBMSK寄存器的低11位每一位對應一個中斷

ldr r0, =INTSUBMSK

str r1, [r0]

# endif

#if defined(CONFIG_S3C2440)//十五個。。。。。。

ldr r1, =0x7fff 

ldr r0, =INTSUBMSK

str r1, [r0]

#endif

//設定分頻比。主FCLK=MCLK=400MHZ,HCLK=100,PCLK=50,是以是1:4:8

// 因為FCLK != HCLK,是以為異步模式,要協處理器

#if defined(CONFIG_S3C2440)

ldr r0, =CLKDIVN

mov r1, #5//101

str r1, [r0]

// 協處理器,異步模式的時候

mrc p15, 0, r1, c1, c0, 0 //P215

orr r1, r1, #0xc0000000 

mcr p15, 0, r1, c1, c0, 0 

//主時鐘  MPLL

mov r1, #CLK_CTL_BASE

mov r2, #MDIV_405 

add r2, r2, #PSDIV_405 

str r2, [r1, #0x04]

#else

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

mrc p15, 0, r1, c1, c0, 0 

orr r1, r1, #0xc0000000 

mcr p15, 0, r1, c1, c0, 0

mov r1, #CLK_CTL_BASE

mov r2, #MDIV_200 

add r2, r2, #PSDIV_200 

str r2, [r1, #0x04]

#endif

#endif

//在重新定位之前,要進行RAM初始化

//如果沒有定義的話。執行ifndef

//用bl 會把下一條要 執行的位址放在lr.

#ifndef CONFIG_SKIP_LOWLEVEL_INIT//mini2440.h===undef

bl cpu_init_crit//bl 帶傳回的跳轉指令

#endif

//考慮要不要搬運代碼

//比較  _start 和_TEXT_BASE,如果兩者相等,說明是直接加載到記憶體中的自主啟動

//  如果不等,則說明是nand或者nor啟動

adr r0, _start //位址為0

ldr r1, _TEXT_BASE //?board/mini2440/config.mk==0x33F80000

cmp     r0, r1                  

beq     stack_setup             //痰進過重定位代碼

//相等的話是加載啟動,直接跳到設定堆棧;不相等的話判斷是nand或者是nor

//不相等的話,判斷是nor或者是nand啟動

//從nor啟動時0位址是NOR,0x40000000是SRAM

//從nand啟動時,0x40000000是SRAM的位址,0位址也是SRAM的位址

//這裡把0x4000003C位址的内容改為

//0,看#0x3c位址的内容是否也該為0.如果是改為0則是NAND啟動

//0x3c位址放的是一個魔數,如0xdeadbeef

ldr r1, =( (4<<28)|(3<<4)|(3<<2) )

mov r0, #0

str r0, [r1]

mov r1, #0x3c

ldr r0, [r1]

cmp r0, #0

bne relocate  //不相等,則是從nor啟動

ldr r0, =(0xdeadbeef)//相等的話是nand啟動,把之前那個 0x4000003C上的資料還原

ldr r1, =( (4<<28)|(3<<4)|(3<<2) )

str r0, [r1]

#define LENGTH_UBOOT 0x60000

#define NAND_CTL_BASE 0x4E000000

#ifdef CONFIG_S3C2440

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD  0x08

#define oNFSTAT 0x20

@ reset NAND

//初始化nand 

mov r1, #NAND_CTL_BASE

ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

str r2, [r1, #oNFCONF]

ldr r2, [r1, #oNFCONF]

ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control 

str r2, [r1, #oNFCONT]

ldr r2, [r1, #oNFCONT]

ldr r2, =(0x6) @ RnB Clear

str r2, [r1, #oNFSTAT]

ldr r2, [r1, #oNFSTAT]

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, #0x4

beq nand2

ldr r2, [r1, #oNFCONT]

orr r2, r2, #0x2 @ Flash Memory Chip Disable

str r2, [r1, #oNFCONT]

@ 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  //調用C函數把代碼從NAND拷貝到記憶體

ldr r0, =TEXT_BASE   //目的位址U-BOOT加載到記憶體的位址

mov r1, #0x0         //源位址//從0位址開始搬

mov r2, #LENGTH_UBOOT  //長度 算一下U-BOOT的長度

bl nand_read_ll    //跳到這個函數裡面去執行搬運

//傳回成功傳回給R0;

tst r0, #0x0     //拷貝成功傳回0

beq ok_nand_read//傳回成功

bad_nand_read:    //拷貝不成功則停在這裡

loop2://搬運失敗;根據傳回值是0-成功,非0失敗

b loop2 @ infinite loop

//傳回成功還要進行校驗

ok_nand_read:      //從0位址和TEXT_BASE分别取0x400内容出來對比驗證

@ 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//不相等,搬運有問題,跳到loop3

subs r2, r2, #4

beq stack_setup//搬完,跳回設定堆棧

bne go_next

notmatch://不相等

loop3:

b loop3 @ infinite loop

#endif

#ifdef CONFIG_S3C2410

#define oNFCONF 0x00

#define oNFCMD 0x04

#define oNFSTAT 0x10

@ 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

mov r1, #0x0

mov r2, #LENGTH_UBOOT

bl nand_read_ll  //跳到C語言那邊去搬運

tst r0, #0x0 //因為我們c那邊成功的話,傳回0,如果相等,則成功。

beq ok_nand_read

bad_nand_read:  //拷貝不成功

loop2:

b loop2 @ infinite loop 死循環

ok_nand_read: //搬運成功

//把nand flash 前面的一小段代碼加載出來和加載到記憶體裡面的内容進行比較。

                  ;//校驗其中一部分代碼

@ 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   // r2為測試部分的大小 r2=0x400

beq stack_setup   //跳到堆棧設定處 //搬運完

bne go_next //未搬完,繼續搬

notmatch:

loop3:

b loop3 @ infinite loop

#endif

//位址修正

relocate:

ldr r1, =(0xdeadbeef)

cmp r0, r1

bne loop3

adr r0, _start

ldr r1, _TEXT_BASE

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

//設定堆棧

stack_setup:

ldr r0, _TEXT_BASE

//預留一部分位址用來存放變量

sub r0, r0, #CONFIG_SYS_MALLOC_LEN

//@CFG_MALLOC_LEN=128*1024+CFG_ENV_SIZE=128*[email protected]=192K

sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)   

#endif

sub sp, r0, #12

//該部分将未初始化資料段_bss_start----_bss_end中的資料清零

//u-boot.lds

//清楚BSS段

clear_bss:

ldr r0, _bss_start //u-boot.lds

ldr r1, _bss_end

mov r2, #0x00000000

clbss_l:str r2, [r0]

add r0, r0, #4

cmp r0, r1

ble clbss_l

//跳到階段二C語言中去

//這邊的ldr是指令,加載内容,僞指令,加載位址

ldr pc, _start_armboot//加載_start_armboot的内容。===_start_armboot的内容又是start_armboot

#if defined(CONFIG_MINI2440_LED)

#define GPIO_CTL_BASE 0x56000000

#define oGPIO_B 0x10

#define oGPIO_CON 0x0

#define oGPIO_DAT 0x4

#define oGPIO_UP 0x8

mov r1, #GPIO_CTL_BASE

add r1, r1, #oGPIO_B

ldr r2, =0x295551

str r2, [r1, #oGPIO_CON]

mov r2, #0xff

str r2, [r1, #oGPIO_UP]

ldr r2, =0x1c1

str r2, [r1, #oGPIO_DAT]

#endif

_start_armboot: .word start_armboot

#define STACK_BASE 0x33f00000

#define STACK_SIZE 0x10000

.align 2

DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 

//主要設定CP15,禁止MMU。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

//初始化cache 

mov r0, #0

mcr p15, 0, r0, c7, c7, 0  //C7高速緩存和寫緩存控制

mcr p15, 0, r0, c8, c7, 0  //C8 TLB控制(存儲保護和控制)

//關閉MMU

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   //r0=****,****,****,****,**01,**00,0***,*010

mcr p15, 0, r0, c1, c0, 0

     //C1是一個控制寄存器,它控制MMU(MPU)的使能,資料Cache或統一Cache的使能,指令Cache的使能,寫緩沖使能等

//設定記憶體區控制期。具體值由廠商或硬體工程師提供。在UBOOT中的設定檔案是

//board/gec2440/lowlevel_init.S

//先儲存之前的lr,防止在BL時,lr把之前的覆寫掉了

mov ip, lr          //從子程式跳到孫程式 呵呵

bl lowlevel_init

mov lr, ip

mov pc, lr

#endif

@

@ IRQ stack frame.    //  這些定義個别沒用到,發生異常時,ro r1 r2等現場保護的偏移量。如.macro bad_save_user_regs有使用

@

#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

// ;儲存中斷前的r0-r12,sp_SVC, lr_SVC, pc, cpsr

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

sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)

sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)

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 r7, sp, #S_PC

stmdb r7, {sp, lr}^ @ Calling SP, LR

str lr, [r7, #0] @ Save calling PC

mrs r6, spsr

str r6, [r7, #4] @ Save CPSR

str r0, [r7, #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

.endm

//;以_armboot_start為基址,向下作為堆棧,存放lr,spsr

.macro get_bad_stack

ldr r13, _armboot_start @ setup our mode stack

sub r13, r13, #(CONFIG_STACKSIZE)

sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)

sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)

str lr, [r13] @ save caller lr / spsr

mrs lr, spsr

str lr, [r13, #4]

mov r13, #MODE_SVC @ //prepare SVC-Mode  10011  把spsr設定為SVC-Mode

@ msr spsr_c, r13

msr spsr, r13

mov lr, pc   @//把下下個指令給lr

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        ;macro

bad_save_user_regs   ;macro

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:

//Apollo +

        sub    lr, lr, #4             @ the return address

        ldr    sp, IRQ_STACK_START     @ the stack for irq

       stmdb   sp!,  { r0-r12,lr }     @ save registers

        ldr    lr, =int_return         @ set the return addr

        ldr    pc, =IRQ_Handle         @ call the isr

int_return:

        ldmia  sp!, { r0-r12,pc }^    @ return from interrupt

//Apollo -

.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

繼續閱讀