QNX相關(guān)歷史文章:
這篇文章主要描述Initial program loader的相關(guān)內(nèi)容件豌,并以Freescale IXM6處理器為例講解
1. Initial program loader
IPL的功能可以類(lèi)比Uboot歪脏,IPL程序的任務(wù)是對(duì)硬件進(jìn)行最低限度的配置闷板,以創(chuàng)建一個(gè)startup程序運(yùn)行的環(huán)境,至少包括以下內(nèi)容:
- 從Reset異常向量開(kāi)始執(zhí)行券膀;
- 配置內(nèi)存控制器辟躏;
- 配置時(shí)鐘谷扣;
- 設(shè)置堆棧,以便允許IPL庫(kù)執(zhí)行OS的驗(yàn)證和設(shè)置(下載捎琐、掃描会涎、設(shè)置、跳轉(zhuǎn)到OS鏡像)
IPL的代碼可能很簡(jiǎn)單瑞凑,也可能非常復(fù)雜末秃,這分別對(duì)應(yīng)到Warm-start和Cold-start。在Warm-start中籽御,已經(jīng)有BIOS或者ROM monitor了练慕,IPL需要做的工作就會(huì)少很多,而在Cold-start中技掏,沒(méi)有BIOS或者ROM monitor铃将,因此需要實(shí)現(xiàn)全部的功能。
IPL的初始化部分是用匯編實(shí)現(xiàn)的(因?yàn)樗鼜腞OM執(zhí)行哑梳,沒(méi)有內(nèi)存控制器)劲阎,初始化硬件之后,IPL調(diào)用main()函數(shù)來(lái)初始化C語(yǔ)言環(huán)境鸠真。
設(shè)置好C語(yǔ)言環(huán)境后悯仙,IPL可以執(zhí)行不同的任務(wù),這個(gè)具體取決于操作系統(tǒng)是從linearly mapped設(shè)備啟動(dòng)弧哎,還是從bank-switched設(shè)備啟動(dòng):
- linearly mapped雁比,整個(gè)鏡像在處理器的線(xiàn)性地址空間中,比如ROM撤嫩;
- bank-switched偎捎,鏡像不能完全由處理器尋址,比如Disk device序攘、Network設(shè)備茴她、串口或并口、以及bank-switched的ROM或RAM程奠;
1.1 bank-switched
從bank-switched設(shè)備中啟動(dòng)時(shí)丈牢,需要以下幾步:
- IPL必須調(diào)用函數(shù)與相關(guān)設(shè)備通信,比如串口下載時(shí)瞄沙,IPL使用image_download_8250()函數(shù)己沛,該函數(shù)用于配置和控制8250類(lèi)串口控制器慌核,完成設(shè)置后,該函數(shù)會(huì)將image拷貝到RAM中申尼;
- IPL調(diào)用image_sacn()來(lái)掃描整個(gè)image垮卓,完成一些校驗(yàn)工作;
- IPL調(diào)用image_setup()來(lái)完成一些設(shè)置工作师幕;
-
IPL調(diào)用image_start()粟按,跳轉(zhuǎn)到startup的起始地址,將控制權(quán)交給startup霹粥;
鏡像加載時(shí)灭将,由于是bank-switched,所以需要將整個(gè)鏡像都拷貝到RAM中后控,如下圖所示:
從圖中可以看出來(lái)庙曙,IPL處理時(shí)可以分為三步:
- IPL接收控制;
- IPL將image加載到RAM中忆蚀;
- IPL將控制權(quán)交給加載的image矾利;
1.2 linearly mapped
linearly mapped設(shè)備的啟動(dòng)方式與bank-switched設(shè)備是一致的,不同點(diǎn)在于馋袜,不需要將整個(gè)image都拷貝到RAM中男旗,如下圖所示:
2. 自定義IPL程序
編寫(xiě)IPL程序,需要以下幾個(gè)步驟:
- 初始化硬件欣鳖,包括對(duì)系統(tǒng)RAM的訪問(wèn)察皇。注意,只需要初始化必須的硬件(比如時(shí)鐘等)泽台,外圍硬件不需要初始化什荣;(匯編實(shí)現(xiàn))
- 將image鏡像(使用mkifs生成)加載到RAM中,加載程序使用header信息來(lái)拷貝header和startup到RAM中怀酷,如果不是在linearly mapped的設(shè)備中稻爬,則需要將整個(gè)鏡像拷貝到RAM中;(比如image_download_8250())
- 定位OS鏡像蜕依,并做一些校驗(yàn)工作桅锄;(調(diào)用image_sacn())
- 拷貝startup程序;(調(diào)用image_setup())
- 跳轉(zhuǎn)到加載鏡像起始位置執(zhí)行样眠;(調(diào)用image_start())
3. IPL庫(kù)
IPL庫(kù)包含了一系列的接口友瘤,用于實(shí)現(xiàn)自定義的IPL程序,可用的函數(shù)接口如下:
4. Freescale IMX6 IPL
Freescale IMX6 BSP包:BSP_freescale-imx6SoloX-sabre-sdb_br-660_be-660_SVN815609_JBN555.zip
下載Freescale IMX6 BSP zip包并解壓檐束,IPL代碼位于src/hardware/ipl/boards/mx6sx-sabre-sdb中辫秧,其中mx6sx-sabre-sdb.lnk為鏈接文件,指定了程序的入口以及內(nèi)存的分段及布局等被丧。
程序的入口:ENTRY(_start)盟戏,在start.S文件中完成了以下工作:
- 設(shè)置CPU為SVC32模式
- Invalidate L1 I/D and TLBs
- Disable MMU和Caches
- 使能ICache
- 設(shè)置堆棧
- 跳轉(zhuǎn)到main函數(shù)
在該目錄中的main.c完成IPL的主要工作:
int main(void)
{
unsigned int image = QNX_LOAD_ADDR;
init_aips();
init_clocks();
init_pinmux();
init_sermx6(MXC_CONSOLE_BASE, 115200, 80000000, 2);
ser_putstr("\nWelcome to QNX Neutrino Initial Program Loader for:\n");
ser_putstr(" Freescale i.MX6 SoloX Sabre SDB (ARM Cortex-A9/M4)\n");
while (1) {
ser_putstr("Command:\n");
ser_putstr("Press 'D' for UART IFS download, using the 'sendnto' utility.\n");
ser_putstr("Press 'M' for SDMMC IFS download.\n");
ser_putstr("Press 'J' for JTAG IFS boot of image loaded to 0x"); ser_puthex(QNX_LOAD_ADDR); ser_putstr(".\n");
switch (ser_getchar()) {
case 'D': case 'd':
ser_putstr("send image now...\n");
if (image_download_ser(QNX_LOAD_ADDR)) {
ser_putstr(str_download_failed);
continue;
} else {
ser_putstr(str_download_ok);
}
break;
case 'M': case 'm':
if (sdmmc_load_file(QNX_LOAD_ADDR, QNX_IFS_FILENAME) != 0) {
ser_putstr(str_download_failed);
continue;
}
ser_putstr(str_download_ok);
break;
case 'J': case 'j':
break;
default:
break;
}
/* No safe boot media, must be scanned */
image = image_scan_2(image, image + MAX_SCAN, 1);
if (image != 0xffffffff) {
ser_putstr(str_found_image);
ser_puthex(image);
ser_putstr("\n");
image_setup_2(image);
ser_putstr(str_jump_to_image);
ser_puthex(startup_hdr.startup_vaddr);
ser_putstr("\n\n");
image_start_2(image);
/* Never reaches here */
return 0;
}
ser_putstr(str_image_scan_fail);
} /* Forever */
/* Never reaches here */
return 0;
}
進(jìn)入main分別完成了以下工作:
- init_aips()绪妹,該函數(shù)用于設(shè)置AHB到IP Bridge的屬性,跟Trust Zone相關(guān)抓半;
- init_clocks()喂急,該函數(shù)用于設(shè)置系統(tǒng)的時(shí)鐘;
- init_pinmux()笛求,該函數(shù)用于設(shè)置管腳的復(fù)用,主要是設(shè)置Uart和SD相關(guān)糕簿,其中Uart用于調(diào)試探入,而SD用于加載image;
- init_sermx6()懂诗,該函數(shù)用于初始化串口信息蜂嗽;
- image_download_ser()/sdmmc_load_file(),這兩個(gè)函數(shù)用于完成Image的加載殃恒;
- image_scan_2()植旧,該函數(shù)用于掃描image,對(duì)Image進(jìn)行一些校驗(yàn)檢查离唐;
- image_start_2()病附,該函數(shù)跳轉(zhuǎn)到Image的入口去執(zhí)行,也就是跳轉(zhuǎn)到startup程序中去運(yùn)行亥鬓;
從以上的流程可以看出IPL整體的功能并不復(fù)雜完沪,完成最少硬件(需要用到的,比如時(shí)鐘嵌戈、串口覆积、SD)的初始化,然后對(duì)Image加載和校驗(yàn)熟呛,最終跳轉(zhuǎn)過(guò)去執(zhí)行即可宽档。
當(dāng)然,我對(duì)這個(gè)IPL可運(yùn)行性是持懷疑態(tài)度的庵朝,因?yàn)楹苤匾腄DR Controler的相關(guān)初始化并沒(méi)有看到吗冤。