0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

深入剖析ARM64内核关键文件:kernel-6.1/arch/arm64/kernel/head.S

jf_44130326 来源:Linux1024 2026-02-04 17:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

ARM64架构的Linux内核开发中,arch/arm64/kernel/head.S是一个绕不开的关键文件——它是内核启动早期的桥梁,承接Bootloader与内核初始化核心逻辑。本文将从文件定位、核心知识点、调试要点、开发意义四个维度展开,带大家吃透这个底层汇编文件,文末还会通过流程图梳理关键流程,助力开发者打通ARM64内核启动的任督二脉

wKgZO2kal-qATMVPAAEVgwd9208676.png

一、本文核心内容预告

在正式分析前,先明确本文将覆盖的核心内容,方便大家带着目标阅读:

1.文件定位与核心作用:搞懂head.SARM64内核启动流程中的角色,以及它为何是启动环节的必经之路

2.关键知识点拆解:结合代码片段与流程图,详解EL等级切换、页表初始化、MMU使能等核心逻辑;

3.调试关键关注点:明确调试head.S阶段时需重点监控的寄存器、断点与日志,快速定位启动故障;

4.开发实践意义:分析理解head.S对内核移植、性能优化、故障排查的实际价值。

二、head.SARM64内核启动的第一块砖

要理解head.S,首先要明确它在整个启动流程中的位置。ARM64内核启动的简化链路如下:

Bootloader(如U-Boot→ head.S → start_kernelC语言初始化入口)

Bootloader完成硬件初始化(如内存、时钟)后,会将内核镜像加载到指定内存地址,随后跳转到head.S的入口(_start标签)。此时内核尚未进入C语言环境,head.S的核心作用就是:

完成CPU异常等级(EL)切换(如从EL2Hypervisor模式切到EL1内核模式);

初始化早期页表,为启用MMU(内存管理单元)做准备;

配置异常向量表,处理启动阶段的异常;

初始化内核栈,为跳转到C语言函数(start_kernel)铺路。

简单说,head.S汇编初始化“C语言初始化的过渡层,没有它,内核无法进入正常的C语言执行环境。

三、head.S关键知识点拆解(附流程图)

head.S的代码以汇编指令为主,逻辑紧凑且高度依赖ARM64架构特性。下面拆解4个核心知识点,并通过流程图梳理整体流程。

1.异常等级(EL)切换:从EL2EL1

ARM64架构定义了4个异常等级(EL0~EL3,权限从低到高),Bootloader通常运行在EL2(支持虚拟化),而Linux内核运行在EL1(内核特权级)。head.Sel2_setup函数负责完成EL2EL1的切换,核心步骤如下:

配置EL2的系统寄存器(如HCR_EL2),禁用EL2EL1的监控;

设置EL1的状态寄存器(如SPSR_EL2),指定EL1的执行模式(AArch64、中断使能);

通过eret指令从EL2跳转到EL1的入口地址(el1_entry)。

2.早期页表初始化:为MMU启用打基础

ARM64要求启用MMU前必须配置页表(不支持实模式),head.S__create_page_tables函数负责初始化早期页表,核心逻辑如下:

分配页表内存(通常从内核镜像末尾的临时内存区域获取);

建立内核镜像区域的页表映射(物理地址虚拟地址,采用大页(2MB/1GB)提升效率);

建立异常向量表区域的页表映射(确保异常处理地址可访问);

配置页表项的权限(如可读可写、执行禁止(XN)、缓存策略)。

早期页表的映射范围较小(仅覆盖内核镜像和关键区域),后续start_kernel会初始化完整页表。

3. MMU启用:进入虚拟地址模式

MMUARM64内存管理的核心,启用MMUCPU将通过虚拟地址访问内存。head.S__primary_switch函数负责启用MMU,核心步骤:

将页表基地址写入TTBR0_EL1EL1的页表基地址寄存器);

配置内存属性寄存器(如SCTLR_EL1),设置缓存、对齐检查等开关;

通过isb指令刷新指令流水线,确保MMU配置生效;

验证MMU是否启用成功(访问虚拟地址,确认地址转换正常)。

MMU启用后,内核正式进入虚拟地址模式,后续所有内存访问均基于虚拟地址。

4.异常向量表设置:处理启动阶段异常

异常向量表是CPU发生异常(如中断、缺页)时的入口地址表head.S__vectors标签定义了ARM64的异常向量表,核心特性:

向量表大小固定(256字节,每个异常类型对应16字节的入口);

支持8种异常类型(如EL1的同步异常、IRQ中断、FIQ中断);

每个异常入口会保存现场(如寄存器值),并跳转到对应的异常处理函数。

5. head.S启动流程总览(流程图)

通过mermaid流程图梳理head.S的核心执行链路,帮助大家建立全局认知:

wKgZO2kal-qACyM8AAGSQiBnLUQ877.png

