在ARM64架構(gòu)的Linux內(nèi)核開(kāi)發(fā)中,arch/arm64/kernel/head.S是一個(gè)繞不開(kāi)的關(guān)鍵文件——它是內(nèi)核啟動(dòng)早期的“橋梁”,承接Bootloader與內(nèi)核初始化核心邏輯。本文將從文件定位、核心知識(shí)點(diǎn)、調(diào)試要點(diǎn)、開(kāi)發(fā)意義四個(gè)維度展開(kāi),帶大家吃透這個(gè)底層匯編文件,文末還會(huì)通過(guò)流程圖梳理關(guān)鍵流程,助力開(kāi)發(fā)者打通ARM64內(nèi)核啟動(dòng)的“任督二脈”。

一、本文核心內(nèi)容預(yù)告
在正式分析前,先明確本文將覆蓋的核心內(nèi)容,方便大家?guī)е繕?biāo)閱讀:
1.文件定位與核心作用:搞懂head.S在ARM64內(nèi)核啟動(dòng)流程中的“角色”,以及它為何是啟動(dòng)環(huán)節(jié)的“必經(jīng)之路”;
2.關(guān)鍵知識(shí)點(diǎn)拆解:結(jié)合代碼片段與流程圖,詳解EL等級(jí)切換、頁(yè)表初始化、MMU使能等核心邏輯;
3.調(diào)試關(guān)鍵關(guān)注點(diǎn):明確調(diào)試head.S階段時(shí)需重點(diǎn)監(jiān)控的寄存器、斷點(diǎn)與日志,快速定位啟動(dòng)故障;
4.開(kāi)發(fā)實(shí)踐意義:分析理解head.S對(duì)內(nèi)核移植、性能優(yōu)化、故障排查的實(shí)際價(jià)值。
二、head.S:ARM64內(nèi)核啟動(dòng)的“第一塊磚”
要理解head.S,首先要明確它在整個(gè)啟動(dòng)流程中的位置。ARM64內(nèi)核啟動(dòng)的簡(jiǎn)化鏈路如下:
Bootloader(如U-Boot)→ head.S → start_kernel(C語(yǔ)言初始化入口)
當(dāng)Bootloader完成硬件初始化(如內(nèi)存、時(shí)鐘)后,會(huì)將內(nèi)核鏡像加載到指定內(nèi)存地址,隨后跳轉(zhuǎn)到head.S的入口(_start標(biāo)簽)。此時(shí)內(nèi)核尚未進(jìn)入C語(yǔ)言環(huán)境,head.S的核心作用就是:
?完成CPU異常等級(jí)(EL)切換(如從EL2Hypervisor模式切到EL1內(nèi)核模式);
?初始化早期頁(yè)表,為啟用MMU(內(nèi)存管理單元)做準(zhǔn)備;
?配置異常向量表,處理啟動(dòng)階段的異常;
?初始化內(nèi)核棧,為跳轉(zhuǎn)到C語(yǔ)言函數(shù)(start_kernel)鋪路。
簡(jiǎn)單說(shuō),head.S是“匯編初始化”到“C語(yǔ)言初始化”的過(guò)渡層,沒(méi)有它,內(nèi)核無(wú)法進(jìn)入正常的C語(yǔ)言執(zhí)行環(huán)境。
三、head.S關(guān)鍵知識(shí)點(diǎn)拆解(附流程圖)
head.S的代碼以匯編指令為主,邏輯緊湊且高度依賴ARM64架構(gòu)特性。下面拆解4個(gè)核心知識(shí)點(diǎn),并通過(guò)流程圖梳理整體流程。
1.異常等級(jí)(EL)切換:從EL2到EL1
ARM64架構(gòu)定義了4個(gè)異常等級(jí)(EL0~EL3,權(quán)限從低到高),Bootloader通常運(yùn)行在EL2(支持虛擬化),而Linux內(nèi)核運(yùn)行在EL1(內(nèi)核特權(quán)級(jí))。head.S的el2_setup函數(shù)負(fù)責(zé)完成EL2到EL1的切換,核心步驟如下:
?配置EL2的系統(tǒng)寄存器(如HCR_EL2),禁用EL2對(duì)EL1的監(jiān)控;
?設(shè)置EL1的狀態(tài)寄存器(如SPSR_EL2),指定EL1的執(zhí)行模式(AArch64、中斷使能);
?通過(guò)eret指令從EL2跳轉(zhuǎn)到EL1的入口地址(el1_entry)。
2.早期頁(yè)表初始化:為MMU啟用打基礎(chǔ)
ARM64要求啟用MMU前必須配置頁(yè)表(不支持實(shí)模式),head.S的__create_page_tables函數(shù)負(fù)責(zé)初始化早期頁(yè)表,核心邏輯如下:
?分配頁(yè)表內(nèi)存(通常從內(nèi)核鏡像末尾的臨時(shí)內(nèi)存區(qū)域獲?。?/span>
?建立“內(nèi)核鏡像區(qū)域”的頁(yè)表映射(物理地址→虛擬地址,采用大頁(yè)(2MB/1GB)提升效率);
?建立“異常向量表區(qū)域”的頁(yè)表映射(確保異常處理地址可訪問(wèn));
?配置頁(yè)表項(xiàng)的權(quán)限(如可讀可寫(xiě)、執(zhí)行禁止(XN)、緩存策略)。
早期頁(yè)表的映射范圍較?。▋H覆蓋內(nèi)核鏡像和關(guān)鍵區(qū)域),后續(xù)start_kernel會(huì)初始化完整頁(yè)表。
3. MMU啟用:進(jìn)入虛擬地址模式
MMU是ARM64內(nèi)存管理的核心,啟用MMU后CPU將通過(guò)虛擬地址訪問(wèn)內(nèi)存。head.S的__primary_switch函數(shù)負(fù)責(zé)啟用MMU,核心步驟:
?將頁(yè)表基地址寫(xiě)入TTBR0_EL1(EL1的頁(yè)表基地址寄存器);
?配置內(nèi)存屬性寄存器(如SCTLR_EL1),設(shè)置緩存、對(duì)齊檢查等開(kāi)關(guān);
?通過(guò)isb指令刷新指令流水線,確保MMU配置生效;
?驗(yàn)證MMU是否啟用成功(訪問(wèn)虛擬地址,確認(rèn)地址轉(zhuǎn)換正常)。
MMU啟用后,內(nèi)核正式進(jìn)入虛擬地址模式,后續(xù)所有內(nèi)存訪問(wèn)均基于虛擬地址。
4.異常向量表設(shè)置:處理啟動(dòng)階段異常
異常向量表是CPU發(fā)生異常(如中斷、缺頁(yè))時(shí)的“入口地址表”,head.S的__vectors標(biāo)簽定義了ARM64的異常向量表,核心特性:
?向量表大小固定(256字節(jié),每個(gè)異常類型對(duì)應(yīng)16字節(jié)的入口);
?支持8種異常類型(如EL1的同步異常、IRQ中斷、FIQ中斷);
?每個(gè)異常入口會(huì)保存現(xiàn)場(chǎng)(如寄存器值),并跳轉(zhuǎn)到對(duì)應(yīng)的異常處理函數(shù)。
5. head.S啟動(dòng)流程總覽(流程圖)
通過(guò)mermaid流程圖梳理head.S的核心執(zhí)行鏈路,幫助大家建立全局認(rèn)知:

