uboot-1.3.0-rc3引導啓動學習筆記

在分析啓動代碼之前先看一下S3C2440的NAND啓動:
在配置NAND啓動模式之後,S3C2440上電會先將NAND中的0x0 - 0x1000共4096字節的數據拷貝到位於Bank0中的Boot Internal SRAM上
Bank0如下圖:

 

可以看出Boot Internal SRAM爲4KB大小,也正是因爲Boot Internal SRAM只有4KB大小,所以只能從NAND中拷貝4K的內容 = 3= 這個Boot Internal SRAM是配置爲NAND FLASH啓動模式纔有的
這4K內容是什麼呢?~ 這就要看Uboot的鏡像文件中是如何進行連接的了~
連接腳本在board/smdk2440/u-boot.lds中,如下
SECTIONS
{
    . = 0x00000000;
    . = ALIGN(4);
    .text :
    {
     cpu/arm920t/start.o    (.text)
     cpu/arm920t/s3c24x0/nand_read.o (.text)
     *(.text)
    }
    . = ALIGN(4);
    .rodata : { *(.rodata) }
    . = ALIGN(4);
    .data : { *(.data) }
    . = ALIGN(4);
    .got : { *(.got) }
    . = .;
    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;
    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) }
    _end = .;
}
.text爲代碼段,可以看出cpu/arm920t/start.o在代碼段的最前面,所以會先執行start.o中的代碼
連接完成後的鏡像文件的前4K如下
cpu/arm920t/start.o(.text)
.text 0x33f80000 0x4e0 cpu/arm920t/start.o
                0x33f80050 IRQ_STACK_START
                0x33f80048 _bss_start
                0x33f8004c _bss_end
                0x33f80044 _armboot_start
                0x33f80000 _start
                0x33f80054 FIQ_STACK_START
cpu/arm920t/s3c24x0/nand_read.o(.text)
.text 0x33f804e0 0x1b8 cpu/arm920t/s3c24x0/nand_read.o
                0x33f804e0 nand_read_ll
*(.text)
.text 0x33f80698 0x64 board/smdk2440/libsmdk2440.a(lowlevel_init.o)
                0x33f8069c lowlevel_init
.text 0x33f806fc 0x280 cpu/arm920t/libarm920t.a(interrupts.o)
                0x33f80934 do_fiq
                0x33f80880 do_undefined_instruction
                0x33f80744 show_regs
                0x33f80958 do_irq
                0x33f80728 bad_mode
                0x33f808c8 do_prefetch_abort
                0x33f8070c disable_interrupts
                0x33f80910 do_not_used
                0x33f808ec do_data_abort
                0x33f808a4 do_software_interrupt
                0x33f806fc enable_interrupts
.text 0x33f8097c 0x250 cpu/arm920t/s3c24x0/libs3c24x0.a(interrupts.o)
                0x33f80aa4 set_timer
                0x33f80a20 reset_timer
                0x33f8097c interrupt_init
                0x33f80ba0 get_tbclk
                0x33f80a90 get_timer
                0x33f809f0 reset_timer_masked
                0x33f80a24 get_timer_masked
                0x33f80ab4 udelay
                0x33f80b10 udelay_masked
                0x33f80bac reset_cpu
                0x33f80b8c get_ticks
.text 0x33f80bcc 0x150 cpu/arm920t/s3c24x0/libs3c24x0.a(speed.o)
                0x33f80c4c get_HCLK
                0x33f80cec get_PCLK
                0x33f80c44 get_FCLK
                0x33f80d14 get_UCLK
.text 0x33f80d1c 0x1e8 cpu/arm920t/s3c24x0/libs3c24x0.a(cmd_s3c24xx.o)
                0x33f80d8c do_s3c24xx
.text 0x33f80f04 0xdc cpu/arm920t/s3c24x0/libs3c24x0.a(serial.o)
                0x33f80f04 serial_setbrg
                0x33f80fa8 serial_tstc
                0x33f80f80 serial_putc
                0x33f80f58 serial_init
                0x33f80fb8 serial_puts
                0x33f80f68 serial_getc
.text 0x33f80fe0 0x140 lib_arm/libarm.a(_divsi3.o)
                0x33f80fe0 __divsi3
