> 技术文档 > (笔记)U-boot 2012.10 armv7启动汇编解析

(笔记)U-boot 2012.10 armv7启动汇编解析


U-Boot ARM汇编启动代码分析

文件概述

文件路径: arch/arm/cpu/armv7/start.S
目标平台: ARM Cortex-A系列处理器
功能: U-Boot bootloader的启动汇编代码
版本: U-Boot 2012.10

文件结构概览

start.S├── 头文件包含和宏定义├── 中断向量表 (_start)├── 全局符号定义├── 复位代码 (reset)├── 代码重定位 (relocate_code)├── CPU初始化函数├── 异常处理函数└── 栈和内存管理

1. 头文件包含部分 (第31-35行)

#include #include #include #include #include 

作用:

  • asm-offsets.h: 汇编偏移量定义
  • config.h: 配置选项定义
  • version.h: 版本信息
  • asm/system.h: ARM系统相关定义
  • linux/linkage.h: 函数链接宏定义

2. 中断向量表 (第37-48行)

.globl _start_start: breset  # 复位向量 - 系统启动入口ldrpc, _undefined_instruction # 未定义指令异常ldrpc, _software_interrupt # 软件中断(SWI/SVC)ldrpc, _prefetch_abort # 指令预取异常ldrpc, _data_abort # 数据访问异常ldrpc, _not_used  # 保留向量ldrpc, _irq  # 普通中断请求ldrpc, _fiq  # 快速中断请求

重要说明:

  • ARM处理器复位后首先执行_start标签
  • 这是ARM架构标准的8个32位向量表
  • ldr pc, label指令将标签地址加载到程序计数器,实现跳转
  • 向量表必须位于地址0x00000000或0xFFFF0000

3. 向量地址定义 (第49-62行)

根据CONFIG_SPL_BUILD配置选择不同的向量处理方式:

SPL构建模式:

_undefined_instruction: .word _undefined_instruction_software_interrupt: .word _software_interrupt_prefetch_abort: .word _prefetch_abort# ... 其他向量指向自身,形成死循环

正常构建模式:

_undefined_instruction: .word undefined_instruction_software_interrupt: .word software_interrupt_prefetch_abort: .word prefetch_abort# ... 向量指向实际的异常处理函数

4. 系统复位代码 (reset标签, 第125行开始)

4.1 保存启动参数

reset:blsave_boot_params # 保存bootloader传递的参数

4.2 CPU模式设置

mrsr0, cpsr  # 读取当前程序状态寄存器bicr0, r0, #0x1f # 清除模式位[4:0]orrr0, r0, #0xd3 # 设置SVC32模式,禁用IRQ和FIQmsrcpsr,r0 # 写回CPSR

模式说明:

  • 0xd3 = 11010011 (binary)
  • Bit[4:0] = 10011 (SVC32模式)
  • Bit[7] = 1 (禁用IRQ)
  • Bit[6] = 1 (禁用FIQ)

4.3 向量基地址设置

mrcp15, 0, r0, c1, c0, 0# 读取系统控制寄存器bicr0, #CR_V  # 清除V位,使VBAR有效mcrp15, 0, r0, c1, c0, 0# 写回控制寄存器ldrr0, =_start # 加载向量表基地址mcrp15, 0, r0, c12, c0, 0# 设置VBAR寄存器

4.4 低级初始化调用

#ifndef CONFIG_SKIP_LOWLEVEL_INITblcpu_init_cp15 # 初始化协处理器CP15blcpu_init_crit # 关键CPU初始化#endif

5. CPU协处理器初始化 (cpu_init_cp15)

5.1 缓存和TLB无效化

movr0, #0mcrp15, 0, r0, c8, c7, 0# 无效化所有TLBmcrp15, 0, r0, c7, c5, 0# 无效化指令缓存mcrp15, 0, r0, c7, c5, 6# 无效化分支预测器mcrp15, 0, r0, c7, c10, 4# 数据同步屏障(DSB)mcrp15, 0, r0, c7, c5, 4# 指令同步屏障(ISB)

5.2 系统控制寄存器配置

mrcp15, 0, r0, c1, c0, 0 # 读取SCTLR寄存器bicr0, r0, #0x00002000 # 清除V位(向量表高地址)bicr0, r0, #0x00000007 # 清除C、A、M位orrr0, r0, #0x00000002 # 设置A位(对齐检查)orrr0, r0, #0x00000800 # 设置Z位(分支预测)orrr0, r0, #0x00001000 # 设置I位(指令缓存)mcrp15, 0, r0, c1, c0, 0 # 写回SCTLR

控制位说明:

  • M位(bit 0): MMU使能 (此时禁用)
  • A位(bit 1): 对齐检查使能
  • C位(bit 2): 数据缓存使能 (此时禁用)
  • I位(bit 12): 指令缓存使能
  • V位(bit 13): 向量表位置 (0=低地址,1=高地址)
  • Z位(bit 11): 分支预测使能

6. 堆栈设置和板级初始化

call_board_init_f:ldrsp, =(CONFIG_SYS_INIT_SP_ADDR) # 设置初始堆栈指针bicsp, sp, #7# 8字节对齐ldrr0,=0x00000000  # 清零参数blboard_init_f  # 调用C语言板级初始化

7. 代码重定位过程 (relocate_code)

7.1 参数保存和堆栈设置

ENTRY(relocate_code)movr4, r0# 保存堆栈指针地址movr5, r1# 保存全局数据指针movr6, r2# 保存目标地址stack_setup:movsp, r4 # 设置堆栈指针

7.2 重定位检查

