DM368开发 -- Bootloader 开发(转毕设)
參看:基于 DM368 的高清視頻監(jiān)控系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn) -- 文波
DM368 的啟動(dòng)過程大致如下: 首先進(jìn)行啟動(dòng)代碼的加載與執(zhí)行, 主要是指 Bootloader啟動(dòng)階段,其次啟動(dòng)系統(tǒng)內(nèi)核并掛載文件系統(tǒng),最后運(yùn)行應(yīng)用程序。其過程如圖 4.1 所示。本系統(tǒng)中 Bootloader 分為 3 個(gè)階段:RBL(Rom Boot Loader),UBL(Use Boot Loader)和 U-boot(Universal Bootloader)。
一、 Bootloader 簡介
Bootloader 是嵌入式系統(tǒng)的引導(dǎo)加載程序,主要存放在 DM368 目標(biāo)板的非易失性存儲(chǔ)器中(通常為 FLASH 存儲(chǔ)器) ,作用類似于 PC 機(jī)上的 BIOS[50]。它是系統(tǒng)上電后最先運(yùn)行的第一段程序,主要用于對硬件設(shè)備進(jìn)行初始化并建立內(nèi)存空間映射,為 Linux操作系統(tǒng)內(nèi)核的運(yùn)行準(zhǔn)備合適的軟硬件運(yùn)行環(huán)境[51]。在完成對系統(tǒng)的初始化任務(wù)后,它會(huì)將存儲(chǔ)器中的 Linux 內(nèi)核拷貝到 RAM 中, 然后跳轉(zhuǎn)到內(nèi)核的第一條指令處繼續(xù)執(zhí)行,從而啟動(dòng) Linux 內(nèi)核。由此可見,Bootloader 和 Linux 內(nèi)核之間有著密不可分的聯(lián)系,對于嵌入式操作系統(tǒng)來說發(fā)揮著很重要的作用。Bootloader 雖然具有初始化系統(tǒng)和執(zhí)行用戶輸入的命令的作用,但它最根本的功能就是為了啟動(dòng) Linux 內(nèi)核。Bootloader 的操作模式分為自啟動(dòng)模式和交互模式。自啟動(dòng)模式是指操作系統(tǒng)的內(nèi)核和文件系統(tǒng)已燒寫到目標(biāo)板的某個(gè)固態(tài)存儲(chǔ)器芯片上,Bootloader 從目標(biāo)板上的固態(tài)存儲(chǔ)設(shè)備上將操作系統(tǒng)加載到 RAM 中運(yùn)行,整個(gè)過程自行完成,不需要用戶介入,自啟動(dòng)模式主要用于產(chǎn)品開發(fā)完成后[52]。交互模式主要應(yīng)用在系統(tǒng)的開發(fā)調(diào)試階段,通過串口和以太網(wǎng)將內(nèi)核映像和文件系統(tǒng)從主機(jī)上下載到目標(biāo)板的內(nèi)存中。系統(tǒng)調(diào)試完成后,可以通過固定的命令將這些文件燒寫到存儲(chǔ)器芯片中,實(shí)現(xiàn)系統(tǒng)自啟動(dòng)。二、系統(tǒng)啟動(dòng)方式
DM368 有兩種啟動(dòng)模式, 第一種是從外部的異步存儲(chǔ)器 AEMIF (NOR /One FLASH)啟動(dòng),無需引導(dǎo)程序引導(dǎo); 第二種是 ARM內(nèi)部的 ROM自帶 RBL引導(dǎo)程序引導(dǎo) bootloader方式啟動(dòng),首先啟動(dòng) RBL,其次啟動(dòng) UBL,最后啟動(dòng) U-boot。DM368 中 ARM 內(nèi)部的ROM 大小為 16KB,在出廠時(shí)已燒寫好一段固件代碼,稱為 RBL(Rom Boot Loader) 。此方式支持 7 種啟動(dòng)方式分別為:NAND 啟動(dòng)方式、MMC/SD 啟動(dòng)方式、UART 啟動(dòng)方式、USB 啟動(dòng)方式、SPI 啟動(dòng)方式、EMAC 啟動(dòng)方式和 HPI 啟動(dòng)方式。DM368 的啟動(dòng)方式示意圖如下圖 4.2 所示:當(dāng) DM368 上電后,芯片會(huì)檢測 BOOT 模式配置引腳 BTSEL[2:0]的狀態(tài),根據(jù)其具體值來決定采取哪種啟動(dòng)方式。 當(dāng) BTSEL[2:0]=001 時(shí), 系統(tǒng)采用第一種啟動(dòng)方式, ARM處理器從 AFMIF 執(zhí)行引導(dǎo)啟動(dòng)程序,即從外部存儲(chǔ)器 One Nand 或 Nor Flash 啟動(dòng)。通過 AEMIF 接口從 Nor/One NAND 里讀取已經(jīng)固化好的代碼,起始地址從 0x02000000開始。同時(shí)通過寄存器 AECFG[2:0]對 Nor/One NAND 的地址線位數(shù)進(jìn)行配置。當(dāng)BTSEL[2:0]≠001 時(shí), 系統(tǒng)采用第二種啟動(dòng)方式, 即 RBL 引導(dǎo) bootloader 方式啟動(dòng)模式。ARM 處理器從其內(nèi)部 ROM 地址 0x00008000 處開始執(zhí)行 RBL 程序,之后 RBL 根據(jù)BTSEL[2:0]的值決定啟動(dòng)方式。Boot 引腳值對應(yīng)的啟動(dòng)模式如表 4.1 所示。
硬件系統(tǒng)選用 NAND FLASH 作為外部存儲(chǔ)器, BTSEL[2:0]設(shè)定為 000,AECFG[2:0]設(shè)定為 000,所以系統(tǒng)采用 RBL 引導(dǎo)的 8 位 NAND FLASH 啟動(dòng)方式。此過程需要三個(gè)階段,分別為 RBL、UBL 和 U-boot[53],啟動(dòng)過程的流程圖如圖 4.3 所示。
根據(jù)以上分析,DM368 的啟動(dòng)需要 3 級引導(dǎo),即 RBL→UBL→U-boot。之所以使用UBL,是因?yàn)?DM368 的內(nèi)部 RAM 空間只有 32KB,而一般的 U-boot 要大于 32KB[54]。
三、RBL 啟動(dòng)過程分析
RBL 是 TI 公司在芯片出廠時(shí)固化在 ARM 內(nèi)部 ROM 中的一段啟動(dòng)程序, 起始地址為 0x00008000,終止地址為 0x0000BFFF。啟動(dòng)開始后,系統(tǒng)會(huì)從該地址讀取數(shù)據(jù),運(yùn)行 RBL 程序。 RBL 從 NAND FLASH 中讀取 UBL 描述符, 隨后復(fù)制 UBL 到內(nèi)部 RAM,并跳轉(zhuǎn)到 UBL 的入口地址 0x00000020 運(yùn)行 UBL。RBL 工作流程如下圖 4.4 所示。
啟動(dòng)開始后,RBL 首先通過 EM_CE0 和 AECFG[2:0]搜索到 NAND FLASH 設(shè)備,并獲取到 FLASH 的相關(guān)信息,如設(shè)備的 ID。通過此 ID 可以獲得 NAND FLASH 相對應(yīng)的信息。 其次 RBL 開始在 NAND FLASH 中搜索有效的 UBL 描述符, 從 NAND FLASH中第 1 塊的第 0 頁開始依次搜索,至到最后一塊的最后一頁為止。如果全部搜索完畢沒有發(fā)現(xiàn)有效的 UBL 描述符,則系統(tǒng)嘗試轉(zhuǎn)入 MMC/SD 卡啟動(dòng)方式啟動(dòng)。如果 RBL搜索到合法的 UBL,則對 UBL 的描述符采取讀入和執(zhí)行措施,同時(shí)將有效的塊號(hào)寫入到 ARM 內(nèi)部 RAM 最后的 32 位地址中,從 0x00007FFC 到 0x00008000[55]。UBL 描述符包含有 UBL 特殊信息描述符 MagicNumber、入口地址、頁數(shù)、開始塊數(shù)和結(jié)束塊等基本信息。當(dāng) RBL 找到 UBL 描述符信息后,會(huì)讀取并處理該信息,并完成 UBL 啟動(dòng)配置, 之后 RBL 會(huì)把 UBL 從 NAND FLASH 中拷貝到 ARM 內(nèi)部的 RAM 中, 執(zhí)行 UBL的地址從 0x00000020 開始。在 RBL 對 UBL 拷貝過程過程中,RBL 對 UBL 進(jìn)行 4 位的ECC 錯(cuò)誤校驗(yàn)和檢測機(jī)制,如果 RBL 檢測出拷貝的數(shù)據(jù)出錯(cuò),UBL 會(huì)通過 ECC 檢驗(yàn)算法糾整錯(cuò)誤。如果糾錯(cuò)失敗,RBL 放棄當(dāng)前塊,繼續(xù)從下一塊開始搜索有效地 UBL描述符。最后當(dāng) RBL 完成 UBL 的搬運(yùn)工作后,RBL 會(huì)將系統(tǒng)指針指向 UBL 起始地址,并將控制權(quán)交給 UBL,UBL 程序接著開始運(yùn)行。
四、UBL 啟動(dòng)過程分析
UBL 主要功能是實(shí)現(xiàn)將 U-boot 代碼拷貝到 DDR2 內(nèi)存中,建立運(yùn)行環(huán)境并引導(dǎo)U-boot。在嵌入式操作系統(tǒng)中,U-boot 的大小一般都較大,基本上都在 100KB 以上。本系統(tǒng)中 DM368 中 ARM 核內(nèi)置的 RAM 大小僅為 32KB,RBL 無法直接將 U-boot 代碼拷貝到 RAM 中,只能加載到 DDR2 外部存儲(chǔ)器中,用 UBL 引導(dǎo) U-boot 的方式進(jìn)行啟動(dòng)。UBL 存放在 DVSDK_DM368_4_02_00_06/psp/flash-utils/DM36X 和flash-uyils/common 目錄下。common 目錄里存放通用程序信息,包括 UBL 的驅(qū)動(dòng)源碼、工具、腳本等,DM36x 存放與平臺(tái)相關(guān)的程序信息。UBL 的工作流程如下圖 4.5 所示。轉(zhuǎn)到 ubl.c 中的 main 函數(shù), main 函數(shù)主要調(diào)用 LOCAL_boot 函數(shù)進(jìn)行實(shí)質(zhì)的引導(dǎo)。 UBL對系統(tǒng)的外圍硬件進(jìn)行初始化設(shè)置并且判斷系統(tǒng)的啟動(dòng)方式, 進(jìn)而完成 U-boot 向 DDR2的拷貝工作。UBL 工作完成并退出,DDR2 中的 U-boot 接管系統(tǒng)的管理權(quán)開始工作運(yùn)行。ubl.c 中的 main 函數(shù)里面有三個(gè)重要的函數(shù)涉及到系統(tǒng)啟動(dòng)方式、硬件初始化和U-boot 拷貝,對應(yīng)的函數(shù)分別為 DEVICE_bootMode()、DVICE_init()和 nandboot_copy。
以下對三個(gè)主要函數(shù)的功能做出分析:
DEVICE_bootMode 函數(shù)通過讀取寄存器的值可獲取系統(tǒng)的啟動(dòng)信息。UBL 會(huì)判斷系統(tǒng)的啟動(dòng)方式,UBL 程序支持 NAND FLASH、NOR FLASH、MMC/SD 和 UART 啟動(dòng)方式。在 4.2.2 小節(jié)中,系統(tǒng)采用 NAND 啟動(dòng)方式。
DEVICE_init 函數(shù)對系統(tǒng)設(shè)備的最底層硬件平臺(tái)進(jìn)行初始化,包括中斷的屏蔽和清除、電源時(shí)鐘使能、復(fù)用引腳功能選擇、時(shí)鐘頻率設(shè)定、DDR2 控制器相關(guān)參數(shù)設(shè)定、EMIF 初始化、串口初始化、I2C 初始化等。NANDBOOT_copy 函數(shù)采用 NAND 啟動(dòng)方式,搜索 U-boot 描述符,通過此描述符配置 U-boot。UBL 完成 U-boot 從 NAND 到 DDR 內(nèi)存的拷貝工作。
1.硬件設(shè)備初始化
對硬件平臺(tái)最底層設(shè)備進(jìn)行初始化是 UBL 工作中最重要的一部分,DEVICE_init 函數(shù)對系統(tǒng)硬件的初始化流程如下圖 4.6 所示。根據(jù) DM368硬件外圍設(shè)備的不同, DEVICE_init函數(shù)對硬件做出相應(yīng)的修改和配置。包括系統(tǒng)屏蔽清除所有中斷、初始化電源時(shí)鐘使能 PSC、管腳復(fù)用寄存器 PINMUX 的配置、系統(tǒng) IO 設(shè)置、系統(tǒng)時(shí)鐘 PLL 的配置以及對 DDR2、外部存儲(chǔ)器、串口、定時(shí)器以及 I2C 總線的初始化。在系統(tǒng)對底層硬件的初始化中,屏蔽清除所有中斷、電源時(shí)鐘使能、系統(tǒng)時(shí)鐘 PLL、串口以及 I2C 總線初始化在系統(tǒng)引導(dǎo)程序中設(shè)置基本一致,故在此不做修改。以下對管腳復(fù)用和 I/O 口的配置、DDR2、EMIF、定時(shí)器初始化做出詳細(xì)設(shè)計(jì)。
(1)管腳復(fù)用寄存器配置如下表 4.2 所示。
(2)外部存儲(chǔ)器(NAND FLASH)的初始化配置如下表 4.3 所示。
(3)定時(shí)器(TIMERO)的初始化配置如下表 4.4 所示
(4)DDR2 初始化
UBL 在對底層硬件初始化的過程中,對 DDR2 的初始化是最為重要的部分。U-boot在由 UBL 拷貝到 DDR2 內(nèi)存之前必須對 DDR2 進(jìn)行初始化工作并對其進(jìn)行相應(yīng)的配置,這是因?yàn)樵谙到y(tǒng)上電后, ARM 內(nèi)核中的 ROM 固化程序 RBL 沒有對 DDR2 進(jìn)行初始化。UBL 對 DDR2 的初始化工作主要由 DEVICE_DDR2Init 函數(shù)完成,UBL 對 DDR2 的初始化流程圖如圖 4.7 所示。
首先,通過電源時(shí)鐘管理模塊 PSC 中的 DEVICE_LPSCTransition(LPSC_DDR2,0,PSC_ENABLE)函數(shù)實(shí)現(xiàn)對 DDR2 模塊的供電和時(shí)鐘使能。其次,在上電或復(fù)位后,DM368 會(huì)對 VPT IO 進(jìn)行校正以實(shí)現(xiàn)對 DDR2 模塊 IO 輸出阻抗的自動(dòng)調(diào)節(jié)。在有關(guān)DDR2 硬件設(shè)計(jì)部分 3.3.2 節(jié)中,DDR_PADREFP 引腳通過精度為 0.5%、大小為 50 歐姆的高精度電阻接地為 VPT IO 的校正提供參考。等待 150 個(gè)時(shí)鐘周期后完成對 VPTIO的 校 正 。 接 下 來 再 次 通 過 電源 時(shí) 鐘 管 理 模 塊 PSC 中 的 函 數(shù) DEVICE_LPSCTTransition(LPSC_DDR2,0,PSC_SYNCRESET) 對 DDR2 進(jìn) 行 同 步 重 啟 , 通 過 函 數(shù)DEVICE_LPSCTTransition(LPSC_DDR2,0,PSC_ENABLE)對電源時(shí)鐘模塊重新使能。然后對 DDR2 的 PHY、參數(shù)、時(shí)鐘和外圍總線優(yōu)先級進(jìn)行設(shè)置。在 DDR2 的 PHY 設(shè)置中,配置 DDRPHYCR 寄存器為 0x000080C6,表示選擇外部選通門,接收器斷電。DDR2 參數(shù)的設(shè)置與 DM368 所外接的具體的 DDR2 芯片有關(guān),根據(jù)實(shí)際所使用的 DDR2 芯片的頁大小、塊數(shù)和總線寬度對 DDR SDCR 寄存器進(jìn)行設(shè)置。系統(tǒng)所選用的 DDR2 的頁大小為 1024,共 8 塊,使用的總線寬度為 16 位,列選通延遲為 5。根據(jù)以上分析將 DDRSDBCR 設(shè)置為0x00D34A32 和 0x0053CA32。 DDR2 的時(shí)鐘配置通過 SDTIMR 和SDTIMR2 實(shí)現(xiàn),分別設(shè)置為 0x45246412 和 0x4225C742。總線突發(fā)優(yōu)先級設(shè)置中,對PBBPR 寄存器設(shè)置為 0x000000FE。刷新控制寄存器設(shè)置中通過對寄存器 SDRCR 設(shè)置為 0X83A 來實(shí)現(xiàn)。最后對 DDR2 同步重啟,電源時(shí)裝模塊重新使能,返回到 DDR2 的初始化狀態(tài),初始化結(jié)束。
2.UBL 對 U-boot 的啟動(dòng)引導(dǎo)
UBL 在完成對底層硬件的初始化后,接下來就是將 NAND FLASH 中的 U-Boot 拷貝到 DDR2 內(nèi)存中,引導(dǎo) U-Boot 啟動(dòng)。UBL 對 U-Boot 啟動(dòng)引導(dǎo)流程圖如圖 4.8 所示。在 UBL 對 U-Boot 的有效描述符開始搜索之前,首先應(yīng)該進(jìn)行對描述符搜尋的起始地址和讀取描述符所需內(nèi)存空間進(jìn)行設(shè)置。在此設(shè)置描述符的起始搜尋地址為BANK8~BANK10。使用函數(shù) rxBuf=(Uint8*)UTIL_allocMem((APP_IMAGE_SIZE))對內(nèi)存空間進(jìn)行設(shè)置,在此對 APP_IMAGE_SIZE 的取值為( ( (Uint32)&DDRSize)>>3。在不超出最大內(nèi)存值的情況下,為 U-Boot 的描述符分配 16MB 的內(nèi)存空間以保證內(nèi)存空間不會(huì)溢出。內(nèi)存空間分配完成后,可通過函數(shù) NAND_open 獲取并配置 NAND Flash的信息,包括 NAND Flash 的塊數(shù)和頁數(shù)信息、起始地址、數(shù)據(jù)總線位數(shù)以及校驗(yàn)信息。上述配置工作完成后, UBL 通過函數(shù) NAND_readPage 對 U-Boot 的描述符進(jìn)行搜索,搜索的范圍從起始塊號(hào)的第 0 頁開始直至最后塊號(hào)的最后一頁結(jié)束。當(dāng)搜索到的描述符為有效時(shí), UBL 會(huì)通過該有效描述符獲取 U-Boot 向 DDR2 寫入所需參數(shù)。通過該參數(shù),UBL 可以完成以下兩個(gè)任務(wù):U-Boot 向 DDR2 內(nèi)存的拷貝所需完成的準(zhǔn)備工作以及分配 U-Boot 在 DDR2 內(nèi)存中實(shí)際所在的空間位置。然后 UBL 通過函數(shù) NAND_readPage將 U-Boot 搬運(yùn)到 DDR2 內(nèi)存中。搬運(yùn)過程中的數(shù)據(jù)都會(huì)進(jìn)行 ECC 校驗(yàn)糾錯(cuò)。如果數(shù)據(jù)拷貝失敗,會(huì)進(jìn)行第二次拷貝。如果第二次拷貝還未成功,UBL 會(huì)重新跳到 UBL 搜索頁繼續(xù)搜索 U-Boot 有效描述符,直到終止塊號(hào)的最后一頁完全拷貝到 DDR2 內(nèi)存中。五、U-Boot 啟動(dòng)過程分析
U-Boot(Univesal Boot Loader)是遵循 GPL 條款開發(fā)的開放源碼項(xiàng)目[56],廣泛應(yīng)用于嵌入式系統(tǒng)開發(fā)中。它不僅支持嵌入式 Linux 系統(tǒng)的引導(dǎo),同時(shí)還支持 NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS 等嵌入式操作系統(tǒng),而且 U-Boot 對硬件的適應(yīng)性也很好,支持 Power PC、MIPS、x86、ARM、NIOS、XScale 等多種處理器架構(gòu)[57]。
U-boot 具有以下優(yōu)點(diǎn):
1.源代碼對外開放,開發(fā)人員可以進(jìn)行修改并共享;
2.支持多種處理器系列和嵌入式操作系統(tǒng)。
3.技術(shù)成熟、性能穩(wěn)定,以及非常高的可靠性。
4.功能設(shè)置靈活,引導(dǎo)產(chǎn)品需求與發(fā)布。
5.設(shè)備驅(qū)動(dòng)源碼豐富,支持常見的外圍設(shè)備如:串口、以太網(wǎng)、SDRAM、FLASH、LCD、鍵盤、EEPROM 等。
6.開發(fā)調(diào)試文檔非常豐富,網(wǎng)絡(luò)支持強(qiáng)大。
U-Boot 的啟動(dòng)過程大致可分為兩個(gè)階段。第一階段代碼一般使用匯編語言代碼實(shí)現(xiàn),執(zhí)行啟動(dòng)代碼 start.s,主要完成部分硬件設(shè)備初始化、設(shè)置異常入口地址和異常處理函數(shù)、配置 PLL 確定系統(tǒng)主頻、屏蔽中斷、初始化 I/O 寄存器、關(guān)閉 MMU、初始化存儲(chǔ)空間、加載 U-Boot 的第二段代碼到 DDR 內(nèi)存中、設(shè)置堆棧大小,并最終跳轉(zhuǎn)到 C代碼的 start_armboot()函數(shù)繼續(xù)執(zhí)行。第二階段代碼采用 C 語言實(shí)現(xiàn),主要完成包括中斷的處理、環(huán)境變量設(shè)置、串口設(shè)置等。采用 C 語言的好處是能夠較好的實(shí)現(xiàn)復(fù)雜的功能,而且程序具有較高的可讀性,代碼的移植也比較方便。第一階段主要功能主要是通過函數(shù) start.s 來實(shí)現(xiàn)的,它對部分硬件設(shè)備進(jìn)行初始化,函數(shù) start.s 啟動(dòng)過程如下圖 4.9 所示。
函數(shù) start.s 首先進(jìn)行復(fù)位使系統(tǒng)進(jìn)入 SVC32 超級保護(hù)模式。接著對時(shí)鐘和處理器的主頻進(jìn)行設(shè)置,依靠 cpu_init_crit 代碼實(shí)現(xiàn),cach 和 MMU 的關(guān)閉也依靠此代碼實(shí)現(xiàn)。處理器工作頻率、總線頻率和存儲(chǔ)器時(shí)鐘頻率的調(diào)節(jié)及初始化工作依據(jù)cpu_init_crit 代碼中的函數(shù) lowlevel_init 進(jìn)行實(shí)現(xiàn)。函數(shù) relocate 對 U-Boot 進(jìn)行重新定位,完成第二階段代碼的拷貝工作。實(shí)際拷貝函數(shù) copy_loop 將 U-Boot 程序拷貝到 TEXT_BASE 開始地址的空間中。初始化堆棧函數(shù) stack_setup 實(shí)現(xiàn)對堆棧的初始化。函數(shù) clear_bass 對未初始化全局變量的 bass 段進(jìn)行初始化,通過函數(shù) clbss_1 循環(huán)清除 bass。最后跳轉(zhuǎn)到第二階段起始代碼入口函數(shù)_star_armboot。第二階段中函數(shù) start_armboot 是 Bootloader 代碼中第一個(gè)被執(zhí)行的 C 語言函數(shù),它也是 C 語言代碼的主函數(shù)。start_armboot 中的主要函數(shù)功能如下表 4.5 所示。
當(dāng)所有的第一階段 start.s 和第二階段 start_armboot 函數(shù)代碼執(zhí)行完成后,系統(tǒng)進(jìn)入main_loop 中,循環(huán)等待用戶從串口輸入的命令并執(zhí)行該命令。
總結(jié)
以上是生活随笔為你收集整理的DM368开发 -- Bootloader 开发(转毕设)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringCloud Eureka服务
- 下一篇: DM368开发 -- uboot 使用