如何設置從0x33f80000開始呢?~這是鏈接的時候指定的
在根目錄下面的config.mk中有下面一句
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
關鍵就是其中的-Ttext $(TEXT_BASE),這句指明瞭代碼段的起始地址
而TEXT_BASE在board/smdk2440/config.mk中定義 TEXT_BASE = 0x33F8 0000
爲什麼是0x33F8 0000呢?~
這是將NAND中Uboot拷貝到RAM中的起始地址,所以在代碼拷貝到RAM之前不能使用絕對地址來尋址數據,只能用相對地址
在以下將用虛擬地址來指Uboot在RAM中的地址,也就是0x33F8 0000
現在來看代碼cpu/arm920t/start.S
_start:    ;異常處理向量表
    b start_code
    ldr    pc, _undefined_instruction   ;未定義指令異常:0x00000004
    ldr    pc, _software_interrupt  ;軟中斷異常:0x00000008
    ldr    pc, _prefetch_abort  ;預取異常:0x0000000C
    ldr    pc, _data_abort  ;數據異常:0x00000010
    ldr    pc, _not_used  ;未使用:0x00000014
    ldr    pc, _irq  ;外部中斷請求IRQ:0x00000018
    ldr    pc, _fiq  ;快束中斷請求FIQ:0x0000001C
b  start_code在虛擬地址0x33F8 0000處 , 拷貝到Boot Internal SRAM後則位於0x0處,所以b  start_code是第一條執行的指令,
start_code在cpu/arm920t/start.S中
代碼如下:
    //讀取CPSR寄存器的內容到R0
    mrs    r0,cpsr
    //清除R0中的0 - 4 這5個位後保存到R0中
    //也就是清除用戶模式位
    bic    r0,r0,#0x1f
    //置R0的0 1 4 6 7 位爲真
    //也就是選擇SVC模式,同時IRQ和FIQ被禁止,處理器處於ARM狀態
    //關閉中斷和快速中斷
    orr    r0,r0,#0xd3
    //將R0中的值保存到CPSR上
    msr    cpsr,r0