adrr0, _start  # 获取当前运行地址cmpr0, r6  # 与目标地址比较moveqr9, #0  # 如果相同,无需重定位beqclear_bss  # 跳转到BSS清零

7.3 代码复制循环

copy_loop:ldmiar0!, {r9-r10} # 批量加载8字节数据stmiar1!, {r9-r10} # 批量存储到目标地址cmpr0, r2  # 检查是否完成blocopy_loop  # 继续循环

7.4 动态重定位修复

fixloop:ldrr0, [r2] # 读取重定位地址addr0, r0, r9  # 添加重定位偏移ldrr1, [r2, #4] # 读取重定位信息andr7, r1, #0xff  # 获取重定位类型cmpr7, #23  # 相对重定位?beqfixrelcmpr7, #2  # 绝对重定位?beqfixabs

8. 异常处理框架

8.1 寄存器保存宏

.macrobad_save_user_regssubsp, sp, #S_FRAME_SIZE # 在堆栈上开辟异常帧stmiasp, {r0 - r12} # 保存通用寄存器# ... 保存CPSR、PC、LR等状态寄存器.endm

8.2 异常处理函数

undefined_instruction:get_bad_stack  # 获取异常处理堆栈bad_save_user_regs # 保存用户寄存器bldo_undefined_instruction # 调用C处理函数prefetch_abort:get_bad_stackbad_save_user_regsbldo_prefetch_abort # 处理指令预取异常

9. 关键内存布局

9.1 符号定义

.globl _TEXT_BASE_TEXT_BASE:.wordCONFIG_SYS_TEXT_BASE # 代码段基地址.globl _bss_start_ofs_bss_start_ofs:.word __bss_start - _start # BSS段起始偏移.globl _bss_end_ofs_bss_end_ofs:.word __bss_end__ - _start # BSS段结束偏移

9.2 堆栈空间

.globl IRQ_STACK_STARTIRQ_STACK_START:.word0x0badc0de  # IRQ堆栈起始地址.globl FIQ_STACK_STARTFIQ_STACK_START:.word 0x0badc0de  # FIQ堆栈起始地址

10. 启动流程总结

#mermaid-svg-6HXc72PBb6inLcnD {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6HXc72PBb6inLcnD .error-icon{fill:#552222;}#mermaid-svg-6HXc72PBb6inLcnD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6HXc72PBb6inLcnD .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-6HXc72PBb6inLcnD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6HXc72PBb6inLcnD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6HXc72PBb6inLcnD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6HXc72PBb6inLcnD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6HXc72PBb6inLcnD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6HXc72PBb6inLcnD .marker.cross{stroke:#333333;}#mermaid-svg-6HXc72PBb6inLcnD svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6HXc72PBb6inLcnD .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6HXc72PBb6inLcnD .cluster-label text{fill:#333;}#mermaid-svg-6HXc72PBb6inLcnD .cluster-label span{color:#333;}#mermaid-svg-6HXc72PBb6inLcnD .label text,#mermaid-svg-6HXc72PBb6inLcnD span{fill:#333;color:#333;}#mermaid-svg-6HXc72PBb6inLcnD .node rect,#mermaid-svg-6HXc72PBb6inLcnD .node circle,#mermaid-svg-6HXc72PBb6inLcnD .node ellipse,#mermaid-svg-6HXc72PBb6inLcnD .node polygon,#mermaid-svg-6HXc72PBb6inLcnD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6HXc72PBb6inLcnD .node .label{text-align:center;}#mermaid-svg-6HXc72PBb6inLcnD .node.clickable{cursor:pointer;}#mermaid-svg-6HXc72PBb6inLcnD .arrowheadPath{fill:#333333;}#mermaid-svg-6HXc72PBb6inLcnD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6HXc72PBb6inLcnD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6HXc72PBb6inLcnD .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-6HXc72PBb6inLcnD .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-6HXc72PBb6inLcnD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6HXc72PBb6inLcnD .cluster text{fill:#333;}#mermaid-svg-6HXc72PBb6inLcnD .cluster span{color:#333;}#mermaid-svg-6HXc72PBb6inLcnD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6HXc72PBb6inLcnD :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}系统复位跳转到_start设置CPU为SVC32模式配置向量基地址初始化CP15协处理器调用cpu_init_crit设置堆栈指针调用board_init_f代码重定位到RAM修复动态链接清零BSS段跳转到board_init_r启动完成

11. 重要配置宏

宏定义 作用 CONFIG_SPL_BUILD SPL(Secondary Program Loader)构建模式 CONFIG_SYS_TEXT_BASE 代码段基地址 CONFIG_SYS_INIT_SP_ADDR 初始堆栈指针地址 CONFIG_SKIP_LOWLEVEL_INIT 跳过低级初始化 CONFIG_SYS_ICACHE_OFF 禁用指令缓存 CONFIG_USE_IRQ 启用中断支持

12. 调试要点

  1. 向量表位置: 确保向量表正确对齐和定位
  2. 堆栈设置: 检查堆栈指针是否指向有效内存
  3. 重定位过程: 验证代码是否正确复制到RAM
  4. 缓存一致性: 确保指令和数据缓存同步
  5. MMU状态: 初期MMU应该关闭

13. 常见问题

Q1: 系统启动后卡在向量表?

A: 检查向量表地址是否正确设置,VBAR寄存器配置是否有误。

Q2: 重定位后程序崩溃?

A: 检查重定位地址计算、动态链接修复是否正确。

Q3: 异常处理不工作?

A: 确认异常向量表、堆栈设置、处理函数地址是否正确。