?
建議讀一讀《嵌入式系統(tǒng)Boot Loader技術(shù)內(nèi)幕》(詹榮開著)。什么是Bootloader就不再這里廢話了,看看上面的文章就明了了。
Bootloader有很多種,如本文將要閱讀的vivi,除此之外還有uboot,redboot,lilo等等。Vivi 是韓國mizi公司專門為三星s3c2410芯片設(shè)計的Bootloader。
先來看看vivi的源碼樹:
vivi-+-arch-+-s3c2410
|-Documentation
|-drivers-+-serial
| ‘ -mtd-+-maps
| |-nor
| ‘-nand
|-include-+-platform
| |-mtd
| ‘-proc
|-init
|-lib-+-priv_data
|-scripts-+-lxdialog
|-test
|-util
可以google一下,搜到源碼vivi.tar.gz。
前面提到的文件已經(jīng)系統(tǒng)的分析了bootloader的,這里就按源代碼來具體說事。vivi也可以分為2個階段,階段1的代碼在arch/s3c2410/head.S中,階段2的代碼從init/main.c的main函數(shù)開始。
階段1
階段1從程序arch/s3c2410/head.S開始,按照head.S的代碼執(zhí)行順序,一次完成了下面幾個任務(wù):
關(guān)WATCH DOG (disable watch dog timer)
上電后,WATCH DOG默認(rèn)是開著的
禁止所有中斷 (disable all interrupts)
vivi中不會用到中斷,中斷是系統(tǒng)的事,bootloader可不能去干這事的(不過這段代碼實(shí)在多余,上電后中斷默認(rèn)是關(guān)閉的)
初始化系統(tǒng)時鐘(initialise system clocks)
啟動MPLL,F(xiàn)CLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改為“Asynchronous bus mode”。
初始化內(nèi)存控制寄存器(memsetup)
S3c2410共有15個寄存器,在此開始初始化13個寄存器。
檢查是否從掉電模式喚醒(Check if this is a wake-up from sleep)若是,則調(diào)用WakeupStart函數(shù)進(jìn)行處理。
點(diǎn)亮所有LED (All LED on)
點(diǎn)一下燈,通知外面的同志,告訴他們有情況發(fā)生。
初始化UART0 (set GPIO for UART & InitUART)
a.設(shè)置GPIO,選擇UART0使用的引腳
b.初始化UART0,設(shè)置工作方式(使用FIFO)、波特率115200 8N1、無流控等。這可是使用串口與s3c2410通信的條件啊,在終端也要如此設(shè)置。
跳到內(nèi)存測試函數(shù)(simple memory test to find some DRAM flaults)
當(dāng)然要定義了CONFIG_BOOTUP_MEMTEST這個參數(shù)才會跳到內(nèi)存測試。
如果定義了以Nand flash方式啟動(#ifdef CONFIG_S3C2410_NAND_BOOT),則此時要將vivi所有代碼(包括階段1和階段2)從Nand flash復(fù)制到SDRAM中(因?yàn)樵贜and flash中是不能執(zhí)行程序的,它只能做為程序和數(shù)據(jù)的存儲器,而Nor flash可就不同了,Nor flash可以執(zhí)行程序,但貴是它發(fā)展的瓶頸):
a.設(shè)置nand flash控制寄存器
b.設(shè)置堆棧指針
c.設(shè)置即將調(diào)用的函數(shù)nand_read_ll的參數(shù):r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=復(fù)制的長度(以字節(jié)為單位)
d.調(diào)用nand_read_ll進(jìn)行復(fù)制
跳到bootloader的階段2運(yùn)行,亦即調(diào)用init/main.c中的main函數(shù)(get read to call C functions)
a.重新設(shè)置堆棧
b.設(shè)置main函數(shù)的參數(shù)
c.調(diào)用main函數(shù)
head.S有900多行,都是些arm匯編,看的云山霧罩,匯編看來是忘的差不多了,所以這部分代碼也看的相當(dāng)糙,只知道大概在干什么,至于個中緣由就不是很了解。先學(xué)學(xué)arm匯編再回來看。
階段2
從init/main.c中的main函數(shù)開始,終于步入C語言的世界了。Main函數(shù)總共有8步(8 steps),先看看源代碼:
int main(int argc, char *argv[])
{
int ret;
/*
* Step 1:
*/
putstr("\r\n");
putstr(vivi_banner); //vivi_banner是vivi執(zhí)行開始的顯示信息,vivi_banner在文件version.c中定義
reset_handler();
/*
* Step 2:
*/
ret = board_init();
if (ret) {
putstr("Failed a board_init() procedure\r\n");
error();
}
/*
* Step 3:
*/
mem_map_init();
mmu_init();
putstr("Succeed memory mapping.\r\n");
/*
* Now, vivi is running on the ram. MMU is enabled.
* Step 4:
*/
/* initialize the heap area*/
ret = heap_init();
if (ret) {
putstr("Failed initailizing heap region\r\n");
error();
}
/* Step 5:
* MTD
*/
ret = mtd_dev_init();
/* Step 6:
*/
init_priv_data();
/* Step 7:
*/
misc();
init_builtin_cmds();
/* Step 8:
*/
boot_or_vivi();
return 0;
}
下面按照上面的步驟逐步來分析一下。
1、Step 1:reset_handler()
reset_handler用于將內(nèi)存清零,代碼在lib/reset_handle.c中。
1 void
2 reset_handler(void)
3 {
4 int pressed;
5 pressed = is_pressed_pw_btn(); /*判斷是硬件復(fù)位還是軟件復(fù)位*/
6 if (pressed == PWBT_PRESS_LEVEL) {
7 DPRINTK("HARD RESET\r\n");
8 hard_reset_handle(); /*調(diào)用clear_mem對SDRAM清0*/
9 } else {
10 DPRINTK("SOFT RESET\r\n");
11 soft_reset_handle(); /*此函數(shù)為空*/
12 }
13 }
在上電后,reset_handler調(diào)用第8行的hard_reset_handle(),此函數(shù)在lib/reset_handle.c中:
[main(int argc, char *argv[]) -> reset_handler() -> hard_reset_handle()]
1 static void
2 hard_reset_handle(void)
3 {
4 #if 0
5 clear_mem((unsigned long)(DRAM_BASE + VIVI_RAM_ABS_POS), \
6 (unsigned long)(DRAM_SIZE - VIVI_RAM_ABS_POS));
7 #endif
/*lib/memory.c,將起始地址為USER_RAM_BASE,長度為USER_RAM_SIZE的內(nèi)存清0*/
8 clear_mem((unsigned long)USER_RAM_BASE, (unsigned long) USER_RAM_SIZE);
9 }
先寫到這兒吧。
2、Step 2:board_init()
board_init調(diào)用2個函數(shù)用于初始化定時器和設(shè)置各GPIO引腳功能,代碼在arch/s3c2410/smdk.c中:
[main(int argc, char *argv[]) > board_init()]
1 int board_init(void)
2 {
3 init_time(); /*arch/s3c2410/proc.c*/
4 set_gpios(); /*arch/s3c2410/smdk.c */
5 return 0;
6 }
init_time() 這個函數(shù)對寄存器進(jìn)行了簡單的操作:
void init_time(void)
{
TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));
/*s3c2410 data sheet P298*/
/*TCFG0 = 0 | 0xf00 | 0 */
}
評論
查看更多