第一節:最簡單的BootLoader編寫步驟
一、 Boot Loader的概念和功能
1、嵌入式Linux軟件結構與分佈:在一般情況下嵌入式Linux系統中的軟件主要分爲以下及部分:
(1)引導加載程序:其中包括內部ROM中的固化啓動代碼和Boot Loader兩部分。
內部固化ROM:是廠家在芯片生產時候固化的,作用基本上是引導Boot Loader。
Boot Loader:引導內核啓動
(2)Linux kernel 和drivers。
(3)文件系統。包括根文件系統和建立於Flash內存設備之上的文件系統(EXT4、UBI、CRAMFS等等)。它是提供管理系統的各種配置文件以及系統執行用戶應用程序的良好運行環境的載體。
(4)應用程序。用戶自定義的應用程序,存放於文件系統之中。
在Flash 存儲器中,他們的 一般分佈如下:
但是以上只是大部分情況下的分佈,也有一些可能根文件系統是initramfs,被一起壓縮到了內核映像裏,或者沒有Bootloader參數區,等等。
第一部分問答:
1、BootLoader的目標是幹什麼?
答:啓動內核
2、那麼內核在什麼地方?
答:內核在flash上
那麼寫BootLoader第一步:從flash上把內核讀到內存
由第一步可見,BootLoader需要對flash進行操作
3、從flash上把內核讀到內存需要具備哪些條件?
答:a.能操作flash;
b.既然需要讀到內存中,那麼就需要初始化內存(內核是要放到SDRAM中 ,因爲nand flash比較小,不能直接燒寫內核,SDRAM這種內存需要先初始化);
c.開發板上電時有自己的運行頻率(例如:三星2440一上電運行的頻率是12MHZ)如果我們想讓它運行的快一點,就需要初始化時鐘;
d.還有一些其它的例如關閉看門狗等。之所以關閉看門狗是因爲開發板一上電看門狗就打開,如果不關掉一到看門狗設置的時間就會重新復位開發板
e.如果BootLoader比較大怎麼辦?把BootLoader重定位到SDRAM
f.如果內核是放在nand flash的話,需要初始化nand flash
g.必須禁止中斷(IRQs和FIQs)?爲中斷提供服務通常是OS設備驅動程序的責任,因此在 Boot Loader 的執行全過程中可以不必響應任何中斷。中斷屏蔽可以通過寫CPU的中斷屏蔽寄存器或狀態寄存器(比如 ARM 的 CPSR 寄存器)來完成。
第二部分問答:
4、在第一部分中已經將內核讀到了內存,那麼怎麼去啓動內核?直接跳到內核的地址裏面去就可以了嗎?
5、在啓動內核之前我想給它傳一些參數,比如說,告訴內核我的內存有多大,你應該去哪裏找這個根文件系統,等等等等。。。。。傳參數?怎麼傳?
答:1、首先設置參數(在某個約定的地址存入一些參數、設置好一些參數)
2、跳轉執行內核
代碼部分:
首先寫一個start.S
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02)) /*設置200MHZ*/
#define MEM_CTL_BASE 0x48000000
.text //.text:表示代碼段
.global _start //.global _start:表示一個全局的標識
_start:
/* 1.關看門狗 */ i
ldr r0, =0x53000000 /*0x53000000看門狗的地址,如果一個數比較複雜,不能用立即數表示,我們就用僞彙編*/
mov r1, #0
str r1, [r0] /*把0存到r0這個地址去*/
/* 2.設置時鐘 */
ldr r0, =0x4c00014 /*0x4c00014時鐘地址*/
mov r1, #0x03 /*0x03分頻係數,FCLK:HCLK:PCLK=1:2:4,HDIVN=1,PDIVN=1*/
str r1, [r0]
/*數據手冊要求,當FCLK不等於HCLK時,cpu的總線模式應該從“fast bus mode”變爲“asynchronous bus mode”*/
mrc p15, 0, r1, c1, c0, 0 /*讀出控制寄存器*/
orr r1, r1, #0xc000000 /*設置爲“asynchronous bus mode”*/
mcr p15, 0, r1, c1, c0, 0 /*寫入控制寄存器*/
/*設置MPLLCON=S3C2440_MPLL_200MHZ*/
ldr r0, =0x4c00004
ldr r1, =S3C2440_MPLL_200MHZ
str r1, [r0]
/* 3.初始化SDRAM */
/*SDRAM控制寄存器的起始地址*/
ldr r0, =MEM_CTL_BASE
/*(sdram_config)的當前地址*/
adr r1, sdram_config
/*r3=r0+52,之所以爲13,是因爲有13個控制寄存器*/
/*每個長度爲4,所以爲13*4*/
add r3, r0, #(13*4)
1:
/*將r1的值加載到r2,同時r1加4。取出寄存器將要被設置的值*/
ldr r2, [r1], #4
/*將r2的值存儲到r0,同時r0加4。將要設置的值賦給對應的寄存器*/
str r2, [r0], #4
/*如果r0小於r3,那麼就跳回到標籤1處*/
cmp r0, r3
/*b是back的意思,結束之後,SDRAM的所有寄存器就都設置好了*/
bne 1b
/*注:爲了完成比較複雜的工作,不能僅僅使用匯編代碼。我們需要使用C語言來編寫一些功能,在使用C語言代碼之前一定要設置棧。
*/
/*2440的SDRAM大小爲64M,並且起始地址爲0x30000000。
這裏指向最高的內存,因爲棧是由高向低地址走的(下文)。
這裏0x04000000爲64M(每個地址對應一個字節)
所以設爲0x30000000+0x04000000*/
ldr sp, =0x34000000
bl nand_init
/*跳轉到C語言程序中的NAND FLASH初始化函數*/
/* 4.重定位 :把BootLoader本身的代碼從flash複製到它的鏈接地址去:他的鏈接地址是什麼?*/
bl copy_code_to_sdram //相對跳轉到copy_code_to_sdram
/* 5.執行main */
/*怎麼執行的main函數?相對跳轉?用bl main ?*/
/*要把這些數據讀出來,存到SDRAM:reg:0x48000000*/
sdram_config:
.long 0x22011110 //BWSCON
.long 0x00000700 //BANKCON0
.long 0x00000700 //BANKCON1
.long 0x00000700 //BANKCON2
.long 0x00000700 //BANKCON3
.long 0x00000700 //BANKCON4
.long 0x00000700 //BANKCON5
.long 0x00018005 //BANKCON6
.long 0x00018005 //BANKCON7
.long 0x008C04F4 //REFRESH
.long 0x000000B1 //BANKSIZE
.long 0x00000030 //MRSRB6
.long 0x00000030 //MRSRB7