四、調(diào)試head.S:重點(diǎn)關(guān)注這些“關(guān)鍵節(jié)點(diǎn)”
head.S運(yùn)行在kernel啟動(dòng)最早期,此時(shí)C語(yǔ)言日志(如printk)尚未生效,調(diào)試難度較高。以下是調(diào)試該階段需重點(diǎn)關(guān)注的內(nèi)容,幫助快速定位故障。
1.寄存器監(jiān)控:關(guān)鍵寄存器反映執(zhí)行狀態(tài)
調(diào)試時(shí)需通過(guò)JTAG/SWD工具監(jiān)控以下核心寄存器,判斷流程是否正常:
?異常等級(jí)相關(guān):CurrentEL(查看當(dāng)前EL等級(jí),確認(rèn)是否成功切到EL1)、SPSR_EL2(EL1的狀態(tài)配置是否正確);
?頁(yè)表相關(guān):TTBR0_EL1(頁(yè)表基地址是否正確)、ESR_EL1(若發(fā)生異常,該寄存器存儲(chǔ)異常原因);
?內(nèi)存相關(guān):sp(內(nèi)核棧指針是否指向合法內(nèi)存區(qū)域)。
2.斷點(diǎn)設(shè)置:瞄準(zhǔn)核心函數(shù)標(biāo)簽
在調(diào)試工具(如GDB)中,針對(duì)head.S的核心標(biāo)簽設(shè)置斷點(diǎn),逐步跟蹤執(zhí)行流程:
?_start:確認(rèn)Bootloader是否正確跳轉(zhuǎn)到head.S入口;
?el2_setup/el1_entry:驗(yàn)證異常等級(jí)切換是否正常;
?__create_page_tables:檢查頁(yè)表初始化后的數(shù)據(jù)(如頁(yè)表基地址對(duì)應(yīng)的內(nèi)存值);
?__primary_switch:監(jiān)控MMU啟用前后的地址轉(zhuǎn)換是否正常(可通過(guò)x命令查看虛擬地址對(duì)應(yīng)的物理地址)。
3.故障定位:常見(jiàn)問(wèn)題與排查思路
若內(nèi)核卡在head.S階段(如無(wú)響應(yīng)、重啟),可按以下思路排查:
?MMU啟用失敗:檢查TTBR0_EL1是否指向正確的頁(yè)表基地址,頁(yè)表項(xiàng)的權(quán)限和映射是否正確;
?EL等級(jí)切換失敗:查看CurrentEL寄存器,若仍停留在EL2,需檢查HCR_EL2和SPSR_EL2的配置;
?異常向量表錯(cuò)誤:若發(fā)生同步異常,查看ESR_EL1的異常原因,確認(rèn)向量表地址是否正確映射。