# define pWTCON        0x53000000  ;看門狗控制寄存器WTCON
# define INTMSK        0x4A000008  ;中斷屏蔽寄存器INTMSK
# define INTSUBMSK    0x4A00001C  ;輔助中斷屏蔽寄存器,由於外設中斷源太多,要用此寄存器屏蔽剩餘的中斷源
# define LOCKTIME    0x4c000000  ;PLL鎖定時間計數寄存器
# define MPLLCON     0x4c000004  ;主時鐘鎖相環控制寄存器
# define UPLLCON     0x4c000008
# define CLKDIVN    0x4C000014    ;時鐘分頻寄存器/* clock divisor register */
# define INTSUBMSK_val    0xffff
# define MPLLCON_val    ((184  12) + (2  4) + 2)    /*406M*/
# define UPLLCON_val     ((60  12) + (4  4) + 2) /* 47M */
# define CLKDIVN_val    7 /* FCLK:HCLK:PCLK = 1:3:6 */
# define CAMDIVN    0x4C000018
    //取得看門狗寄存器的地址
    ldr r0, =pWTCON
    //將R1寄存器清0
    mov r1, #0x0
    //將看門狗寄存器清0,即將看門狗禁止,包括定時器定時,溢出中斷及溢出復位等
    str r1, [r0]
    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    //設R1寄存器爲0xFFFF FFFF
    mov    r1, #0xffffffff
    //讀取中斷屏蔽寄存器的地址
    ldr    r0, =INTMSK
    //將中斷屏蔽寄存器中的位全設1,屏蔽所有中斷
    str    r1, [r0]
    //# define INTSUBMSK_val    0xffff
    //設R1寄存器爲0xFFFF
    ldr    r1, =INTSUBMSK_val
    //讀取輔助中斷屏蔽寄存器的地址
    ldr    r0, =INTSUBMSK
    //將輔助中斷屏蔽寄中的11箇中斷信號屏蔽掉,本人覺得INTSUBMS_val應設成7ff
    str    r1, [r0]
    //# define LOCKTIME    0x4c000000
    //讀取PLL鎖頻計數器寄存器地址到R0中
    ldr r0,=LOCKTIME
    //將R1設爲0x00FF FFFF
    ldr r1,=0xffffff
    //M_LTIME爲最大的0xFFF
    //U_LTIME爲最大的0xFFF
    str r1,[r0]    ;0xfff=4096>1800,遠遠滿足鎖定要求
    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    //# define CLKDIVN    0x4C000014    /* clock divisor register */
    //讀取時鐘分頻寄存器的地址
    ldr    r0, =CLKDIVN
    //# define CLKDIVN_val    7 /* FCLK:HCLK:PCLK = 1:3:6 */
    //將R1設爲0x7
    mov    r1, #CLKDIVN_va
    //PDIVN - 1: PCLK has the clock same as the HCLK/2.
    //HDIVN - 11 : HCLK = FCLK/3 when CAMDIVN[8] = 0.
    // HCLK = FCLK/6 when CAMDIVN[8] = 1.
    str    r1, [r0]
    /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */
    //# define CAMDIVN    0x4C000018
    //讀取攝像頭時鐘分頻寄存器的地址
    ldr r0, =CAMDIVN
    //將R1設爲0
    mov r1, #0
    //將攝像頭時鐘分頻寄存器清0
    str r1, [r0]
    /* Clock asynchronous mode */
    //MRC p15, 0, Rd, c1, c0, 0 ; read control register
    //讀取控制寄存器中的值到R1中
    mrc p15, 0, r1, c1, c0, 0  ;將協處理器p15的寄存器c1和c0的值傳到arm處理器的R1寄存器中
    //31 iA bit Asynchronous clock select
    //30 nF bit notFastBus select
    orr r1, r1, #0xc0000000  ;將最高兩位置1
    //MCR p15, 0, Rd, c1, c0, 0 ; write control register
    //將R1中的值寫到控制寄存器中
    mcr p15, 0, r1, c1, c0, 0 將arm的寄存器R1的32位數據傳到協處理器p15的兩個16位寄存器c1和c0
    //# define UPLLCON     0x4c000008
    //讀取UPLL設置寄存器的地址到R0中
    ldr    r0,=UPLLCON
    //# define UPLLCON_val     ((60
    ldr    r1,=UPLLCON_val
    //將R1中的值寫入UPLL設置寄存器中
    str    r1,[r0]
    //ARM920T爲5級流水線,需要至少5個週期來讓指令生效
    nop   
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    //讀取MPLL設置寄存器的地址到R0中   
    ldr    r0,=MPLLCON
    //# define MPLLCON_val    ((184
    ldr    r1,=MPLLCON_val
    //將R1中的值寫入MPLL設置寄存器中
    str    r1,[r0]
#define GPJCON 0x560000D0
#define GPJDAT 0x560000D4
#define GPJUP             0x560000D8
    //跳轉到cpu_init_crit處執行
    //並將下一條指令的地址寫入LR寄存器中
    bl    cpu_init_crit
cpu_init_crit在cpu/arm920t/start.S中
代碼如下:
cpu_init_crit:
    /*
     * flush v4 I/D caches
     */
    //將R0寄存器置0
    mov    r0, #0
    //Invalidate ICache and DCache SBZ MCR p15,0,Rd,c7,c7,0
    //禁止指令和數據cache
    mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */
    //Invalidate TLB(s) SBZ MCR p15,0,Rd,c8,c7,0
    mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */
    /*
     * disable MMU stuff and caches
     */
    //MRC p15, 0, Rd, c1, c0, 0 ; read control register
    mrc    p15, 0, r0, c1, c0, 0
    //清除[8] [9] [13] 這3個位
    //8 - System protection
    //9 - ROM protection
    //13 - Base location of exception registers - 0 = Low addresses = 0x00000000.
    bic    r0, r0, #0x00002300    // clear bits 13, 9:8 (--V- --RS)
    //清除[0] [1] [2] [7] 這4個位
    // 0 - MMU enable - 0 = MMU disabled.
    // 1 - Alignment fault enable - 0 = Fault checking disabled.
    // 2 - DCache enable - 0 = DCache disabled.
    // 7 - Endianness - 0 = Little-endian operation.
    bic    r0, r0, #0x00000087    // clear bits 7, 2:0 (B--- -CAM)
    //設置位[1]爲真
    // 1 - Alignment fault enable - 1 = Fault checking enabled.
    orr    r0, r0, #0x00000002    // set bit 2 (A) Align
    //設置位[12]爲真
    //12 - ICache enable - 1 = ICache enabled.
    orr    r0, r0, #0x00001000    // set bit 12 (I) I-Cache
    //MCR p15, 0, Rd, c1, c0, 0 ; write control register
    mcr    p15, 0, r0, c1, c0, 0
    //將返回地址保存到IP中
    mov    ip, lr
    //跳轉到lowlevel_init中執行
    bl    lowlevel_init
