本文旨在闡述一些移植之前應該掌握的基本知識,參考:
http://home.eeworld.com.cn/my/space.php?uid=135723&do=blog&id=25347
1. 首先,U-Boot1.3.4還沒有支持s3c2440,移植仍是用2410的文件稍作修改而成的。
2. 2440和2410的區別:
2440和2410的區別主要是2440的主頻更高,增加了攝像頭接口和AC‘97音頻接口;寄存器方面,除了新增模 塊的寄存器外,移植所
要注意的是NAND FlASH控制器的寄存器有較大的變化、芯片的時鐘頻率控制寄存器(芯片PLL的寄存器)有一定的變化。其他寄存器
基本是兼容的。
3. 你開發板的boot方式是什麼,開發板上電以後是怎麼執行的。
一般來說三星的開發板有三種啓動方式:nand、nor、ram。
具體用那一種方式來啓動決定於CPU的0M[0:1]這兩個引腳,具體請參考S3C2440的datasheet
nand:對於2440來說,CPU是不給nand-flash分配地址空間的,nand-flash只相當於CPU的一個外設,S3C2440做了一個從nand-flash
啓動的機制。開發板一上電,CPU就自動複製
nand-flash裏面的前4K-Bytes內容到S3C2440內部集成的SDRAM,然後把4K內容所在 的RAM映射到S3C2440的0地址,從
0地址開始執行。這4K的內容主要負責下面這些工 作:初始化中斷矢量、設定CPU的工作模式爲SVC32模式、屏蔽看門狗、屏
蔽中斷、 初始化時鐘、把整個u-boot重定向到外部SDRAM、跳到主要的C函數入口。
nor: 早期的時候利用nor-flash啓動的方式比較多,就是把u-boot燒寫到nor-flash裏面, 直接把nor-flash映射到S3C2440
的0地址,上電從0地址開始執行。
ram: 直接把u-boot放到外部SDRAM上跑,這一般debug時候用到。
4. u-boot程序的入口地址問題
要理解程序的入口地址,自然想到的是連接文件,首先看看開發板相對於某個開發板的連接文件"/board/你的開發板/u-
boot.lds",看一個2410的例子:
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/arm920t/start.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 = .;
}
(1) 從ENTRY(_start)可以看出u-boot的入口函數是_start,這個沒錯
(2) 從. = 0x00000000也許可以看出_start的地址是0x00000000,事實並不是這樣的,這裏的0x00000000沒效,在連接的時候最終會
被TETX_BASE所代替的,具體請參考u-boot根目錄下的config.mk.
(3) 網上很多說法是 _start=TEXT_BASE,我想這種說法也是正確的,但沒有說具體原因。
本人的理解是這樣的,TEXT_BASE表示text段的起始地址,而從
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
看,放在text段的第一個文件就是start.c編譯後的內容,而start.c中的第一個函數就是
_start,所以 _start應該是放在text段的起始位置,因此說_start=TEXT_BASE也不爲過。
5. 一直不明白的U-BOOT是怎樣從4Ksteppingstone跳到RAM中執行的,現在終於明白了。關鍵在於:
ldr pc, _start_armboot
_start_armboot: .word start_armboot
這兩條語句,ldr pc, _start_armboot指令把_start_armboot這個標籤的地方存放的內容(也即是start_armboot)移到PC寄存
器裏面,start_armboot是一個函數地址,在編譯的時候給分配了一個絕對地址,所以上面語句實際上是完成了一個絕對地址的跳轉
。而我一直不明白的爲什麼在start.S裏面有很多BL,B跳轉語句都沒有跳出4Ksteppingstone,原因是他們都是相對於PC的便宜的跳轉
,而不是絕對地址的跳轉。還有要補充一下LDR,MOV,LDR僞指令的區別。
LDR R0,0x12345678 //把地址0x12345678存放的內容放到R0裏面
MOV R0,#x //把立即數x放到R0裏面,x必須是一個8 bits的數移到偶數次得到的數。
LDR R0,=0x12345678 //把立即數0x12345678放到R0裏面
6. 在移植u-boot-1.3.3以上版本的時候要注意:
在u-boot1.3.3及以上版本Makefile有一定的變化,使得對於24x0處理器從nand啓動的遇到問題。也就是網上有人說的:無法
運行過lowlevel_init。其實這個問題是由於編譯器將我們自己添加的用於nandboot的子函數nand_read_ll放到了4K之後造成的(到
這不理解的話,請仔細看看24x0處理器nandboot原理)。我是在運行失敗後,利用mini2440的4個LED調試發現u-boot根本沒有完成自
我拷貝,然後看了uboot根目錄下的System.map文件就可知道原因。
解決辦法其實很簡單:
將__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改爲__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))
7. 然後說一下跳轉指令。ARM有兩種跳轉方式。
(1)mov pc <跳轉地址〉
這種向程序計數器PC直接寫跳轉地址,能在4GB連續空間內任意跳轉。
(2)通過B BL BLX BX可以完成在當前指令向前或者向後32MB的地址空間的跳轉(爲什麼是32MB呢?寄存器是32位的,此時的值是24
位有符號數,所以32MB)。
B是最簡單的跳轉指令。要注意的是,跳轉指令的實際值不是絕對地址,而是相對地址——是相對當前PC值的一個偏移量,它的值由
彙編器計算得出。
BL非常常用。它在跳轉之前會在寄存器LR(R14)中保存PC的當前內容。BL的經典用法如下:
bl NEXT ; 跳轉到NEXT
……
NEXT
……
mov pc, lr ; 從子程序返回。