五、理解head.S:對(duì)開(kāi)發(fā)的3大核心意義
head.S看似是“底層匯編代碼”,但對(duì)ARM64內(nèi)核開(kāi)發(fā)至關(guān)重要,其實(shí)際意義體現(xiàn)在三個(gè)維度:
1.內(nèi)核移植的“敲門(mén)磚”
當(dāng)將Linux內(nèi)核移植到新的ARM64開(kāi)發(fā)板時(shí),head.S是首當(dāng)其沖需要適配的文件:
?若硬件內(nèi)存布局變化(如內(nèi)核鏡像加載地址、頁(yè)表內(nèi)存區(qū)域),需修改__create_page_tables的映射邏輯;
?若CPU異常等級(jí)配置不同(如Bootloader運(yùn)行在EL3),需新增el3_setup函數(shù)處理EL3到EL1的切換;
?若硬件緩存策略特殊,需調(diào)整頁(yè)表項(xiàng)的緩存屬性(如MAIR_EL1寄存器配置)。
2.啟動(dòng)性能優(yōu)化的“關(guān)鍵點(diǎn)”
head.S的執(zhí)行效率直接影響內(nèi)核啟動(dòng)速度,優(yōu)化方向包括:
?簡(jiǎn)化頁(yè)表初始化邏輯:采用更大的頁(yè)(如1GB大頁(yè))減少頁(yè)表項(xiàng)數(shù)量,降低初始化耗時(shí);
?合并冗余指令:如EL等級(jí)切換和MMU配置中的重復(fù)寄存器操作,可通過(guò)宏定義簡(jiǎn)化;
?減少異常處理開(kāi)銷(xiāo):優(yōu)化異常向量表的入口邏輯,縮短異常響應(yīng)時(shí)間。
3.底層故障排查的“金鑰匙”
當(dāng)內(nèi)核啟動(dòng)出現(xiàn)“早期崩潰”(如start_kernel前panic),head.S是排查的核心突破口:
?若內(nèi)核卡在MMU啟用后,可通過(guò)斷點(diǎn)確認(rèn)TTBR0_EL1和SCTLR_EL1的配置,排查頁(yè)表映射錯(cuò)誤;
?若發(fā)生EL2切換失敗,可監(jiān)控eret指令前后的寄存器值,定位HCR_EL2的配置問(wèn)題;
?若異常向量表觸發(fā)錯(cuò)誤,可檢查向量表的地址映射和權(quán)限,確認(rèn)是否被意外修改。
六、總結(jié):head.S是ARM64內(nèi)核的“啟動(dòng)基石”
head.S作為ARM64內(nèi)核啟動(dòng)的“第一塊匯編代碼”,看似代碼量不大(約500行),卻承載了異常等級(jí)切換、頁(yè)表初始化、MMU啟用等核心功能——它是內(nèi)核從“硬件初始化”到“軟件初始化”的橋梁,也是理解ARM64架構(gòu)與Linux內(nèi)核底層邏輯的“鑰匙”。
對(duì)于開(kāi)發(fā)者而言,吃透head.S不僅能應(yīng)對(duì)內(nèi)核移植、性能優(yōu)化、故障排查等實(shí)際需求,更能深入理解ARM64的特權(quán)級(jí)管理、內(nèi)存虛擬化等底層機(jī)制,為后續(xù)定制內(nèi)核、開(kāi)發(fā)驅(qū)動(dòng)打下堅(jiān)實(shí)基礎(chǔ)。
如果大家在閱讀head.S源碼時(shí)遇到具體問(wèn)題(如某段匯編指令不懂、調(diào)試時(shí)卡殼),歡迎在評(píng)論區(qū)交流,后續(xù)可針對(duì)細(xì)節(jié)展開(kāi)更深入的分析!
-
內(nèi)核
+關(guān)注
關(guān)注
4文章
1467瀏覽量
42866 -
Linux
+關(guān)注
關(guān)注
88文章
11756瀏覽量
218997 -
文件
+關(guān)注
關(guān)注
1文章
594瀏覽量
26052
發(fā)布評(píng)論請(qǐng)先 登錄
迅為RK3562開(kāi)發(fā)板Android源碼定制開(kāi)發(fā)-kernel開(kāi)發(fā)
如何對(duì)RK3399 CPU arm64的內(nèi)核進(jìn)行配置
Rk3399內(nèi)核編譯配置流程梳理
淺析openat系統(tǒng)調(diào)用在arm64下的實(shí)現(xiàn)及使用原理
介紹在ARM64架構(gòu)下啟動(dòng)多核的兩種方式
RK3568的.config文件是通過(guò)kernel/arch/arm64/configs中的哪個(gè)配置文件生成的呢
迅為iTOP-RK3588開(kāi)發(fā)板Android12源碼定制開(kāi)發(fā)kernel開(kāi)發(fā)
ARM64與ARM32 的Linux程序區(qū)別在哪里
ARM64 Linux內(nèi)核頁(yè)表的塊映射
Core 3399KJ Linux根文件系統(tǒng)鏡像(arm64/arm32)
Core 3399J Linux根文件系統(tǒng)鏡像(arm64/arm32)
ROC RK3399 PC Pro文件系統(tǒng)Linux根文件系統(tǒng)鏡像(arm64/arm32)
AIO 3399ProC Linux根文件系統(tǒng)鏡像(arm64/arm32)
ARM64位與ARM32位OP-TEE啟動(dòng)過(guò)程的差異
深入剖析ARM64異常處理:開(kāi)發(fā)者必須掌握的底層核心邏輯
深入剖析ARM64內(nèi)核關(guān)鍵文件:kernel-6.1/arch/arm64/kernel/head.S
評(píng)論