QNX相關(guān)歷史文章:
這篇文章主要描述Initial program loader的相關(guān)內(nèi)容,并以Freescale IXM6處理器為例講解
1. Initial program loader
IPL的功能可以類比Uboot,IPL程序的任務(wù)是對硬件進(jìn)行最低限度的配置,以創(chuàng)建一個startup程序運行的環(huán)境,至少包括以下內(nèi)容:
- 從Reset異常向量開始執(zhí)行;
- 配置內(nèi)存控制器;
- 配置時鐘;
- 設(shè)置堆棧,以便允許IPL庫執(zhí)行OS的驗證和設(shè)置(下載、掃描、設(shè)置、跳轉(zhuǎn)到OS鏡像)
IPL的代碼可能很簡單,也可能非常復(fù)雜,這分別對應(yīng)到Warm-start和Cold-start。在Warm-start中,已經(jīng)有BIOS或者ROM monitor了,IPL需要做的工作就會少很多,而在Cold-start中,沒有BIOS或者ROM monitor,因此需要實現(xiàn)全部的功能。
IPL的初始化部分是用匯編實現(xiàn)的(因為它從ROM執(zhí)行,沒有內(nèi)存控制器),初始化硬件之后,IPL調(diào)用main()函數(shù)來初始化C語言環(huán)境。
設(shè)置好C語言環(huán)境后,IPL可以執(zhí)行不同的任務(wù),這個具體取決于操作系統(tǒng)是從linearly mapped設(shè)備啟動,還是從bank-switched設(shè)備啟動:
- linearly mapped,整個鏡像在處理器的線性地址空間中,比如ROM;
- bank-switched,鏡像不能完全由處理器尋址,比如Disk device、Network設(shè)備、串口或并口、以及bank-switched的ROM或RAM;
1.1 bank-switched
從bank-switched設(shè)備中啟動時,需要以下幾步:
- IPL必須調(diào)用函數(shù)與相關(guān)設(shè)備通信,比如串口下載時,IPL使用image_download_8250()函數(shù),該函數(shù)用于配置和控制8250類串口控制器,完成設(shè)置后,該函數(shù)會將image拷貝到RAM中;
- IPL調(diào)用image_sacn()來掃描整個image,完成一些校驗工作;
- IPL調(diào)用image_setup()來完成一些設(shè)置工作;
-
IPL調(diào)用image_start(),跳轉(zhuǎn)到startup的起始地址,將控制權(quán)交給startup;
鏡像加載時,由于是bank-switched,所以需要將整個鏡像都拷貝到RAM中,如下圖所示:
從圖中可以看出來,IPL處理時可以分為三步:
- IPL接收控制;
- IPL將image加載到RAM中;
- IPL將控制權(quán)交給加載的image;
1.2 linearly mapped
linearly mapped設(shè)備的啟動方式與bank-switched設(shè)備是一致的,不同點在于,不需要將整個image都拷貝到RAM中,如下圖所示:

2. 自定義IPL程序
編寫IPL程序,需要以下幾個步驟:
- 初始化硬件,包括對系統(tǒng)RAM的訪問。注意,只需要初始化必須的硬件(比如時鐘等),外圍硬件不需要初始化;(匯編實現(xiàn))
- 將image鏡像(使用mkifs生成)加載到RAM中,加載程序使用header信息來拷貝header和startup到RAM中,如果不是在linearly mapped的設(shè)備中,則需要將整個鏡像拷貝到RAM中;(比如image_download_8250())
- 定位OS鏡像,并做一些校驗工作;(調(diào)用image_sacn())
- 拷貝startup程序;(調(diào)用image_setup())
- 跳轉(zhuǎn)到加載鏡像起始位置執(zhí)行;(調(diào)用image_start())
3. IPL庫
IPL庫包含了一系列的接口,用于實現(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)的時鐘;
- init_pinmux(),該函數(shù)用于設(shè)置管腳的復(fù)用,主要是設(shè)置Uart和SD相關(guān),其中Uart用于調(diào)試,而SD用于加載image;
- init_sermx6(),該函數(shù)用于初始化串口信息;
- image_download_ser()/sdmmc_load_file(),這兩個函數(shù)用于完成Image的加載;
- image_scan_2(),該函數(shù)用于掃描image,對Image進(jìn)行一些校驗檢查;
- image_start_2(),該函數(shù)跳轉(zhuǎn)到Image的入口去執(zhí)行,也就是跳轉(zhuǎn)到startup程序中去運行;
從以上的流程可以看出IPL整體的功能并不復(fù)雜,完成最少硬件(需要用到的,比如時鐘、串口、SD)的初始化,然后對Image加載和校驗,最終跳轉(zhuǎn)過去執(zhí)行即可。
當(dāng)然,我對這個IPL可運行性是持懷疑態(tài)度的,因為很重要的DDR Controler的相關(guān)初始化并沒有看到。
