1. 程式人生 > >uboot.2015.07移植之從NAND Flash啟動(5)

uboot.2015.07移植之從NAND Flash啟動(5)

移植u-boot-2015.07之修改程式支援NAND Flash

1.為什麼要支援NAND Flash啟動

由於NAND Flash 的儲存空間大並且價格便宜(相對於 NOR Flash 來說),所以程式的儲存位置一般會放在 NAND FLash 裡面,雖然 NAND Flash 也有缺點,那就是容易發生位反轉,但是這並不妨礙 NAND Flash 的優勢,所以從 NAND Flash 啟動是非常有必要的。還有一個問題就是在 S3C2440 上電的時候,只會從 NAND Flash 的前面4K空間拷貝程式碼到記憶體空間裡面,這就導致了一些比較大的bootloader不能夠直接放入記憶體空間執行,而是由程式從 NAND Flash 裡面拷貝到記憶體空間裡面去執行

2.新增驅動函式

新增nand的讀函式,新增bss段的清零函式到單板目錄下面(建立init.c檔案,並且新增到單板目錄下的 makefile 檔案中去)。這個程式碼需要自己去實現,這裡不再贅述。

3.修改設定

  • 註釋掉 arch/arm/config.mk 裡面的82行 LDFLAGS_u-boot += -pie (我們使用自己的重定位函式,為了能夠從 nand flash 啟動)

  • 修改smdk2440.h裡面的 CONFIG_SYS_TEXT_BASE 為 0x33f00000,這個就是程式碼的連結地址

  • 把最開始要執行的程式碼都放在bin檔案的最前面,以防被編譯器編譯到4K空間之外,在 arch/arm/cpu/u-boot.lds 裡面修改,包括
    arch/arm/lib/built-in.o board/samsung/smdk2440/built-in.o。本版本u-boot將一個資料夾下面的c檔案都連結成一個.o檔案,名字為built-in.o,所以我們直接寫上built-in.o即可。要想將一個單獨的檔案放出來以供手動指定連結位置的話,把該檔案所在目錄下面的 Makefile 檔案中該檔案對應的obj-y選項改為 extra-y 即可

    ,這樣的話就可以在u-boot.lds裡面單獨指定一個c檔案的位置,這點檢視start.S檔案所在資料夾下面的Makefile就可以知道。另外把開頭的 #include <config.h> 給註釋掉,不然當你使用雙斜槓註釋掉板級檔案標頭檔案中的一些巨集定義的時候make會出現錯誤,主要就是根目錄下的 u-boot.lds 檔案頭部會出現一大堆註釋巨集定義,當然,出現錯誤的時候直接在生成的 u-boot.lds 檔案裡面刪除也是可以的,這裡為了方便就把它給註釋掉了

. = 0x00000000;

. = ALIGN(4);
.text :
{
        *(.__image_copy_start)
        *(.vectors
) CPUDIR/start.o (.text*) arch/arm/lib/crt0.o (.text*) arch/arm/lib/vectors.o (.text*) board/samsung/smdk2440/built-in.o (.text*) *(.text*) }

4.修改 board_init_f

注意:這裡說的board_init_f指的是board.c裡面的函式,而不是board_f.c裡面的函式
- 在crt0.S裡面進行程式碼的重定位,在board_init_f上面新增一個識別符號,例如:

bym_board_init_f:
    bl  board_init_f
/* 然後在上面進行程式碼的重定位,修改後如下所示 */
ldr r0, =_start
mov r1, #0
ldr r2, =__bss_start
sub r2, r2, r0

bl bym_copy2sdram

bym_board_init_f:
    bl  board_init_f
  • 在board_init_f裡面註釋掉
addr -= gd->mon_len;
addr &= ~(4096 - 1);

改為

addr = (ulong)&_start;  /* 指向程式碼段的開始,人為指定 */

5.修改重定位程式碼

在Crt0.S裡面註釋掉所有與程式碼重定位和清除bss段有關的程式碼,用自己的程式碼替換之,替換後的程式碼如下:

    ldr r0, =__image_copy_start
    mov r1, #0

    /* 為避免 __image_copy_start 等值錯誤而加的 */
    ldr r2, =__rel_dyn_start    /* r2 <- SRC &__rel_dyn_start */
    ldr r3, =__rel_dyn_end  /* r3 <- SRC &__rel_dyn_end */
    /* 為避免 __image_copy_start 值錯誤而加的 */

    ldr r2, =__image_copy_end
    sub r2, r2, r0

    bl bym_cpoy2sdram

    bl clear_bss

    ldr pc, =bym_board_init_f

bym_board_init_f:
    /* mov r0, #0 not needed due to above code */
    ldr r0,=0x00000000
    bl  board_init_f

6.測試

  1. 拷貝並覆蓋以上修改檔案到虛擬機器上面

  2. make smdk2440_defconfig

  3. make 這一步出現u-boot contains unexpected relocations.通過網上查詢資料,發現是編譯的時候有checkarmreloc選項,再次去arch/arm/config.mk裡面修改,註釋掉ALL-y += checkarmreloc,重新make。該行程式碼指的是檢測重定位資訊,我們把所有的重定位程式碼資訊都給註釋掉了(包括前面的編譯選項),所以這裡會出現錯誤。

悲劇

下載之後啟動不成功,檢視反彙編檔案,發現__bss_start的值並不是我們期望的在0x33f00000之後的一個值,而是0,這點顯然是不對的,而且在make的時候最後連結之後出現了奇怪的錯誤。這樣想來這一版本的u-boot還不單單是通過修改 CONFIG_SYS_TEXT_BASE 就可以達到完全改變程式連結地址的目的,此項擱置暫時轉為2012版本的移植,以後再來看這個版本的

轉機

我又回來了,上面說到反彙編之後檢視__bss_start的值不對,我百無聊賴之下把crt0.S裡面的官方重定位程式碼又加上了,重新編譯,__bss_start值變得正常了,下載到單板上面可以執行前面的串列埠初始化以及列印CPU資訊那裡。問題何在,我又一次去掉了系統原有重定位程式碼,再次編譯,__bss_start值再次不正常,然後我懷疑是重定位裡面程式碼有什麼貓膩,然後一點一點去掉重定位函式裡面的程式碼,我發現如果要是去掉了與u-boot.lds檔案裡面指定的__rel_dyn_start與__rel_dyn_end標號有關的程式碼__bss_start的值就會變得不正常。萬般無奈之下只得把這兩句程式碼搬移到crt0.S裡面自己實現的重定位程式碼之前如上面的程式碼,不影響重定位程式碼的引數值,又使用了這兩個標號,終於成功。然後我懷疑是編譯器的優化作用或是別的什麼地方有特殊的處理,總之非常奇怪,這點暫時擱置,現在已經實現了支援 nand flash 啟動的程式碼了

7.從 board_f.c 裡面啟動

然後我想從board_f.c裡面的board_init_f函式啟動,沒錯我就是這麼愛折騰。再次修改smdk2440.h裡面,還原 #define CONFIG_SYS_GENERIC_BOARD。更改board_init_f(board_f.c裡面的)函式裡面呼叫函式組裡面的reserve_uboot函式裡面的gd->relocaddr賦值語句

//  gd->relocaddr -= gd->mon_len;
//  gd->relocaddr &= ~(4096 - 1);
#ifdef CONFIG_E500
    /* round down to next 64 kB limit so that IVPR stays aligned */
    gd->relocaddr &= ~(65536 - 1);
#endif

    gd->relocaddr = (ulong)&__image_copy_start;

儲存覆蓋檔案到虛擬機器,重新make並且下載。程式成功執行到等待使用者輸入命令介面。