arm:啟動代碼判斷是從nand啟動還是從norflash啟動,拷貝程序到內存的過程


一、nand啟動和nor啟動:[1]

  CPU從0x00000000位置開始運行程序。

  1、nand啟動:

  如果將S3C2440配置成從NANDFLASH啟動(將開發板的啟動開關拔到nand端,此時OM0管腳拉低)S3C2440的Nand控制器會自動把Nandflash中的前4K代碼數據搬到內部SRAM中(地址為0x40000000),同時還把這塊SRAM地址映射到了0x00000000地址CPU從0x00000000位置開始運行程序。 

  2、如果將S3C2440配置成從Norflash啟動(將開發的啟動開關拔到nor端,此時OM0管腳拉高),0x00000000就是norflash實際的起始地址,norflash中的程序就從這里開始運行,不涉及到數據拷貝和地址映射

  3、總結:

  nand啟動時,地址0x00000000為內部SRAM映射的地址;

  nor啟動時,地址0x00000000為norflash的實際起始地址。

  向Norflash中寫數據需要特定的命令時序,而向內存中寫數據可以直接向內存地址賦值。

 

二、判斷是從nand啟動還是從norflash啟動:

1.根據硬件接線,

  引腳OM1、OM0  :  00: Nand-boot 01: 16-bit 10: 32-bit 11: Test mode

  

  總線寬度和等待控制寄存器(BWSCON)0x48000000      BWSCON_bit[2:1] Indicate data bus width for bank 0 (read only).

  The states are selected by OM[1:0] pins 。(01 = 16-bit, 10 = 32-bit  ...)

 

what's done before copy?

ResetHandler
    ;WTCON  watch dog disable
    ;INTMSK
    ;INTSUBMSK
    ;To reduce PLL lock time, adjust the LOCKTIME register.
    ;Setting value Fclk:Hclk:Pclk
    ;Configure UPLL 
    ;Configure MPLL
    ;Check if the boot is caused by the wake-up from SLEEP mode.
      ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler.
    ;Set memory control registers
    ;Initialize stacks
    bl    InitStacks 
 ; Setup IRQ handler
    ldr r0,=HandleIRQ ;This routine is needed
    ldr    r1,=IsrIRQ    ;if there isn t 'subs pc,lr,#4' at 0x18, 0x1c
    str    r1,[r0]

now copy:

;===========================================================
;// 判斷是從nor啟動還是從nand啟動
;===========================================================
    ldr    r0, =BWSCON
    ldr    r0, [r0]
    ands    r0, r0, #6                ;0110
    bne    NORRoCopy                  ;BWSCON的[2:1]反映了外部引腳OM[1:0].
                                    ;bne:若OM[1:0] != 00, 是從NOR FLash啟動.  
                                    ;若OM[1:0]==00,則為Nand Flash Mode.

NandFlashMode
    adr    r0, ResetEntry        ;注意adr得到的是相對地址,非絕對地址.    Cpu剛啟動時,ResetEntry==0.
    cmp    r0, #0                ;再比較入口是否為0地址處 
    bne    InitRamZero           ;如果不是0,直接初始化bss段,進入CEntry.
    ;nop
    
    
