首發:嵌入式客棧
作者:逸珺
導讀:前文對U-Boot架構設計做了分析,本文來梳理一下U-Boot在具體板子上的移植工作,主要記錄整體思路、要點,以觸類旁通而記之。
1.收集Boot相關信息
NanoPC-T3 是友善之臂為企業用戶設計的主板,采用三星八核Cortex -A53架構的S5P6818處理器。其主要技術參數:
- CPU: S5P6818, 動態運行主頻400Mhz--1.4GHz 8核
- DDR3 RAM: 1GB,采用2片K4B4G1646D
- SD: 標準SD卡槽一個
- eMMC:8GB
- HDMI: HDMI 1.4a, Type A型口,1080P高清顯示
- DVP Camera接口: 24pin, 0.5mm間距,FPC貼片豎座
- GPIO擴展接口: 4個UART, 1路I2C, 1路SPI, 3路PWM,9個GPIO
- …
- 1SOC Boot相關信息
需要將采用該SOC的方式以U-Boot引導,那么首先應該將Boot的相關信息進行收集分析。
支持的Boot模式:
復位首條指令直接從外部靜態存儲器引導。
- 內部ROM boot
- NAND boot with Error Correction
- SD/MMC/SDFS (SD FAT File system) boot
- SPI Serial EEPROM boot
- UART boot
- USB Boot
自< SEC/_S5P6818X/_Users/_Manual/_preliminary/_Ver/_0.00.pdf>
SOC內置了20KB的iROMBOOT,這是一段固化的boot程序,通過識別外部Boot配置進入相應的Boot模式,完成內部boot到用戶boot程序的第一階段Boot。
從datasheet 看見該SOC內部實現了iROMBOOT,而SPL(Secondaryprogramloader)是u-boot第一階段執行的代碼。主要負責搬移u-boot第二階段的代碼到。iROMBOOT已經實現了這一功能,故不需要用戶實現SPL了。
1.2 NanoPC-T3 板級信息
由于boot一般與板子的設計配置相關,大多由IO口配置進行選擇,既然支持上述如何之多的Boot模式,那么拿到的板子又支持哪些引導模式呢?
可見nanoPC T3僅支持SDMMC Boot模式,進入對應的章節,可看出支持三個SD通道。通過從SD存儲卡,MMC存儲卡和eMMC中讀取iROMBOOT并通過使用SDHC模塊將其加載到內存中,iROMBOOT執行用戶啟動代碼。此方法稱為SDHCBOOT。SDCLK輸出400 kHz用于識別,輸出24 MHz用于數據傳輸。
SD3已經電路下拉為低:
- 默認CAM1/_D3為高,用戶boot通道默認為CH0,電路板設計為SD卡
SD卡是(secure digital memory card)安全數碼卡,是一種基于半導體快閃記憶器的新一代記憶設備,是在MMC基礎上發展起來的,其內部存儲介質大都為NAND Flash增加了兩個主要特色:
可以設置所存儲的使用權限,防止數據被他人復制;第二是傳輸速度比2.11版mmc卡快。
特性:
1)可選通信協議:SD模式和SPI模式
2)可變時鐘頻率:0~25MHz
3)通信電壓范圍:2.0~3.6V
4)數據壽命:10萬次編程/擦除
5)正向兼容MMC卡;
6)運行在25M的頻率上,數據帶寬是4位,因此最大傳輸速率是12.5MHz(12.5兆字節每秒) <自百度知道>
eMMC (Embedded Multi Media Card)是MMC協會訂立、主要針對手機或平板電腦等產品的內嵌式存儲器標準規格。eMMC在封裝中集成了一個控制器,提供標準接口并管理閃存,使得手機廠商就能專注于產品開發的其它部分,并縮短向市場推出產品的時間。其內部存儲介質大都為NAND Flash。
硬件地址空間:
該SOC具有兩個內存控制器:
- MCU-A:DDR3 / LVDDR3(低壓DDR3)/ LPDDR3 / LPDDR2
- MCU-A由DREX和DDRPHY組成
- 支持DDR3 /LVDDR3(低壓DDR3)/ LPDDR3 / LPDDR2內存
- 支持2 GB的8/16/32位SDRAM
- 單個存儲區(32位數據總線寬度)
- 支持掉電模式
- 支持自我刷新模式
- MCU-S:靜態存儲器
- 靜態內存
- Static兩個靜態存儲芯片選擇
- NAND閃存接口
- 23位地址支持使用鎖存器地址
- SLC NAND,帶ECC的MLC NAND(支持BCH算法)
- 靜態內存映射陰影
板上網口采用什么芯片需要,RTL8211E-VB-CG 集成 10/100/1000M 以太網收發器,顯示接口:RGB LCD接口/HDMI
至此,第一階段收集了那些為移植需要準備的信息?
- S5P6818 ,8核,armv8,64位SOC
- Boot模式,SDMMC Boot模式,支持兩個通道,默認通道Ch0板載eMMC, 按住Boot 按鍵,CH0:SD Boot,不需要SPL
- 內存地址:0x40000000—7FFF FFFF 1G DDR3(2片K4B4G1646D 4Gbit/chip)
- 控制臺:UART0
- 網口:RTL8211E-VB-CG集成10/100/1000M 以太網收發器。
- LCD:RGB LCD接口/HDMI
2.移植
2.1 明確移植內容
在具體實施之前,首先須總體上明確How to do:
2.2明確Boot流程
明確Boot流程,需要明確有哪些地方需要根據所選SOC,板級硬件設計做出移植:
如前文分析,u-boot的啟動流程主要分亮部分。
第一階段:芯片復位,執行復位跳轉,從自各自芯片的start.S開始執行匯編代碼
一般而言,start.S 位于- arch/ic/_xxx/cpu/start.S
如:
- arch/arm/cpu/armv7/start.S
- arch/powerpc/cpu/mpc83xx/start.S
-arch/mips/cpu/start.S
為什么這是復位入口呢?這取決于如何鏈接,由u-boot.lds指定:
鏈接文件位于./arch/arm/cpu/armv8/u-boot.lds
注:因為nanoPC-T3 S5P6818的SOC是一顆8核A53核,A53是armv8架構。
第二階段:lowlevel/_init(),board/_init/_f(),board/_init/_r():
lowlevel/_init():
- 目的:允許執行達到oard/_init/_f()的基本初始化
- 沒有global/_data或BSS。
- 沒有堆棧(ARMv7可能有一個堆棧,但是很快就會被刪除)
- 不得設置SDRAM或使用控制臺
- 必須只做最少的工作,以允許執行繼續到board/_init/_f()
- 幾乎不需要
- 從此函數正常返回
board/_init/_f():
- 目的:初始化CPU運行環境以準備運行board/_init/_r():即初始化SDRAM和UART
- global/_data可用
- 堆棧位于SRAM中
- BSS不可用,因此您不能使用全局/靜態變量,只能使用堆棧變量和global/_data
- 非SPL特定說明:
- 調用dram/_init()設置DRAM。 如果已經在SPL中完成,則無法執行任何操作
- SPL特定說明:
- 可以根據需要使用自己的版本覆蓋整個board/_init/_f()函數。
- preloader/_console/_init()可以在依據需要調用
- 須初始化SDRAM,以及初始化UART
- -不需要清除BSS段,由crt0.S完成
- -必須從此函數正常返回(不要直接調用board/_init/_r())
此處清除了BSS。對于SPL,如果定義了CONFIG/_SPL/_STACK/_R,則此時將堆棧和global/_data重定位到CONFIG/_SPL/_STACK/_R/_ADDR之下。 對于非SPL,U-Boot被重定位以在內存頂部運行。
board/_init/_r():
- 目的:主要執行,通用代碼
- global/_data可用
- SDRAM可用
- BSS可用,可以使用所有靜態/全局變量
- 執行最終繼續到main/_loop()
- 非SPL特定說明:
- U-Boot重定位到內存頂部,并且現在從那里開始運行。
- SPL特定說明:
-
如果定義了CONFIG/_SPL/_STACK/_R并且
CONFIG/_SPL/_STACK/_R/_ADDR指向SDRAM,則堆棧可選地位于SDRAM中
- 在這里可以調用preloader/_console/_init()-通常是通過定義CONFIG/_SPL/_BOARD/_INIT然后提供包含此調用的spl/_board/_init()函數來完成的
- 加載U-Boot或(在falcon模式下)Linux
以上關于lowlevel/_init(),board/_init/_f(),board/_init/_r()翻譯自./README
這里有幾個概念需要進一步解析,方便下面理解:
- 堆(heap):堆的管理由C庫實現的,Linux中是一般由Glibc,取決于選用什么C庫。內存的獲取與釋放由程序員通過調用C庫中的malloc/free進行操作,C庫中的動態內存管理單元具體實現。大體上在工程中指定堆的大小,C庫中的堆管理器將這片內存進行動態管理,這里需要用到一些數據結構算法對這片內存區進行動態管理。如果要對堆的管理實現進行分析,可以參考glibc的源代碼。
- 棧(stack):由編譯器實現棧的管理,由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧。
堆/棧的大小由下面的宏定義:
- CONFIG/_SYS/_MALLOC/_LEN 指定堆大小
- CONFIG/_SYS/_RESERVE/_MEM/_SIZE/ CONFIG/_SYS/_MALLOC/_LEN 一起指定棧大小
Stack size= CONFIG/_SYS/_RESERVE/_MEM/_SIZE-
CONFIG/_SYS/_MALLOC/_LEN
這幾個宏定義了內存上界、堆上下界、棧的上下界有編譯器、C庫實現越界保護機制。
global/_data:
該結構體收集板子的基本信息,內存,名稱,CPU時鐘,環境變量,標準IO,設備驅動句柄等等。
紅色部分信息將堆分配情況與U-Boot全局數據結構關聯。
- bss段:bss段(bss segment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域。bss是英文Block Started by Symbol的簡稱。bss段屬于靜態內存分配。
- data段:數據段(data segment)通常是指用來存放程序中已初始化的全局變量的一塊內存區域。數據段屬于靜態內存分配。
-
text段:代碼段(code segment/text segment)通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,并且內存區域通常屬于只讀(某些架構也允許代碼段為可寫,即允許修改程序)。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量等。
一個程序本質上由這三個段由鏈接器鏈接而成。
2.3 創建板子文件
位置board/my/_vendor/my/_board/my/_board.c, 對于nanoPC-T3而言
./board/s5p6818/nanopi3/ board.c
- dram/_init 實現內存初始化
-
board/_init 實現GPIO初始化、啟動設備初始化等操作,這與板子的硬件息息相關。
需聲明DECLARE/_GLOBAL/_DATA/_PTR指針,因為本模塊需要對gd成員進行初始化,ARM32等價于r9寄存器,ARM64等價于寄存器x18
位于./arch/arm/include/asm/global/_data.h
2.4 創建Kconfig配置文件
board/my/_vendor/my/_board/Kconfig
需定義Kconfig對于board需要的相關變量SYS/_BOARD,SYS/_VENDOR,SYS/_CONFIG/_NAME。
由于S5P6818是一顆64位芯片,那么32位/64位將變成可選配置。故這里新創建了S5P6818/_FEATURES用以配置32位/64位,當取值為no表示為32位配置。
- SYS/_BOARD,SYS/_VENDOR 用于給kuild識別在那個board,verder目錄需去編譯相應源文件
- SYS/_CONFIG/_NAME 用于給kuild識別在哪里去尋找板子頭文件
include/configs/SYS/_CONFIG/_NAME.h
2.6創建板子Makefile
board/my/_vendor/my/_board/Makefile 對nanoPC-T3而言:
obj-y:=board.o hwrev.o onewire.o lcds.o
由于需要實現LCD以及單線觸摸控制器,則需要將上述文件編譯。
2.7 創建板子defconfig
configs/my/_board/_defconfig, 對nanoPC-T3而言:
s5p6818/_nanopi3
/_defconfig
對于新版的U-boot已支持make menuconfig,可以運行該命令進行其他配置,然后將生成的.config文件拷貝至此。
mv .config ./configs/s5p6818/_nanopi3/_defconfig
主要裁剪支持的驅動,以及shell命令等
注:舊版本的U-Boot使用boards.cfg添加板子。
2.8創建板子頭文件
include/confi gs/my/_board.h,對nanoPC-T3而言:
include/confi gs/ s5p6818/_nanopi3.h
環境變量:
這些定義由./common下環境變量管理模塊負責維護,其結構體定義如下,主要為字符串常量。
2.8 引導分析
為了能夠重新映射內存,U-Boot隨后跳至其鏈接地址。為了能夠在C中實現初始化代碼,在內部雙端RAM中設置了一個(很小的)初始堆棧(如果CPU提供了諸如MPC8xx或MPC8260之類的功能),或者在數據的鎖定部分中緩存。之后,U-Boot初始化CPU內核,緩存和SIU。
接下來,使用初步映射來映射所有可用的存儲體。例如,將它們放在512 MB邊界上(0x20000000的倍數:0x00000000和0x20000000上的SDRAM,0x40000000和0x60000000上的Flash,0x80000000上的SRAM)。然后,將UPMA編程用于SDRAM訪問。使用臨時配置,將運行簡單的內存測試,以確定SDRAM存儲區的大小。
如果有多個SDRAM存儲區,并且存儲區的大小不同,則首先映射最大的存儲區。對于相等的大小,將首先映射第一個存儲區(CS2#)。第一個映射始終是針對地址0x00000000的,后面緊跟著任何其他存儲區以創建從0開始的連續存儲器。
然后,監視器將自身安裝在SDRAM區域的高端,并分配內存供malloc()和全局Board Info數據使用;同樣,將異常矢量代碼復制到低RAM頁面中,并建立最終堆棧。
只有在此重定位之后,才能擁有“正常”的C環境。由于受到多種方式的限制,主要是因為從ROM運行,并且必須將代碼重定位到RAM中的新地址運行。
至于上述過程重定向,主要利用鏈接綁定以實現符號表位置可知,從將u-boot映象拷貝到內存可實現運行切換。
/*指定輸出格式elf64-littleaarch64*/
而在./arch/arm/lib/sections.c 定義了對應的全局符號,這樣就實現了鏈接地址綁定:
char __bss_start[0] __attribute__((section(".__bss_start")));
下面對crt0/_64.S 匯編代碼做簡要注釋幫助理解重定向過程:
ENTRY(_main)/*聲明入口*/
總結:
- 思路須清楚,不要一開始關注細節
- 采用漸進明細、逐步迭代的方法論
- u-boot 其核心在于將系統成功引導。
_—END_—
審核編輯 黃昊宇-
u-boot
+關注
關注
0文章
121瀏覽量
38315 -
深度學習
+關注
關注
73文章
5516瀏覽量
121553
發布評論請先 登錄
相關推薦
U-boot的基本介紹
![<b class='flag-5'>U-boot</b>的基本介紹](https://file1.elecfans.com/web2/M00/8C/C4/wKgaomSxDC-AIi1QAACKegMzhAU876.png)
嵌入式系統中U-Boot 基本特點及其移植方法
嵌入式系統中U-Boot 基本特點及其移植方法
基于S3C44B0的U-Boot啟動分析和移植實現
U-Boot的啟動及移植分析
嵌入式U-BOOT的啟動流程及移植
剖析基于nanoPC-T3的U-Boot移植過程
![剖析基于<b class='flag-5'>nanoPC-T3</b>的<b class='flag-5'>U-Boot</b><b class='flag-5'>移植</b><b class='flag-5'>過程</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
U-boot的QSPI驅動移植方法及驗證方法
![<b class='flag-5'>U-boot</b>的QSPI驅動<b class='flag-5'>移植</b>方法及驗證方法](https://file.elecfans.com/web2/M00/9F/06/poYBAGQ4uJyAR2S0AAFCsQC4t40453.png)
評論