cpu_init_crit在cpu/arm920t/start.S中
代碼如下:
.globl lowlevel_init
    //讀取下面標號爲SMRDATA處的地址到R0中
    ldr r0, =SMRDATA
    //讀取上面標號爲_TEXT_BASE處的地址內容到R1中
    //也就是取得TEXT_BASE的值到R1中
    ldr    r1, _TEXT_BASE
    //計算SMRDATA的相對地址保存到R0中
    //SMRDATA爲虛擬地址,而TEXT_BASE爲虛擬地址的起始地址
    //而現在Uboot的起始地址並不爲虛擬地址
    //TEXT_BASE爲0x33F8 0000,SMRDATA爲0x33F8 06C8
    //而現在程序運行在起始地址爲0x0000 0000的地方
    //所以需要計算以0x0000 0000爲標準的相對地址
    sub    r0, r0, r1
    //取得帶寬與等待狀態控制寄存器地址到R1中
    ldr    r1, =BWSCON    /* Bus Width Status Controller */
    //一共需要設置13個寄存器,每個寄存器4字節
    add r2, r0, #13*4
0:
    //讀取R0所指的項的值到R3中後R0自加4字節
    ldr r3, [r0], #4
    //將R3中的值保存到R1所指的地址中後R1自加4字節
    str r3, [r1], #4
    //比較R0和R2是否相等,相等則說明13個寄存器全部設置完畢
    cmp r2, r0
    //不等則跳轉到上面標號爲0處的地址繼續執行
    bne 0b
    //跳回到返回地址中繼續執行
    mov    pc, lr
    .ltorg