四、调试head.S:重点关注这些关键节点

head.S运行在kernel启动最早期,此时C语言日志(如printk)尚未生效,调试难度较高。以下是调试该阶段需重点关注的内容,帮助快速定位故障。

1.寄存器监控:关键寄存器反映执行状态

调试时需通过JTAG/SWD工具监控以下核心寄存器,判断流程是否正常:

异常等级相关CurrentEL(查看当前EL等级,确认是否成功切到EL1)、SPSR_EL2EL1的状态配置是否正确);

页表相关TTBR0_EL1(页表基地址是否正确)、ESR_EL1(若发生异常,该寄存器存储异常原因);

内存相关sp(内核栈指针是否指向合法内存区域)。

2.断点设置:瞄准核心函数标签

在调试工具(如GDB)中,针对head.S的核心标签设置断点,逐步跟踪执行流程:

_start:确认Bootloader是否正确跳转到head.S入口;

el2_setup/el1_entry:验证异常等级切换是否正常;

__create_page_tables:检查页表初始化后的数据(如页表基地址对应的内存值);

__primary_switch:监控MMU启用前后的地址转换是否正常(可通过x命令查看虚拟地址对应的物理地址)。

3.故障定位:常见问题与排查思路

若内核卡在head.S阶段(如无响应、重启),可按以下思路排查:

MMU启用失败:检查TTBR0_EL1是否指向正确的页表基地址,页表项的权限和映射是否正确;

EL等级切换失败:查看CurrentEL寄存器,若仍停留在EL2,需检查HCR_EL2SPSR_EL2的配置;

异常向量表错误:若发生同步异常,查看ESR_EL1的异常原因,确认向量表地址是否正确映射。

wKgZO2kal-qAcAFiAABZg1RGkt0377.png

五、理解head.S:对开发的3大核心意义

head.S看似是底层汇编代码,但对ARM64内核开发至关重要,其实际意义体现在三个维度:

1.内核移植的敲门砖

当将Linux内核移植到新的ARM64开发板时,head.S是首当其冲需要适配的文件:

若硬件内存布局变化(如内核镜像加载地址、页表内存区域),需修改__create_page_tables的映射逻辑;

CPU异常等级配置不同(如Bootloader运行在EL3),需新增el3_setup函数处理EL3EL1的切换;

若硬件缓存策略特殊,需调整页表项的缓存属性(如MAIR_EL1寄存器配置)。

2.启动性能优化的关键点

head.S的执行效率直接影响内核启动速度,优化方向包括:

简化页表初始化逻辑:采用更大的页(如1GB大页)减少页表项数量,降低初始化耗时;

合并冗余指令:如EL等级切换和MMU配置中的重复寄存器操作,可通过宏定义简化;

减少异常处理开销:优化异常向量表的入口逻辑,缩短异常响应时间。

3.底层故障排查的金钥匙

当内核启动出现早期崩溃(如start_kernelpanic),head.S是排查的核心突破口:

若内核卡在MMU启用后,可通过断点确认TTBR0_EL1SCTLR_EL1的配置,排查页表映射错误;

若发生EL2切换失败,可监控eret指令前后的寄存器值,定位HCR_EL2的配置问题;

若异常向量表触发错误,可检查向量表的地址映射和权限,确认是否被意外修改。

六、总结:head.SARM64内核的启动基石

head.S作为ARM64内核启动的第一块汇编代码,看似代码量不大(约500行),却承载了异常等级切换、页表初始化、MMU启用等核心功能——它是内核从硬件初始化软件初始化的桥梁,也是理解ARM64架构与Linux内核底层逻辑的钥匙

对于开发者而言,吃透head.S不仅能应对内核移植、性能优化、故障排查等实际需求,更能深入理解ARM64的特权级管理、内存虚拟化等底层机制,为后续定制内核、开发驱动打下坚实基础。

