編寫IPL程序

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)初始化并沒有看到。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • QNX相關(guān)歷史文章:QNX簡介QNX Neutrino微內(nèi)核QNX IPC機(jī)制QNX進(jìn)程管理器QNX資源管理器QN...
    Loyen閱讀 8,804評論 0 4
  • 一、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運行的地址不確定 關(guān)于...
    SeanCST閱讀 8,137評論 0 27
  • QNX相關(guān)歷史文章:QNX簡介QNX Neutrino微內(nèi)核QNX IPC機(jī)制QNX進(jìn)程管理器QNX資源管理器QN...
    Loyen閱讀 8,496評論 2 5
  • [TOC] Android 簡介 Android 操作系統(tǒng)是基于Linux內(nèi)核, Google使用Linux內(nèi)核構(gòu)...
    Joe_HUST閱讀 9,397評論 0 9
  • 轉(zhuǎn)發(fā)http://www.itdecent.cn/p/439ce15436c1 Android 簡介 Andro...
    wholesky閱讀 1,373評論 0 1

友情鏈接更多精彩內(nèi)容