本文章首發(fā)地址:https://www.lgfccl.xyz 隨時down 機,轉(zhuǎn)載注明出處謝謝
UBOOT 概述
1 U-Boot簡介
U-Boot堕扶,全稱 Universal Boot Loader南用,是遵循 GPL 條款的開放源碼項目李剖。從 FADSROM尖飞、8xxROM琉挖、PPCBOOT 逐步發(fā)展演化而來玻侥。其源碼目錄决摧、編譯形式 與 Linux 內(nèi)核很相似,事實上,不少 U-Boot 源碼就是相應(yīng)的 Linux 內(nèi)核源程序的簡化掌桩,尤其是一些設(shè)備的驅(qū)動程序边锁,如網(wǎng)絡(luò)設(shè)備、flash拘鞋、ddr等砚蓬,這從 U-Boot 源碼的注釋中能體現(xiàn)這一點。
U-Boot 不僅僅支持嵌入式 Linux 系統(tǒng)的引導(dǎo)盆色,它還支持如NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS 嵌入式OS灰蛙。硬件支持包括 MIPS、 x86隔躲、ARM摩梧、Powerpc、Zynq 等諸多常用處理器宣旱。 這兩個特點正是 U-Boot 項目的開發(fā)目標(biāo)仅父,即支持盡可能多的嵌入式處理器和嵌 入式操作系統(tǒng)。
這個項目起源于 Magnus Damm.[1] 在 8xx PowerPC 架構(gòu)下寫的引導(dǎo)加載程序: 8xxROM浑吟。1999 年十月笙纤,Wolfgang Denk 將項目移轉(zhuǎn)到 SourceForge.net,但 SourceForge.net 不允許數(shù)字開頭的項目名稱组力,所以改名為 PPCBoot省容。PPCBoot 在 2000年 7 月 19 日第一次公開發(fā)布 0.4.1 版。也正是因此燎字,U-Boot對PPC支持最為豐富腥椒。
- 選擇 u-boot 的理由:
? 開放源碼
? 支持多種嵌入式OS,如 Linux候衍、NetBSD笼蛛、VxWorks、QNX等
? 支持多種處理器架構(gòu)蛉鹿,如PowerPC滨砍、ARM、x86妖异、MIPS惋戏、XScale、Zynq(ARM);
? 較高的可靠性和穩(wěn)定性;
? 豐富的設(shè)備驅(qū)動源碼随闺,如串口日川、以太網(wǎng)、SDRAM矩乐、FLASH等;
? 較為豐富的開發(fā)調(diào)試文檔與強大的網(wǎng)絡(luò)技術(shù)支持;
2 目錄結(jié)構(gòu)
- board 目標(biāo)板相關(guān)文件龄句,主要包含SDRAM回论、FLASH驅(qū)動;
- common 獨立于處理器體系結(jié)構(gòu)的通用代碼分歇,如內(nèi)存大小探測與故障檢測傀蓉;
- cpu 與處理器相關(guān)的文件。如mpc8xx子目錄下含串口职抡、網(wǎng)口葬燎、LCD驅(qū)動及中斷初始化等文件;
- driver 通用設(shè)備驅(qū)動缚甩,如CFI FLASH驅(qū)動(目前對INTEL FLASH支持較好)
- doc U-Boot的說明文檔谱净;
- examples可在U-Boot下運行的示例程序;如hello_world.c,timer.c擅威;
- include U-Boot頭文件壕探;尤其configs子目錄下與目標(biāo)板相關(guān)的配置頭文件是移植過程中經(jīng)常要修改的文件;
- lib_xxx 處理器體系相關(guān)的文件郊丛,如lib_ppc, lib_arm目錄分別包含與PowerPC李请、ARM體系結(jié)構(gòu)相關(guān)的文件;
- net 與網(wǎng)絡(luò)功能相關(guān)的文件目錄厉熟,如bootp,nfs,tftp导盅;
- post 上電自檢文件目錄。尚有待于進一步完善揍瑟;
- rtc RTC驅(qū)動程序白翻;
- tools 用于創(chuàng)建U-Boot S-RECORD和BIN鏡像文件的工具;
(
以上關(guān)于目錄結(jié)構(gòu)的說明只適應(yīng)u-boot-2010.06之前版本月培。u-boot-2010.06之后目錄結(jié)構(gòu)改變
cpu與lib_arch合二為一嘁字,命名arch
增加include folder
分離出通用庫文件夾lib
)
3 主要功能
U-Boot 可支持的主要功能如下:
- 系統(tǒng)引導(dǎo),Linux 支持最為強勁;
- 支持NFS掛載恩急、RAMDISK(壓縮或非壓縮)形 式的根文件系統(tǒng);
- 支持NFS掛載杉畜、從FLASH中引導(dǎo)壓縮或非壓縮系統(tǒng)內(nèi)核;
- 支持目標(biāo)板環(huán)境參數(shù)多種存儲方式,如FLASH衷恭、NVRAM此叠、EEPROM;
- CRC32 校驗,可校驗 FLASH 中內(nèi)核随珠、RAMDISK 鏡像文件是否完好;
- 設(shè)備驅(qū)動 串口灭袁、SDRAM、FLASH窗看、以太網(wǎng) 茸歧、USB、PCMCIA显沈、PCI软瞎、RTC 等驅(qū)動支持;
- 上電自檢功能 SDRAM逢唤、FLASH 大小自動檢測;SDRAM 故障檢測;CPU型號;
- 特殊功能 XIP 內(nèi)核引導(dǎo);
二 UBOOT移植分析與流程
大多數(shù)BootLoader都分為stage1和stage2兩大部分,U-boot也不例外涤浇。依賴于cpu體系結(jié)構(gòu)的代碼(如設(shè)備初始化代碼等)通常都放在stage1且可以用匯編語言來實現(xiàn)鳖藕,而stage2則通常用C語言來實現(xiàn),這樣可以實現(xiàn)復(fù)雜的功能只锭,而且有更好的可讀性和移植性著恩。
1、 stage1(start.s代碼結(jié)構(gòu))
? U-boot的stage1代碼通常放在start.s文件中蜻展,它用匯編語言寫成喉誊,其主要代碼部分如下:
(1) 定義入口。由于一個可執(zhí)行的image必須有一個入口點纵顾,并且只能有一個全局入口裹驰,通常這個入口放在rom(Flash)的0x0地址,因此片挂,必須通知編譯器以使其知道這個入口幻林,該工作可通過修改連接器腳本來完成。
(2)設(shè)置異常向量(exception vector)音念。
(3)設(shè)置CPU的速度沪饺、時鐘頻率及中斷控制寄存器。
(4)初始化內(nèi)存控制器 闷愤。
(5)將rom中的程序復(fù)制到ram中整葡。
(6)初始化堆棧 。
(7)轉(zhuǎn)到ram中執(zhí)行讥脐,該工作可使用指令ldrpc來完成遭居。
2、 stage2(C語言代碼部分)
lib_arm/board.c中的start armboot是C語言開始的函數(shù)旬渠,也是整個啟動代碼中C語言的主函數(shù)俱萍,同時還是整個u-boot(armboot)的主函數(shù),該函數(shù)主要完成如下操作:
(1)調(diào)用一系列的初始化函數(shù)告丢。
(2)初始化flash設(shè)備枪蘑。
(3)初始化系統(tǒng)內(nèi)存分配函數(shù)。
(4)如果目標(biāo)系統(tǒng)擁有nand設(shè)備岖免,則初始化nand設(shè)備岳颇。
(5)如果目標(biāo)系統(tǒng)有顯示設(shè)備,則初始化該類設(shè)備颅湘。
(6)初始化相關(guān)網(wǎng)絡(luò)設(shè)備话侧,填寫ip,c地址等。
(7)進入命令循環(huán)(即整個boot的工作循環(huán))闯参,接受用戶從串口輸入的命令瞻鹏,然后進行相應(yīng)的工作术羔。
1 獲取U-Boot源代碼
如下舉例,由于此服務(wù)器基本處于爹媽不維護狀態(tài)乙漓,所以建議直接瀏覽器下載壓縮包级历,或者wget下載,如果用git clone下載很慢叭披。
- 官方版本:這個版本是U-Boot開源社區(qū)維護的寥殖。
- Powerpc私有Git:這個版本是Freescale(被NXP收購)自己維護的目前已經(jīng)不更新,不過是最好的選擇涩蜘。
- Yocto SDK 工具:bitbake -c compile -f u-boot 獲取嚼贡,不建議 SDK占用資源大(50G),且編譯基于bitbake同诫,bitbake又基于python開發(fā)效率不高粤策,對于嵌入式編成,優(yōu)選利用交叉編譯環(huán)境误窖。
> wget http://git.freescale.com/git/cgit.cgi/auto/u-boot.git/snapshot/u-boot-2016.01_bsp14.0.tar.gz
> tar xvf u-boot-2016.01_bsp14.0.tar.gz
> cd u-boot-2016.01_bsp14.0
> ls -alh
- 如上獲取了官方支持的最新的U-Boot源代碼叮盘,接下來獲取交叉編譯工具(不通內(nèi)核架構(gòu)工具不一樣)方式也有3種:
- Yocto SDK 工具: 可以通過官方工具進行生成,具體方式按照官方[User Guide]([https://freescaleesd.flexnetoperations.com/337170/767/8926767/QorIQ%20SDK%20v1.8%20Info%20Center.pdf?ftpRequestID=7521903397&server=freescaleesd.flexnetoperations.com&dtm=DTM20200114145812NTQ5NzQwNTAy&authparam=1579042692_3dc60c9668a2e35e5b8887f88c5f05e4&ext=.pdf](https://freescaleesd.flexnetoperations.com/337170/767/8926767/QorIQ SDK v1.8 Info Center.pdf?ftpRequestID=7521903397&server=freescaleesd.flexnetoperations.com&dtm=DTM20200114145812NTQ5NzQwNTAy&authparam=1579042692_3dc60c9668a2e35e5b8887f88c5f05e4&ext=.pdf))自行生成即可霹俺。
source ./fsl-setup-poky -h 查看支持的參考Demo板卡
source ./fsl-setup-poky -m 選擇你的處理器如P2020RDB
bitbake fsl-toolchain
cd build_<machine>_release/tmp/deploy/sdk
./fsl-networking-eglibc-<host-system>-<core>-toolchain-<release>.sh
默認(rèn)安裝/opt/下直接允許即可
尋求技術(shù)支持索要:最直接柔吼,最快速,推薦丙唧。
-
我分享在github的SDK編譯出的文件愈魏,避免下載Yocto SDK工具。
2 P2020芯片U-Boot配置
2.1 獲取Demo板卡參考配置
P2020芯片原Freescale出過兩個Demo板卡想际,我們?nèi)∑渲蠵2020RDB-PC 進行參考即可
> cd u-boot-2016.01_bsp14.0
> source /opt/fsl-networking/QorIQ-SDK-V1.6/environment-setup-ppce500v2-fsl-linux-gnuspe;
> unset LDFLAGS;
> make distclean;make P2020RDB-PC_config;make -j8;
> powerpc-fsl-linux-gnuspe-objdump -j .text -l -C -S u-boot >uboot.map;
到此培漏,你應(yīng)該可以獲得bin,大小根據(jù)頭文件include/configs/p1_p2_rdb_pc.h里的 #define CONFIG_SYS_TEXT_BASE 0xeff40000決定胡本,這個地址到0xefffffff正好是768K大小牌柄。這里你看你會有疑問,e500V2架構(gòu)Core第一條指令不是去0xFFFFFFFC去取指令嗎打瘪,且一般是跳轉(zhuǎn)到前4K Page Size處友鼻,沒錯這里就是由于兩個default決定的了傻昙。
請參考:P2020RM的4.3.3章節(jié):Boot page tranlation,E500CORERM 1.5.1 章節(jié) Initial Instruction Fetch
? 我們這里不展開討論TLB以及MMU闺骚,LAW的概念,后續(xù)我會根據(jù)時間繼續(xù)進行介紹妆档。
2.2 自定義板卡配置
如上僻爽,你已經(jīng)獲取了u-boot.bin,通過code warrior jtag或者usb code warrior jtag 燒寫程序到Nor的0xfff40000地址即可啟動贾惦,可能是亂碼胸梆,根據(jù)至于code warrior 的永久license和如何根據(jù)自己Nor Flash生成tcl敦捧,生成Nor的自定義型號,這里不展開討論碰镜,后續(xù)看時間專門出一片code warrior 工具使用介紹(自己看help也夠用了)兢卵,不過這個cw工具官方已經(jīng)不在維護,建議不要過度依賴绪颖。cw的后臺server是ccs服務(wù)程序秽荤,這個程序又可以寫一片博客了,看時間進行總結(jié)吧柠横。
- 這里指列舉幾個看你修改的文件窃款,請自行修改:
Include/configs/p1_p2_rdb_pc.h --->修改sys clk,ddr clk牍氛,nor law reg晨继,ddr2(3) 參數(shù)等。
- board/freescale/p1_p2_rdb/下的law.c tab.c p1_p2_rdb.c 這三個文件就是tlb和law修改搬俊,按需修改紊扬。
- 期間可能需要修改Makefile,如編譯遇到libgcc問題唉擂,請自行g(shù)oogle 搜nxp論壇即可珠月。
- 到此U-Boot P2020自定義板卡移植結(jié)束,當(dāng)然前提是你板子的硬件設(shè)計已經(jīng)OK楔敌,比如啟動位置啤挎,各種clk配置陪好。
3 U-Boot 啟動分析
本部分涉及的代碼非常多卵凑,所以只能對關(guān)鍵代碼進行解釋庆聘,還有更多部分涉 及到 POWERPC 體系結(jié)構(gòu)、MMU 工作原理等勺卢,這里對這些內(nèi)容不再敘述伙判,但是 使用U-Boot過程中,上述內(nèi)容是必備的黑忱,可以參考《POWERPC 體系結(jié)構(gòu)》與 《MMU 工作原理》等手冊相關(guān)內(nèi)容宴抚。
3.1 入口函數(shù)
打開文件,vim arch/powerpc/cpu/mpc85xx/start.S 文件開始定義了:
CPU 復(fù)位后做了三件事情甫煞,1清寄存器菇曲、2設(shè)置異常向量表、3設(shè)置更多更大TLB供CPU看見地址:
/*
* e500 Startup -- after reset only the last 4KB of the effective
* address space is mapped in the MMU L2 TLB1 Entry0. The .bootpg
* section is located at THIS LAST page and basically does three
* things: clear some registers, set up exception tables and
* add more TLB entries for 'larger spaces'(e.g. the boot rom) to
* continue the boot procedure.
* Once the boot rom is mapped by TLB entries we can proceed
* with normal startup.
*
*/
.section .bootpg,"ax"
.globl _start_e500
_start_e500:
/* Enable debug exception */
li r1,MSR_DE
mtmsr r1
/*
* If we got an ePAPR device tree pointer passed in as r3, we need that
* later in cpu_init_early_f(). Save it to a safe register before we
* clobber it so that we can fetch it from there later.
*/
mr r24, r3
接下來就是根據(jù)不同芯片的ERRATUM 進行操作抚吠,和關(guān)閉L2常潮,L1禁止cache的操作,源碼很簡單這里不粘貼楷力,只撿最關(guān)鍵幾點喊式,接下來是初始化異常向量表孵户,告訴CPU出現(xiàn)下列異常應(yīng)該怎么辦:
/* Interrupt vectors do not fit in minimal SPL. */
#if !defined(MINIMAL_SPL)
/* Setup interrupt vectors */
lis r1,CONFIG_SYS_MONITOR_BASE@h
mtspr IVPR,r1
li r4,CriticalInput@l
mtspr IVOR0,r4 /* 0: Critical input */
li r4,MachineCheck@l
mtspr IVOR1,r4 /* 1: Machine check */
li r4,DataStorage@l
mtspr IVOR2,r4 /* 2: Data storage */
li r4,InstStorage@l
mtspr IVOR3,r4 /* 3: Instruction storage */
li r4,ExtInterrupt@l
mtspr IVOR4,r4 /* 4: External interrupt */
li r4,Alignment@l
mtspr IVOR5,r4 /* 5: Alignment */
li r4,ProgramCheck@l
mtspr IVOR6,r4 /* 6: Program check */
li r4,FPUnavailable@l
mtspr IVOR7,r4 /* 7: floating point unavailable */
li r4,SystemCall@l
mtspr IVOR8,r4 /* 8: System call */
/* 9: Auxiliary processor unavailable(unsupported) */
li r4,Decrementer@l
mtspr IVOR10,r4 /* 10: Decrementer */
li r4,IntervalTimer@l
mtspr IVOR11,r4 /* 11: Interval timer */
li r4,WatchdogTimer@l
mtspr IVOR12,r4 /* 12: Watchdog timer */
li r4,DataTLBError@l 等
直至后就是cache 當(dāng)臨時stack供C語言代碼運行,新tlb 映射岔留,u-boot C代碼出事后ddr夏哭,基本設(shè)置,copy自身代碼到ram(ddr)等等献联。這部分代碼基本不會出什么問題方庭,后續(xù)就到了最關(guān)鍵的relocate 技術(shù)了。
3.2 U-Boot中的Relocate技術(shù)
所謂代碼重定位技術(shù)就是對于鏈接時地址已經(jīng)固定的數(shù)據(jù)段與代碼段酱固,在進行代碼搬移后械念,需要對這些數(shù)據(jù)段與代碼段的地址進行修改,使程序能夠正確尋 址的技術(shù)运悲。在 bootloader 中龄减,通常有 GOT與 PLT兩種實現(xiàn)方法。其基本原理就是利 用數(shù)據(jù)段與代碼段的相對位置不變實現(xiàn)的班眯。代碼重定位技術(shù)也應(yīng)用于 OS 中希停,OS 的加載器也實現(xiàn)了 PIC凉夯,這里不做算法研究盛龄。
我們知道對于全局變量的訪問讨阻,首先要獲取該變量的全局地址仁烹,而這個地址是編譯鏈接時生成的一個地址,對于沒有-fpic 選項編譯的程序句惯,此值是一個靜態(tài)的地址豫喧,當(dāng)程序從 flash 重新定位到 ram 后靴跛,訪問的地址仍然在 Flash 中诊霹,那 么如何讀寫呢?
這就需要一種機制來保證獲取的全局變量的地址是一個動態(tài)的值羞延,也是說當(dāng) 程序重定位到 RAM 中后,這個地址也需要隨之修正脾还。而 U-boot 正是將所有全局 符號的地址保存在一個表中 GOT伴箩,程序訪問變量時先從這個表中動態(tài)獲取該符 號的地址,而這個地址在重定位時已經(jīng)修正過了鄙漏,從而保證能從重定位后的地址 處正確訪問全局變量嗤谚。
總的來講,U-Boot 依靠維護 GOT 表來實現(xiàn)怔蚌,在 GOT 表中存放一些全局 label表巩步,這些表項記錄重要的地址。運行在 Flash 時媚创,GOT 表中存放的是編譯時 全局 label 的值(地址);當(dāng) U-Boot 運行時檢測 RAM 大小進行代碼搬運之后,利用代碼搬運前后產(chǎn)生的地址偏移對(相對偏移)GOT表中的各個表項值進行更新渗钉,使其記錄 RAM 中的相應(yīng)的地址。 這樣代碼運行時不會出現(xiàn)代碼/變量地址出錯的問題钞钙。
- 代碼運行到 in_ram之后首先進行GOT轉(zhuǎn)換鳄橘,其實核心思想就是程序的編譯后的指令,
.globl in_ram
in_ram:
/*
* Relocation Function, r12 point to got2+0x8000
*
* Adjust got2 pointers, no need to check for 0, this code
* already puts a few entries in the table.
*/
li r0,__got2_entries@sectoff@l
la r3,GOT(_GOT2_TABLE_)
lwz r11,GOT(_GOT2_TABLE_)
mtctr r0
sub r11,r3,r11
addi r3,r3,-4
1: lwzu r0,4(r3)
cmpwi r0,0
beq- 2f
add r0,r0,r11
stw r0,0(r3)
2: bdnz 1b
其實可以這么理解芒炼,一旦有全局變量的地方都需要進行地址換算瘫怜,這個U-boot原始位置與最新位置,在調(diào)用relocate函數(shù)之前已經(jīng)算好本刽,并傳參數(shù)給匯編代碼鲸湃。其實就是公式:
這里Offset可以是負(fù)數(shù)子寓,具體參考Uboot源代碼暗挑。
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
* r3 = dest
* r4 = src
* r5 = length in bytes
* r6 = cachelinesize
*/
.globl relocate_code
relocate_code:
mr r1,r3 /* Set new stack pointer */
mr r9,r4 /* Save copy of Init Data pointer */
mr r10,r5 /* Save copy of Destination Address */
GET_GOT
#ifndef CONFIG_SPL_SKIP_RELOCATE
mr r3,r5 /* Destination Address */
lis r4,CONFIG_SYS_MONITOR_BASE@h /* Source Address */
ori r4,r4,CONFIG_SYS_MONITOR_BASE@l
lwz r5,GOT(__init_end)
sub r5,r5,r4
li r6,CONFIG_SYS_CACHELINE_SIZE /* Cache Line Size */
/*
* Fix GOT pointer:
*
* New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
*
* Offset:
*/
sub r15,r10,r4
/* First our own GOT */
add r12,r12,r15
*/
sub r15,r10,r4
/* First our own GOT */
add r12,r12,r15
/* the the one used by the C code */
add r30,r30,r15
4 U-Boot主要命令
U-Boot發(fā)展到現(xiàn)在,已經(jīng)接近 linux 系統(tǒng)斜友。它具備了豐富的命令炸裆,可以幫助 用戶實現(xiàn)調(diào)試與系統(tǒng)環(huán)境設(shè)置等。下面我僅介紹下幾個常用的命令鲜屏。1烹看、HELP 命令
? 在終端輸入 help 命令,將會顯示系統(tǒng)支持的命令及簡要說明洛史。
-
help == ?
? - alias for 'help'
base - print or set address offset
bdinfo - print Board Info structure
boot - boot default, i.e., run 'bootcmd' - boot default, i.e., run 'bootcmd'
flinfo. - print flash bank and erase infotftp - download image from serverip via net
rx - receive by xmodel
setenv editenv savenv and so on
總結(jié)
U-BOOT 是一個非常好用的嵌入式 bootloader惯殊。它已經(jīng)成為目前嵌入式linux的御用boot,內(nèi)容非常豐富也殖,但結(jié)構(gòu)混亂土思,看下common里面的board_r和board_f就能可見一斑,本文只是從整體上對其啟動部分原理做了簡要陳述忆嗜。關(guān)于 u-boot 程序開發(fā)浪漠,已經(jīng)超出了 u-boot 啟動部分內(nèi)容,并且需要很多外圍硬件的相關(guān)知識霎褐,所以沒有進行講解址愿。
? 本文參 考了網(wǎng)絡(luò)相關(guān)文章,并進行了實踐驗證冻璃,以及Powerpc 相關(guān)手冊响谓,但由于本人技術(shù)水平有限,難免存在 理解錯誤省艳,望大家指正娘纷。