/* the literal pools origin */
SMRDATA:
    .word (0+(B1_BWSCON4)+(B2_BWSCON8)+(B3_BWSCON12)+(B4_BWSCON16)+(B5_BWSCON20)+(B6_BWSCON24)+(B7_BWSCON28))
    .word ((B0_Tacs13)+(B0_Tcos11)+(B0_Tacc8)+(B0_Tcoh6)+(B0_Tah4)+(B0_Tacp2)+(B0_PMC))
    .word ((B1_Tacs13)+(B1_Tcos11)+(B1_Tacc8)+(B1_Tcoh6)+(B1_Tah4)+(B1_Tacp2)+(B1_PMC))
    .word ((B2_Tacs13)+(B2_Tcos11)+(B2_Tacc8)+(B2_Tcoh6)+(B2_Tah4)+(B2_Tacp2)+(B2_PMC))
    .word ((B3_Tacs13)+(B3_Tcos11)+(B3_Tacc8)+(B3_Tcoh6)+(B3_Tah4)+(B3_Tacp2)+(B3_PMC))
    .word ((B4_Tacs13)+(B4_Tcos11)+(B4_Tacc8)+(B4_Tcoh6)+(B4_Tah4)+(B4_Tacp2)+(B4_PMC))
    .word ((B5_Tacs13)+(B5_Tcos11)+(B5_Tacc8)+(B5_Tcoh6)+(B5_Tah4)+(B5_Tacp2)+(B5_PMC))
    .word ((B6_MT15)+(B6_Trcd2)+(B6_SCAN))
    .word ((B7_MT15)+(B7_Trcd2)+(B7_SCAN))
    .word ((REFEN23)+(TREFMD22)+(Trp20)+(Trc18)+(Tchr16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30
執行mov  pc, lr後將返回到cpu_init_crit中
剩下來還有2條指令
    //恢復返回地址到LR
    mov    lr, ip
    //跳轉到返回地址
    mov    pc, lr
執行完畢之後將返回到start_code中執行接下來的代碼
代碼如下:
        //#define GPJCON 0x560000D0
        //取得J端口控制寄存器的地址到R0中
        LDR R0, = GPJCON
        //將R1設置爲0x1 5555
        LDR R1, = 0x15555
        //將R1中的值保存到J端口控制寄存器
        //GPJ0 - 01 - Output
        //GPJ1 - 01 - Output
        //GPJ2 - 01 - Output
        //GPJ3 - 01 - Output
        //GPJ4 - 01 - Output
        STR R1, [R0]
        //#define GPJUP        0x560000D8
        //取得J端口上拉功能寄存器的地址到R0中
        LDR R0, = GPJUP
        //將R1設置爲0x1F
        LDR R1, = 0x1f
        //將R1中的值保存到J端口上拉功能寄存器
        //禁止GPJ0 - GPJ4的上拉功能
        STR R1, [R0]
        //#define GPJDAT 0x560000D4
        //取得J端口數據寄存器的地址到R0中
        LDR R0, = GPJDAT
        //將R1設爲0x0
        LDR R1, = 0x00
        //將R1中的值保存到J端口數據寄存器
        //將J端口數據寄存器清0
        STR R1, [R0]
//下面是NAND數據拷貝過程
//relocate:
copy_myself:
    //#define S3C2440_NAND_BASE        0x4E000000
    //取得Nand Flash設置寄存器的地址
    mov    r1, #S3C2440_NAND_BASE
    //將R2設爲0xFFF0
    ldr    r2, =0xfff0        // initial value tacls=3,rph0=7,rph1=7
    //#define oNFCONF            0x00
    //讀取Nand Flash設置寄存器中的值到R3中
    ldr    r3, [r1, #oNFCONF]
    //將R3或上R2後保存到R3中
    orr    r3, r3, r2
    //將R3中的值保存到Nand Flash設置寄存器中
    //TWRPH0 - 111 - Duration = HCLK * (TWRPH0 + 1)
    //TACLS - 11 - Duration = HCLK * TACLS
    str    r3, [r1, #oNFCONF]
    //#define oNFCONT            0x04
    //讀取Nand Flash控制寄存器中的值到R3中
    ldr    r3, [r1, #oNFCONT]
    //將R3的[0]位置1
    orr    r3, r3, #1        // enable nand controller
    //將R3中的值保存到Nand Flash控制寄存器中
    //Mode - 1:Nand Flash Controller Enable
    str    r3, [r1, #oNFCONT]
    //讀取虛擬起始地址到R0中
    ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot */
    //預留malloc所需要的空間
    sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area */
    //預留bdinfo所需要的空間
    sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
    //預留中斷和快速中斷向量表空間
    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    //預留12字節給中斷棧
    sub    sp, r0, #12        /* leave 3 words for abort-stack */
    // copy u-boot to RAM
    //讀取虛擬起始地址到R0中,作爲目標地址
    ldr    r0, _TEXT_BASE
    //將R1設爲0,作爲源地址
    mov r1, #0x0
    //將UBOOT大小的值保存在R2中,作爲數據大小
    mov    r2, #CFG_UBOOT_SIZE
    //跳轉到nand_read_ll處執行
    //並將下一條指令的地址保存在LR中
    bl    nand_read_ll
nand_read_ll的原型爲
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
之前設置的R0 R1 R2爲它的3個參數
R0 - buf
R1 - start_addr
R2 - size
nand_read_ll的代碼在cpu/arm920t/s3c24x0/nand_read.c中
int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
    int i, j;
    //檢測源地址和大小是否在NandFlash的邊界上
    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
        //不在邊界上則返回-1表示出錯
        return -1;    /* invalid alignment */
    /* chip Enable */
    // #define nand_select()    (NFCONT &= ~(1
    //置NAND Flash控制寄存器中除Reg_nCE外所有的位爲1
    //Reg_nCE - NAND FLASH Memory nFCE signal control
    //0 - Force nFCE to low (Enable chip select)
    nand_select();
    // #define nand_clear_RnB()    (NFSTAT |= (1
    //置NAND Flash操作狀態寄存器中的RnB_TransDetect位爲1
    //When RnB low to high transition is occurred, this value set and issue interrupt if enabled.
    //To clear this value write '1'
    //1: RnB transition is detected
    nand_clear_RnB();
    for (i=0; i10; i++);
    //從源地址的首地址開始歷便所要拷貝的數據大小
    for (i=start_addr; i  (start_addr + size);)
    {
        //檢測地址是否在NAND Flash的邊界上
        if (start_addr % NAND_BLOCK_SIZE == 0)
        {
            //檢測是否爲壞塊
            if (is_bad_block(i))
            {
                /* Bad block */
                //向後延伸一個存儲塊
                i += NAND_BLOCK_SIZE;
                size += NAND_BLOCK_SIZE;
                //跳到下一塊
                continue;
            }
        }
        j = nand_read_page_ll(buf, i);
        //指向下一塊
        i += j;
        buf += j;
    //    LED_FLASH();
    }
    /* chip Disable */
    // #define nand_deselect()    (NFCONT |= (1
    //置Reg_nCE位爲1
    //NAND Flash Memory nFCE signal control
    //1: Force nFCE to High(Disable chip select)
    nand_deselect();
    return 0;
}
nand_read_ll將Uboot從NAND中拷貝到RAM中
拷貝完成後將返回到start_code
接下來的代碼如下:
    //檢測R0是否爲0,R0爲nand_read_ll的返回值
    tst    r0, #0x0
    //爲0則說明無錯,跳轉到ok_nand_read處執行
    beq    ok_nand_read
ok_nand_read:
    //將R0設爲0
    mov    r0, #0
    //ldr    r1, =0x33f00000
    //將R1設爲虛擬地址起始處
    ldr    r1, _TEXT_BASE
    //檢測0x400個字節
    mov    r2, #0x400    // 4 bytes * 1024 = 4K-bytes
go_next:
    //讀取R0處地址的數據到R3中
    //然後R0自加4字節
    ldr    r3, [r0], #4
    //讀取R1處地址的數據到R4中
    //然後R1自加4字節
    ldr    r4, [r1], #4
    //比較R3和R4的數據是否相等
    //也就是檢測Boot Internal SRAM和RAM中的數據是否相等
    //以保證數據無錯
    teq    r3, r4
    //不等則跳轉到notmatch
    bne    notmatch
    //相等則R2自減4
    subs    r2, r2, #4
    //當R2爲0則跳轉到done_nand_read
    beq    done_nand_read
    //R2不爲0則跳轉回go_next繼續檢測
    bne    go_next
done_nand_read:
    LDR R0, = GPJDAT
    LDR R1, = 0x2
    STR R1, [R0]
stack_setup:
    //讀取虛擬起始地址到R0中
    ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot */
    //預留malloc所需要的空間
    sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area */
    //預留bdinfo所需要的空間
    sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
    //預留中斷和快速中斷向量表空間
    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    //預留12字節給中斷棧
    sub    sp, r0, #12        /* leave 3 words for abort-stack */
clear_bss:
    //讀取BSS段的起始地址
    ldr    r0, _bss_start        /* find start of bss segment */
    //讀取BSS段的結束地址
    ldr    r1, _bss_end        /* stop here */
    //將R2設爲0x0
    mov     r2, #0x00000000        /* clear */
clbss_l:
    //將R2中的值保存在R0所指的地址
    str    r2, [r0]        /* clear loop... */
    //R0自加4字節
    add    r0, r0, #4
    //比較R0和R1是否相等
    cmp    r0, r1
    //不等則說明清0還沒結束
    ble    clbss_l
    LDR R0, = GPJDAT
    LDR R1, = 0x1
    STR R1, [R0]
    //跳轉到start_armboot處執行
    ldr    pc, _start_armboot
_start_armboot:    .word start_armboot
這裏start_armboot是一個絕對地址,在朗成所修改的這個Uboot中爲0x33F8 13F4
執行ldr pc, _start_armboot之後將會跳到RAM中的絕對地址繼續執行
整理了一個流程圖,分爲3個存儲器:
1 Boot Internal SRAM , 接在BANK0,起始地址爲0x0
2 RAM , 接在BANK6,起始地址爲0x3000 0000
3 NAND FLASH,爲單獨尋址
流程如下圖:

 

 

 

紅字爲流程序號:
1. 首先將NAND FLASH中的前0x1000字節內容拷貝到Boot Internal SRAM中
2. 從Boot Internal SRAM的0x0地址處開始執行指令
3. 將Uboot從Flash拷貝到RAM中
4. 執行ldr pc, _start_armboot
從Boot Internal SRAM中跳轉到RAM中的絕對地址0x33F8 13F4處繼續執行

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章