;===========================================================
;如果ResetEntry==0,說明是cpu剛啟動(注意此處是nand啟動),那就應該將nand中的代碼搬運到sdram中。
;===========================================================
nand_boot_beg
    bl    ClearSdram             ;將內存清零。從內存起始地址--->指定的足夠大的范圍,不超過內存的實際大小。
    
    mov    r5, #NFCONF            ;nand控制器初始化    
    ;set clk value
    ldr    r0,    =(7<<12):OR:(7<<8):OR:(7<<4)
    str    r0,    [r5]
    ;enable control
    ldr    r0, =(0<<13):OR:(0<<12):OR:(0<<10):OR:(0<<9):OR:(0<<8):OR:(1<<6):OR:(1<<5):OR:(1<<4):OR:(1<<1):OR:(1<<0)
    str    r0, [r5, #4]
    
    bl    ReadNandID            ;讀nandId,從而判斷nand芯片的種類. r5 = nandId
    mov    r6, #0
    ldr    r0, =0xecF1
    cmp    r5, r0
    beq    %F1                    ;if(nandId==0xecf1){r6=0;//addr_cycle=4}else{r6=1;//addr_cycle=5}
    mov    r6, #1                ;Nandaddr(尋址周期 0:4  1:5)
1    
    bl    ReadNandStatus        ;r1 = ret_of_ReadNandStatus ,這里似乎沒有用。
    
    mov        r8, #0                ;page_addr = r8 = 0;
    ldr        r9, =ResetEntry        ;r9 = size_copyed = pBuff = 0;
    mov        r10,#64             ;+081010 feiling     nPages_need_to_copy=64(128KB);
2    
    ands    r0, r8, #0x3f        ;R0 = R8 & 0X3F ; 如果是第一頁(mov r8, #0),本式子equal 0;
    bne        %F3                  
    mov        r0, r8                ;如果是第一頁,則檢測壞塊
    bl        CheckBadBlk            ;unsigned int CheckBadBlk(unsigned int    page_addr)
    cmp        r0, #0        
    addne    r8, r8, #64            ;每塊的頁數 r8 同時也做計數用。 
    addne    r10,r10,#64         ;+081010 feiling  if(is_bad_block){page_addr+=64;nPages_need_to_copy+=64;}
    bne        %F4
3    
    mov    r0, r8
    mov    r1, r9           ;r1 = r9 = size_copyed 
    bl    ReadNandPage 
    add    r9, r9, #2048    ;size_copyed+=2048
    add    r8, r8, #1       ;page_addr+1
4    
    cmp    r8, r10           ;要拷貝的頁數 081010 pht .  if(page_addr < nPages_need_to_copy ){copy_loop;}
    bcc    %B2
    
    mov    r5, #NFCONF        ;DsNandFlash
    ldr    r0, [r5, #4]
    bic r0, r0, #1
    str    r0, [r5, #4]
    
    ldr    pc, =InitRamZero    ;此處跳轉到內存空間 LDR 裝載數據,尋址靈活。 但不改變PSR
                            ;要裝載一個被存儲的‘狀態’並正確的恢復它 可以這樣寫:ldr r0, [base] 換行  moves pc, r0
;=============================================================================================
;若是從NAND啟動,則先清零內存,再從nand[0 ~ user_set_size]拷貝到內存(ro 和.data),再初始化bss段,進入main。
;若是從NOR啟動,同樣是先清零,后拷貝,再初始化bss段,進入main。為了考慮jlink等調試的情況,避免二次拷貝,才使代碼顯得復雜。
;其實可以不管,直接全部拷貝過來,nor拷貝比nand拷貝更簡單,逐個字節復制即可。
;============================================================================================= NORRoCopy ;copy_proc_from_nor_to_sdram bl ClearSdram ;clear all sdram needed adr r0, ResetEntry ;判斷是否在ROM中運行,ROM即RO指定的地址,從NOR啟動時ResetEntry為0 ldr r2, BaseOfROM ;如果相等,說明是jlink調試,調試器將程序.ro段直接下載到了內存,就不需再拷貝。 cmp r0, r2 ;pFrom = r0 = ResetEntry(活的) ; pTo = r2 = BaseOfROM(鏈接文件寫死的) ;pEnd = TopOfROM(鏈接文件寫死的) beq NORRwCopy ;if(ResetEntry==BaseOfROM){skip RoCopyLoop ,directly do RwCopy;} RoCopyLoop                 ldr r3, TopOfROM ; 0 ldmia r0!, {r4-r7} stmia r2!, {r4-r7} ;mem_ResetEntry----> mem_BaseOfROM ; pFrom+=4;pTo+=4; cmp r2, r3 ;if(pTo<pEnd){copy_loop;} bcc %B0 NORRwCopy            ;拷貝.data段(已初始化的全局變量、靜態變量等),它在固件里占有空間。   ldr r0, TopOfROM ;根據鏈接文件sct, TopOfROM == BaseOfRW ldr r1, BaseOfROM ; sub r0, r0, r1 ;pFrom = r0 = (TopOfROM - BaseOfROM) ldr r2, BaseOfRW ;pTo = BaseOfRW ,pEnd = BaseOfZero ldr r3, BaseOfZero 0 cmp r2, r3 ;if(r2<r3){ ldrcc r1, [r0], #4 ; r1 = [r0] ; r0+=4; strcc r1, [r2], #4 ; [r2] = r1 ; r2+=4; ;} bcc %B0
                InitRamZero
;初始化Bss段,之后立即進入CEntry mov r0, #0   ldr r2, BaseOfZero ldr r3, EndOfBSS 1 cmp r2, r3 ;清零bss段,bss段(未初始化的全局變量、靜態變量)在bin文件中不占空間,只有占位符,因此需要在系統初始化時,手動初始化(一般memset為0); strcc r0, [r2], #4 bcc %B1 ldr pc, =CEntry ;goto compiler address CEntry bl Main ;Don t use main() because ...... b .

 

ClearSdram:在拷貝程序到內存之前,先清內存。

;=========================================================
ClearSdram
    mov r1,#0
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
    mov r6,#0
    mov r7,#0
    mov r8,#0
    
    ldr    r9,=0x00700000   ;size of ram to clear
    ldr    r0,=0x30000000
0    
    stmia    r0!,{r1-r8}
    subs    r9,r9,#32 
    bne    %B0
    BX lr

 

 2、根據 “向norflash寫入數據需要一定的命令序列,而向內存中寫數據可以直接向內存地址賦值” 這一點來區別:

//int bBootFrmNORFlash(void) : 判斷是否從norflash啟動。
//ret==1 :norflash啟動
//ret==0 :nandflash啟動。(或者是jlink調試的情況。)
//說明:該函數應用范圍有限,只針對於bootloader最初的stage1。
int bBootFrmNORFlash(void)
{
    volatile unsigned int *pdw = (volatile unsigned int *)0;  //volatile
    unsigned int dwVal;
    
    /*
     * 無論是從NOR Flash還是從NAND Flash啟動,
     * 地址0處為指令"b    Reset", 機器碼為0xEA00000B,
     * 對於從NAND Flash啟動的情況,其開始4KB的代碼會復制到CPU內部4K內存中,
     * 對於從NOR Flash啟動的情況,NOR Flash的開始地址即為0。
     * 對於NOR Flash,必須通過一定的命令序列才能寫數據,
     * 所以可以根據這點差別來分辨是從NAND Flash還是NOR Flash啟動:
     * 向地址0寫入一個數據,然后讀出來,如果沒有改變的話就是NOR Flash
     * 這僅僅針對於初始階段,norflash啟動時,最終也要將程序加載到SDRAM中運行。因此該函數應用范圍是有局限性的。
     */

    dwVal = *pdw;       
    *pdw = 0x12345678;
    if (*pdw != 0x12345678)
    {
        return 1;
    }
    else
    {
        *pdw = dwVal;//測試完后要還原數據。
        return 0;
    }
}

 參考:
1、uboot如何檢測XC2440是從Nand或Nor啟動 http://blog.chinaunix.net/uid-22030783-id-3347621.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM