實戰(zhàn))
1. 先弄懂U-Boot在4412啟動鏈中的位置再談源碼結構在4412開發(fā)板上做嵌入式學習到了第十篇這個階段大多已經(jīng)跑過裸機程序、編過內(nèi)核、燒過文件系統(tǒng)。操作層面熟練之后很容易對U-Boot產(chǎn)生一種“會用但沒吃透”的感覺知道它負責加載內(nèi)核但不知道它啟動時執(zhí)行了什么能敲命令但不知道命令背后對應哪一段源碼。這篇主要解決的就是uboot源代碼結構問題把整套引導程序拆成功能模塊搞清楚每個模塊放在哪個目錄、由誰編譯、怎么被調(diào)用。只有先把結構吃透后面做移植、裁剪、調(diào)試才談得上效率。1.1 看代碼前的啟動流程基礎4412是四核Cortex-A9架構它的完整啟動流程是分層加載的。片上iROM里固化的代碼最先運行初始化基礎時鐘和存儲控制器然后把第一段引導代碼從啟動介質(zhì)SD卡、eMMC、USB等加載到片內(nèi)SRAM執(zhí)行這一段通常叫BL1主要作用是把DRAM初始化好。BL1隨后把第二段引導代碼加載到DRAM運行這一段才是U-Boot本體在廠商BSP里有時也直接叫BL2。U-Boot拿到控制權之后完成更完整的硬件初始化等待命令行交互或者按預設指令從啟動介質(zhì)讀取內(nèi)核鏡像、設備樹、啟動參數(shù)最后跳轉到內(nèi)核入口。這個流程里有三個關鍵點容易忽略。第一BL1和U-Boot往往由同一套源碼產(chǎn)物加工而來或者BL1本身就是廠商固化好的二進制所以在U-Boot源碼目錄里不一定能看到完整的BL1實現(xiàn)它更像一個介于硬件和U-Boot之間的中間環(huán)節(jié)。第二U-Boot的職責是“把環(huán)境準備好、把內(nèi)核請進來”所有跟操作系統(tǒng)運行無關的常駐服務都不是它的任務所以它的代碼量雖然大但主線非常清晰。第三4412的BSP往往帶了很多廠商定制的驅(qū)動和命令源碼結構跟主線標準版不完全一致閱讀前最好先確認自己手里的代碼版本和目錄風格避免拿主線結構硬套。1.2 為什么要優(yōu)先掌握源碼結構初學U-Boot最常犯的錯誤是把源碼壓縮包當成一本小說打算從第一行讀到最后一頁。但一套完整的U-Boot源碼樹動輒幾千個文件、幾十萬行代碼按文件順序翻頁撐不了幾天就會迷失在drivers或arch目錄里。我之前給同學的建議都是反過來的先搞懂目錄結構再帶著具體問題去定位代碼。這就跟查字典一樣不需要通讀整本字典但必須知道它的排序規(guī)則和檢索方法。結構本身就是信息??吹揭粋€文件在arch/arm/cpu/armv7下面基本能確定它是CPU架構相關的代碼看到它在board/samsung目錄里大概率是和具體板卡硬件初始化強相關的代碼看到它在common/cmd_*.c里那對應的是某個命令行命令的實現(xiàn)。這種“路徑即分類、目錄即模塊”的組織方式是U-Boot能被大量不同平臺復用的根本原因。所以掌握結構本質(zhì)上是掌握一套代碼檢索系統(tǒng)后面無論做交叉移植還是功能裁剪都能快速找到下手的位置。2. U-Boot頂層目錄結構全景先建立全局地圖再動手把源碼壓縮包解壓后第一件事不是打開某個文件而是先看目錄。頂層目錄的命名基本就是模塊分類經(jīng)典U-Boot2010.x到2013.x那個年代和更新一些的主線版本雖然在目錄上有增刪但骨架一直保持穩(wěn)定。對4412這個型號的BSP來說目錄風格偏向經(jīng)典結構理解起來反而更直觀。2.1 目錄樹的全局劃分我建議把目錄分組來記不要一個目錄一個目錄孤立地看。拿一套比較典型的BSP來說解壓后頂層大致如下/uboot源碼根目錄 ├── arch/ # CPU架構相關代碼ARM、x86、RISC-V等各占一個子目錄 ├── board/ # 板級代碼按廠商/開發(fā)板組織 ├── common/ # U-Boot通用邏輯命令框架與公共流程 ├── configs/ # 新版本板級配置文件入口老版本在include/configs ├── drivers/ # 各類硬件驅(qū)動串口、網(wǎng)卡、MMC、USB、顯示等 ├── dts/ # 設備樹源文件與編譯相關 ├── fs/ # 文件系統(tǒng)支持ext4、fat、jffs2等 ├── include/ # 全局頭文件configs子目錄存放板級配置文件 ├── lib/ # 通用庫函數(shù)與輔助代碼 ├── net/ # 網(wǎng)絡協(xié)議棧主要用于tftp、nfs等啟動方式 ├── scripts/ # Kconfig配置腳本和構建輔助腳本 ├── tools/ # mkimage、fw_printenv等輔助工具源碼 ├── Makefile # 頂層構建入口 ├── config.mk # 全局編譯規(guī)則與變量 ├── mkconfig # 經(jīng)典版本配置階段的核心腳本 └── rules.mk # 通用編譯規(guī)則這十幾項可以按職責分成幾組arch、board、common、drivers、lib、fs、net是源碼本體include是頭文件和配置文件Makefile、config.mk、rules.mk、mkconfig、scripts是構建體系tools是輔助工具。閱讀優(yōu)先級上源碼本體優(yōu)先構建體系其次tools最后。2.2 各核心目錄的職能與特點對4412這種ARM平臺arch/arm目錄是必看的重點。arch/arm下面繼續(xù)按話題拆分cpu目錄按ARM內(nèi)核分類比如armv7對應Cortex-A系列里面能找到start.S、cpu.c這類核心文件lib目錄放架構相關的內(nèi)存操作、延時函數(shù)、異常處理等include目錄放架構專屬頭文件。你要找“CPU上電后執(zhí)行的第一行代碼”答案就在arch/arm/cpu/armv7/start.S這個文件被鏈接腳本指定為入口點。board目錄在經(jīng)典U-Boot里是board/廠商/板子這樣的二級結構比如board/samsung下面可能放著好幾個型號的板級代碼。4412的BSP里這一塊的板級代碼往往已經(jīng)由廠商準備好包含板級初始化的C文件和匯編文件比如lowlevel_init.S、board.c、sd_boot.c等??吹絙oard目錄要格外注意兩點一是此處的代碼跟著具體板子走不同板子的內(nèi)存容量、時鐘頻率、引腳定義全在這里體現(xiàn)二是以后燒寫時碰到某個外設不工作十有八九要回到board目錄查配置。drivers目錄最容易讓人迷失因為驅(qū)動數(shù)量太多。閱讀策略是只關注當前板子用到的類別比如MMC、網(wǎng)卡、串口、USB Host這幾個。44512 BSP里最常見的啟動方式是從eMMC/SD卡引導所以drivers/mmc下的代碼優(yōu)先級會比較高如果經(jīng)常用tftp下載內(nèi)核drivers/net也要看。驅(qū)動目錄的閱讀不需要從頭到尾用到哪個驅(qū)動就深入哪個其他保持“知道位置”即可。2.3 arch/arm 下與4412最相關的部分我在實際閱讀時會再把arch/arm目錄拆細一些。arch/arm/cpu/armv7/start.S是啟動起點負責設置異常向量、切換CPU模式、準備棧指針如果是較新的源碼還可能看到cpu.c里面放著輔助性的CPU控制函數(shù)。arch/arm/lib里則有board_init_f、board_init_r這類板級流程入口函數(shù)它們是U-Boot啟動主干中的關鍵節(jié)點。另一個容易被忽略的是mach或soc目錄。不少BSP會按廠商平臺放置獨立的平臺代碼目錄里面是時鐘、內(nèi)存控制器、引腳配置等平臺級代碼。這些代碼比board目錄更底層比arch通用代碼更具體正好處于中間層。理解源碼結構時按“通用架構層—平臺層—板級層”三層來看arch/arm是通用架構層mach/soc是平臺層board/samsung/xxx是板級層。對于4412這樣的定制化板子產(chǎn)品差異和硬件適配問題大多集中在平臺層和板級層。3. 4412專屬代碼在哪三步鎖定板級支撐文件從源碼結構上找到屬于4412這塊板子的代碼是后續(xù)所有移植和裁剪工作的前提。這里分享一套三步定位法先看board目錄再看板級配置頭文件最后用Makefile確認它確實參與了編譯。按這個順序走基本不會漏掉關鍵文件。3.1 第一步從board目錄找板級代碼進入board目錄找到samsung子目錄里面通常會有一到多個板級目錄。命名風格因BSP而異常見的有smdk4412、origen、itop4412這種格式要是不完全一致就找和開發(fā)板型號最接近的那個。這個目錄下一般包含三部分Makefile決定本目錄哪些文件編進U-Boot、一個或幾個C文件板級初始化和定制功能以及一個或幾個匯編文件如lowlevel_init.S負責DRAM和時鐘等早期硬件配置。查看板級代碼時重點看兩件事電源、時鐘、DDR初始化參數(shù)以及外設引腳復用和驅(qū)動注冊情況。4412這類板子的DDR參數(shù)和時鐘樹極其依賴BSP預置值亂改board目錄里的數(shù)值很容易讓板子直接變磚。如果BSP還包含sd_boot或mmc相關文件這些文件通常負責啟動介質(zhì)初始化它們和BL1的配合關系比較緊密建議結合串口啟動日志去理解純源碼閱讀階段可以先跳過。3.2 第二步從include/configs找板級配置在include/configs目錄部分新版本是configs目錄找到對應板子的頭文件這是整個U-Boot源碼里最重要的配置入口之一。這個頭文件塞滿了宏定義每個宏決定一個模塊是否編譯或一項功能是否啟用。典型的宏包括CONFIG_CMD_MMC、CONFIG_CMD_NET、CONFIG_BOOTCOMMAND、CONFIG_SYS_TEXT_BASE等。初看會覺得信息密度太大但它的本質(zhì)是一塊“開關面板”需要的外設驅(qū)動就打開不需要的模塊就裁掉啟動參數(shù)在這里寫準。頭文件里最值得做筆記的幾個宏直接決定系統(tǒng)能不能啟動宏名作用配置錯了的后果CONFIG_SYS_TEXT_BASE指定U-Boot鏈接基地址鏡像加載地址錯亂必死CONFIG_SYS_INIT_SP_ADDR早期棧指針位置棧覆蓋代碼或數(shù)據(jù)行為詭異CONFIG_BOOTCOMMAND自動啟動時執(zhí)行的命令序列自動引導失敗或進入不了系統(tǒng)CONFIG_BOOTARGS傳給內(nèi)核的命令行參數(shù)內(nèi)核啟動參數(shù)錯誤外設失聯(lián)CONFIG_ENV_IS_IN_MMC環(huán)境變量存儲介質(zhì)選擇環(huán)境變量保存不了或加載錯亂這些宏在標準U-Boot里基本都有但具體定義方式會隨版本變化。閱讀舊版本BSP時還會看到大量不帶CONFIG_前綴的宏比如USE_4410_BOARD或CFG_XXX之類的舊式寫法這些是歷史版本遺留的叫法作用類似遇到時別慌。3.3 第三步順著Makefile確認編譯參與情況U-Boot里一個源文件是否編進最終鏡像不只看文件在不在目錄里還要看目錄內(nèi)的Makefile有沒有引用它。打開board目錄下的Makefile能看到obj-y、obj-$(CONFIG_XXX)這類寫法。obj-y表示無條件編譯obj-$(CONFIG_XXX)表示只有當對應配置宏打開時才編譯。通過Makefile既可以確認哪些文件參與了構建也能學會改配置的正確姿勢增加驅(qū)動文件就添加obj-y條目或者在板級配置頭文件里打開對應CONFIG宏。經(jīng)典U-Boot里還經(jīng)常出現(xiàn)COBJS-y、SOBJS-y這類歷史寫法分別代表C目標文件和匯編目標文件職責和obj-y一樣只是不同版本的命名習慣不同。理解了這些細節(jié)之后你甚至可以從源碼結構推算出最終U-Boot鏡像里包含哪些功能配置頭文件定義開關Makefile決定文件與開關的對應關系兩者結合一目了然。4. 從make到.bin構建系統(tǒng)如何把零散源碼組織成固件源碼結構不只是目錄布局構建系統(tǒng)也屬于結構的一部分。很多人在源碼里找不到頭緒問題往往出在不了解U-Boot的構建流程。經(jīng)典U-Boot的構建分兩個大階段配置階段和編譯階段。把這兩個階段的流程走一遍目錄結構和構建方式就串起來了。4.1 配置階段的流程配置階段通常執(zhí)行“make _config”這樣的命令比如make smdk4412_config。這一步并不真正編譯代碼而是執(zhí)行根目錄下的mkconfig腳本完成幾件事根據(jù)board、cpu、soc等參數(shù)生成include/config.mk文件記錄板級和架構信息生成include/config.h文件把板級配置頭文件引入進來生成后續(xù)編譯要用的各種中間配置。一句話總結配置階段就是把“這塊板子是什么、用哪套配置”固化到構建系統(tǒng)能讀取的文件里。實戰(zhàn)中如果改了板級頭文件里的宏光執(zhí)行make往往不會重新觸發(fā)配置舊配置殘留會導致新改動不生效或者出現(xiàn)和改動無關的詭異編譯錯誤。我在操作時習慣改成“make distclean再make xxx_config最后make”全套流程雖然多花一點時間但能避免大量莫名其妙的問題。特別提醒如果你同時改了交叉編譯工具鏈路徑一定要在頂層Makefile里確認CROSS_COMPILE變量否則后面編譯到一半才報錯更難排查。4.2 編譯階段的構成配置完成后執(zhí)行make頂層Makefile開始真正發(fā)揮作用。它讀取include/config.mk、config.mk、rules.mk等文件解析編譯工具鏈、編譯選項、目標文件列表然后遞歸進入各個子目錄生成.o文件最后通過鏈接腳本把所有目標文件鏈接成ELF格式的u-boot再用objcopy生成純二進制的u-boot.bin。部分BSP還會繼續(xù)執(zhí)行自定義腳本給鏡像添加頭部信息或拆分成適合燒寫的多個文件。閱讀頂層Makefile不需要逐行讀抓住幾個關鍵變量即可。CROSS_COMPILE是交叉編譯工具鏈前綴CONFIG_SYS_TEXT_BASE或TEXT_BASE是鏈接基地址LDSCRIPT指向鏈接腳本位置MKIMAGE對應tools目錄下的鏡像工具。理解這些變量之后改工具鏈、改內(nèi)存地址、改鏡像生成方式都能快速找到對應位置。還要注意頂層Makefile里可能會有“目標幫助”注釋列出各種板子的config目標名想知道當前BSP支持哪些板子直接看這段列表就行。4.3 鏈接腳本和鏡像產(chǎn)物的來龍去脈鏈接腳本在源碼里一般放在CPU或board目錄下文件名通常是u-boot.lds或u-boot.lds.S。它規(guī)定了輸出文件的段布局最關鍵的是入口點和第一個段的起始位置。對ARM平臺來說鏈接腳本開頭基本會把.text段的起始地址設置為CONFIG_SYS_TEXT_BASE對應的值然后讓start.S所在的第一個目標文件排在最前面。u-boot.lds里還能看到.text、.rodata、.data、.bss等段的排列順序這些排布直接決定鏡像在內(nèi)存里的實際布局。編譯完成后源碼根目錄會出現(xiàn)一堆產(chǎn)物。u-boot是ELF格式的調(diào)試鏡像里面有完整的符號信息GDB調(diào)試時用它u-boot.bin是去掉ELF頭的純二進制鏡像燒寫用這個u-boot.map記錄每個符號被鏈接到的地址查函數(shù)入口、確認代碼段大小、分析鏈接地址沖突都靠它。有些BSP還會生成u-boot.img、u-boot.bin等帶頭部格式的文件這些通常由tools/mkimage加工具體格式跟BSP腳本相關。建議每次編譯完都瞄一眼u-boot.map開頭的內(nèi)存布局時間長了能建立起非常扎實的地址感。5. 啟動流程在源碼中的對應關系和閱讀路徑看懂了目錄和構建下一步要把這些知識和代碼串聯(lián)起來。U-Boot的啟動流程不是抽象的它的每一步都能在源碼里找到對應實現(xiàn)?!鞍戳鞒陶掖a”是嵌入式源碼閱讀的核心能力掌握之后調(diào)試效率會明顯提升。5.1 從start.S開始的早期初始化CPU上電復位后會從鏈接腳本指定的入口進入start.S。這個匯編文件通常會做這些事設置異常向量表切換CPU到SVC模式并關中斷初始化關鍵的狀態(tài)寄存器如果啟動介質(zhì)需要還會做一部分SoC層面的早期初始化最后設置當前執(zhí)行環(huán)境的棧指針。對4412來說start.S里可能會回調(diào)板級代碼完成DRAM初始化這個回調(diào)函數(shù)就是lowlevel_init這也是board目錄下存在lowlevel_init.S文件的原因。閱讀start.S時容易被大段的條件編譯和宏定義擋住視線。我個人的做法是先抽出整體流程不逐行死磕匯編入口在哪、哪些是CPU通用流程、哪些是CONFIG宏控制的板級差異。等真遇到啟動異常再回頭針對具體寄存器逐行分析。匯編代碼里的注釋一般比較少遇到不懂的寄存器和位域操作同步打開芯片手冊對照看效率最高。5.2 板級初始化和重定位早期初始化完成后啟動流程進入C語言階段。經(jīng)典U-Boot的路徑大致是start.S調(diào)用board_init_f完成早期的板級初始化比如串口、時鐘、DRAM等然后在內(nèi)存里準備新的棧和環(huán)境接著執(zhí)行代碼重定位把U-Boot自身搬運到運行地址之后調(diào)用board_init_r完成板級后期初始化建立完整的運行環(huán)境最終進入main_loop在那里實現(xiàn)命令行交互和自動啟動邏輯。這里的board_init_f和board_init_r名字里就帶著“board”字樣說明它們都是板級頂層入口。這兩個函數(shù)通常定義在arch/arm/lib/board.c或相近位置內(nèi)部會調(diào)用一系列指向板級目錄的回調(diào)函數(shù)。之前強調(diào)過board目錄要重點看真正原因就在這里啟動流程的骨架是通用的但具體板子的硬件動作全部落在board目錄的回調(diào)里。閱讀時先看board_init_f調(diào)用了哪些板級回調(diào)再順著回調(diào)進board目錄整個啟動鏈路就串起來了。5.3 如何根據(jù)啟動日志反查代碼位置調(diào)試階段最實用的技能是通過串口日志反推代碼路徑。U-Boot啟動時會打印大量日志包括版本信息、DRAM容量、啟動介質(zhì)、環(huán)境變量加載狀態(tài)等。每個日志字符串都能在源碼里用搜索找到唯一出處。如果在日志里看到“Board init”或者“MMC init”這類關鍵字直接用字符串搜索定位到打印函數(shù)往往就能順藤摸瓜找到整個初始化鏈。這個方法比盲目讀源碼高效很多因為它是用實際運行結果來指導閱讀方向的。錯誤信息日志同樣很有價值。U-Boot源碼的錯誤路徑一般都會打印字符串比如“mmc init failed”“Invalid boot device”??吹竭@類日志后搜索對應字符串可以直接定位到出錯分支再分析為什么會走到錯誤分支比在代碼里瞎猜準得多。實際操作中還要注意打印緩沖區(qū)和串口波特率的匹配問題很多“啟動卡死”其實只是串口配置沒對上并不代表代碼真的跑飛了。6. 源碼閱讀中常見的坑和排查方法源碼結構搞清楚了實際應用里還是會碰到一堆頭疼問題。這里列幾個我見過最多的情況以及對應的排查思路權當一份速查表。6.1 配置文件改了卻不生效這類問題幾乎每天都能遇到。改完板級頭文件重新make發(fā)現(xiàn)改動沒生效或者編譯報錯提示宏未定義。常見原因有兩個一是沒有清除舊的配置產(chǎn)物include/config.h和include/config.mk還是老版本構建系統(tǒng)讀到的仍然是舊內(nèi)容二是宏定義本身存在依賴關系某個宏需要依賴另一組宏先定義順序不對就會失效。解決辦法是執(zhí)行make distclean重新走配置和編譯的全流程。如果還不行就檢查板級頭文件是否真的被include/config.h引用了路徑寫沒寫對有沒有因版本差異而放在其他目錄。6.2 符號找不到和鏈接錯誤U-Boot鏈接錯誤最常見的是undefined reference。這類問題一般和Makefile對象列表或配置宏有關某個目標文件調(diào)用了函數(shù)但定義這個函數(shù)的源文件沒有參與編譯鏈接自然找不到符號。排查步驟是先在源碼里搜索函數(shù)定義在哪個文件再去該目錄下的Makefile確認文件是否參與編譯如果沒參與判斷它應該無條件編譯還是由某個CONFIG宏控制然后在板級配置頭文件里打開宏。宏已經(jīng)打開還不行時嘗試clean后重新編譯因為舊的目標文件可能沒被重新構建這也是新手最容易忽視的。6.3 合理使用搜索工具在幾十萬行代碼里找函數(shù)靠肉眼翻文件不現(xiàn)實。C語言源碼的查找順序一般是先在當前目錄搜再在上級目錄擴大范圍然后查include頭文件最后全源碼搜。常用命令是grep -rn和grep -rln分別用來搜內(nèi)容和只列文件。建議在源碼根目錄生成tags和cscope數(shù)據(jù)庫配合編輯器使用跳轉效率會提升一個檔次。搜索時注意區(qū)分函數(shù)聲明、定義、調(diào)用三種場景搜“函數(shù)名 (”和單獨搜函數(shù)名的結果差別很大用正則過濾掉注釋和聲明能少看很多噪音。還有幾個搜索時容易踩的細節(jié)宏里嵌套宏函數(shù)通過函數(shù)指針間接調(diào)用不同目錄下同名文件。碰到搜索出多個結果時多看一眼文件路徑前綴路徑通常能幫你判斷當前平臺真正用的是哪一個。尤其要注意一個函數(shù)可能在arch、board、include三個目錄各出現(xiàn)一次實際生效的那個由鏈接腳本和Makefile共同決定不能只看搜索順序。6.4 編譯工具鏈和主機平臺相關的坑在Windows環(huán)境下折騰U-Boot源碼比Linux環(huán)境麻煩得多最直接的問題就是mkconfig等腳本依賴shell環(huán)境換行符轉換、路徑分隔符不一致都會導致配置階段失敗。即使強行通過后續(xù)編譯也可能出現(xiàn)莫名報錯。我的建議是優(yōu)先在Linux環(huán)境或WSL里操作工具鏈使用與BSP配套的交叉編譯器版本太新或太舊都可能導致某條匯編指令或內(nèi)嵌匯編語法不兼容。遇到編譯告警不用太緊張U-Boot老版本對告警的容忍度很高但如果告警里出現(xiàn)“missing binary operator”這類預處理錯誤多半是配置宏或頭文件包含順序出了問題。7. 一份更省時間的源碼閱讀路線最后給出我總結的閱讀順序主打“先框架、后細節(jié)、再擴展”的思路避免走彎路。7.1 從主線開始向外擴展不建議從鏈接腳本、Makefile、start.S一頭扎進去死磕雖然這些是入口但信息密度太大新手很容易看崩潰。建議按這個順序做三輪閱讀先梳理啟動流程整體框架知道BL1、U-Boot、內(nèi)核三者如何接力。再讀板級配置頭文件把關鍵宏和它們的作用整理出來。通過串口啟動日志建立“現(xiàn)象—日志—源碼”的對應關系。這三件事做完后再回頭啃start.S和board_init_f/board_init_r。這時候你已經(jīng)知道每一段代碼在為什么服務讀起來負擔小很多。之后再進入命令實現(xiàn)、驅(qū)動框架、環(huán)境變量機制等外圍模塊就屬于按需深入了。7.2 閱讀時建立自己的代碼地圖學習過程中建議把目錄結構、關鍵文件、關鍵函數(shù)、關鍵宏記成一個自己的筆記形式不限紙質(zhì)、電子文檔、思維導圖都可以。筆記里可以寫“改內(nèi)存頻率去board目錄的哪個文件”“改啟動參數(shù)去配置頭文件搜CONFIG_BOOTARGS”“想加命令去common目錄看cmd_*文件怎么注冊命令”。這些記錄本質(zhì)上是在把U-Boot源碼的“目錄索引”升級成“功能索引”以后移植或者裁剪時這套索引比讀十遍源碼都管用。我自己的習慣是把每一塊板子對應的關鍵信息單獨建一頁上面記著DDR初始化參數(shù)所在文件、啟動介質(zhì)配置宏、環(huán)境變量存儲位置、常用編譯命令和燒寫命令。換一塊板子做項目時直接復制模板再修改能省掉大量重復摸索的時間。7.3 版本差異是常態(tài)別老想著一步到位最后提醒一點不同版本的U-Boot之間目錄組織、宏命名、Makefile寫法都有差異。4412的BSP和一些主線版本的差異尤其明顯這是正?,F(xiàn)象。面對一份新源碼時先花半小時確認它的目錄風格屬于哪個年代再決定用哪套查找策略比一開始就套用記憶里的舊經(jīng)驗可靠得多。只要掌握“配置頭文件控開關、Makefile管參與、arch管架構、board管板級差異”這個核心框架任何U-Boot源碼樹都能較快上手。我在反復對照源碼結構和實際啟動流程之后最大的體會是U-Boot這種項目把它只當成“會用”的工具時能力邊界是很有限的一旦把它當成一部可翻閱的代碼大百科能獲取的信息量會成倍增加很多問題根本不用四處搜索自己查看源碼就能找到答案。源碼目錄結構就是這部大百科的目錄索引花點時間把索引摸熟后面無論是繼續(xù)深入設備驅(qū)動還是研究環(huán)境變量存儲都會順暢得多。