如果大家在阅读head.S源码时遇到具体问题(如某段汇编指令不懂、调试时卡壳),欢迎在评论区交流,后续可针对细节展开更深入的分析!


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    4

    文章

    1479

    浏览量

    43140
  • Linux
    +关注

    关注

    88

    文章

    11854

    浏览量

    219820
  • 文件
    +关注

    关注

    1

    文章

    599

    浏览量

    26167
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Linux Kernel 6.1 tools目录全解析 | RK平台ARM64交叉编译实战指南

    、硬件测试等全场景能力。 本文完整拆解 Linux Kernel 6.1 tools 目录所有模块功能,并给出 RK 平台 ARM64 架构交叉编译的标准指令 ,一站式解决内核工具使用
    的头像 发表于 04-16 18:42 7760次阅读
    Linux <b class='flag-5'>Kernel</b> <b class='flag-5'>6.1</b> tools目录全解析 | RK平台<b class='flag-5'>ARM64</b>交叉编译实战指南

    迅为RK3562开发板Android源码定制开发-kernel开发

    内核版本是 5.10.157 版本,内核默认的配置文件kernel-5.10/arch/arm64
    发表于 02-11 15:54

    如何对RK3399 CPU arm64内核进行配置

    如何对RK3399 CPU arm64内核进行配置?
    发表于 02-16 06:20

    Rk3399内核编译配置流程梳理

    firefly_defconfigmakeARCH=arm64 "${KERNEL_DTS}.img" -j $MAKE_THEARD说明:arch/arm64/configs
    发表于 05-26 10:59

    浅析openat系统调用在arm64下的实现及使用原理

    (openat),然后调用了svc进入异常处理。进入异常模式后,内核根据异常类型(同步异常)及当前所处的ELx, 调用相应的异常处理函数,这里是el0_sync。arch/arm64/ker
    发表于 06-02 17:48

    RK3568的.config文件是通过kernel/arch/arm64/configs中的哪个配置文件生成的呢

    RK3568的.config文件是通过kernel/arch/arm64/configs中的哪个配置文件生成的呢?如果新增了一个功能模块,需
    发表于 07-06 12:01

    迅为iTOP-RK3588开发板Android12源码定制开发kernel开发

    内核版本是 5.10.66 版本,内核默认的配置文件是 3588-android12/kernel-5.10/arch/
    发表于 06-09 15:54

    ARM64ARM32 的Linux程序区别在哪里

    arm64ARM64。我在示例中使用了AArch64寄存器,但我所描述的许多问题也发生在ARMv8-A 32位执行状态。
    的头像 发表于 08-09 09:51 2.9w次阅读
    <b class='flag-5'>ARM64</b>与<b class='flag-5'>ARM</b>32 的Linux程序区别在哪里

    ARM64 Linux内核页表的块映射

    内核文档Documentation/arm64/memory.rst描述了ARM64 Linux内核空间的内存映射情况,应该是此方面最权威文档。 以典型的4K页和48位虚拟地址为例,整
    的头像 发表于 01-04 13:37 3424次阅读
    <b class='flag-5'>ARM64</b> Linux<b class='flag-5'>内核</b>页表的块映射

    Core 3399KJ Linux根文件系统镜像(arm64/arm32)

    电子发烧友网站提供《Core 3399KJ Linux根文件系统镜像(arm64/arm32).txt》资料免费下载
    发表于 09-14 10:08 3次下载
    Core 3399KJ Linux根<b class='flag-5'>文件</b>系统镜像(<b class='flag-5'>arm64</b>/<b class='flag-5'>arm</b>32)

    Core 3399J Linux根文件系统镜像(arm64/arm32)

    电子发烧友网站提供《Core 3399J Linux根文件系统镜像(arm64/arm32).txt》资料免费下载
    发表于 09-14 09:24 0次下载
    Core 3399J Linux根<b class='flag-5'>文件</b>系统镜像(<b class='flag-5'>arm64</b>/<b class='flag-5'>arm</b>32)

    ROC RK3399 PC Pro文件系统Linux根文件系统镜像(arm64/arm32)

    电子发烧友网站提供《ROC RK3399 PC Pro文件系统Linux根文件系统镜像(arm64/arm32).txt》资料免费下载
    发表于 09-20 10:59 5次下载
    ROC RK3399 PC Pro<b class='flag-5'>文件</b>系统Linux根<b class='flag-5'>文件</b>系统镜像(<b class='flag-5'>arm64</b>/<b class='flag-5'>arm</b>32)

    AIO 3399ProC Linux根文件系统镜像(arm64/arm32)

    电子发烧友网站提供《AIO 3399ProC Linux根文件系统镜像(arm64/arm32).txt》资料免费下载
    发表于 09-21 09:52 11次下载
    AIO 3399ProC Linux根<b class='flag-5'>文件</b>系统镜像(<b class='flag-5'>arm64</b>/<b class='flag-5'>arm</b>32)

    ARM64位与ARM32位OP-TEE启动过程的差异

    ARM32的OP-TEE与ARM64的OP-TEE启动过程大致相同。ARM64的OP-TEE的_start函数定义在generic_entry_a64.S
    的头像 发表于 11-07 15:12 1859次阅读

    深入剖析ARM64异常处理:开发者必须掌握的底层核心逻辑

    ARM64架构的开发领域,异常处理绝非单纯的理论知识点,而是直接决定系统稳定性、调试效率和功能实现的关键技术。无论是嵌入式开发、Linux内核移植,还是驱动开发与芯片调试,理解异常发生后CPU
    的头像 发表于 12-24 07:05 1456次阅读
    <b class='flag-5'>深入</b><b class='flag-5'>剖析</b><b class='flag-5'>ARM64</b>异常处理:开发者必须掌握的底层核心逻辑