(笔记)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
CONFIG_SYS_TEXT_BASE
CONFIG_SYS_INIT_SP_ADDR
CONFIG_SKIP_LOWLEVEL_INIT
CONFIG_SYS_ICACHE_OFF
CONFIG_USE_IRQ
12. 调试要点
- 向量表位置: 确保向量表正确对齐和定位
- 堆栈设置: 检查堆栈指针是否指向有效内存
- 重定位过程: 验证代码是否正确复制到RAM
- 缓存一致性: 确保指令和数据缓存同步
- MMU状态: 初期MMU应该关闭
13. 常见问题
Q1: 系统启动后卡在向量表?
A: 检查向量表地址是否正确设置,VBAR寄存器配置是否有误。
Q2: 重定位后程序崩溃?
A: 检查重定位地址计算、动态链接修复是否正确。
Q3: 异常处理不工作?
A: 确认异常向量表、堆栈设置、处理函数地址是否正确。