(笔记)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行)

assembly 复制代码
#include <asm-offsets.h>
#include <config.h>
#include <version.h>
#include <asm/system.h>
#include <linux/linkage.h>

作用:

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

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

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

重要说明:

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

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

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

SPL构建模式:

assembly 复制代码
_undefined_instruction: .word _undefined_instruction
_software_interrupt:    .word _software_interrupt
_prefetch_abort:        .word _prefetch_abort
# ... 其他向量指向自身,形成死循环

正常构建模式:

assembly 复制代码
_undefined_instruction: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:        .word prefetch_abort
# ... 向量指向实际的异常处理函数

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

4.1 保存启动参数

assembly 复制代码
reset:
	bl	save_boot_params    # 保存bootloader传递的参数

4.2 CPU模式设置

assembly 复制代码
	mrs	r0, cpsr           # 读取当前程序状态寄存器
	bic	r0, r0, #0x1f      # 清除模式位[4:0]
	orr	r0, r0, #0xd3      # 设置SVC32模式,禁用IRQ和FIQ
	msr	cpsr,r0            # 写回CPSR

模式说明:

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

4.3 向量基地址设置

assembly 复制代码
	mrc	p15, 0, r0, c1, c0, 0	# 读取系统控制寄存器
	bic	r0, #CR_V               # 清除V位,使VBAR有效
	mcr	p15, 0, r0, c1, c0, 0	# 写回控制寄存器

	ldr	r0, =_start             # 加载向量表基地址
	mcr	p15, 0, r0, c12, c0, 0	# 设置VBAR寄存器

4.4 低级初始化调用

assembly 复制代码
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_cp15          # 初始化协处理器CP15
	bl	cpu_init_crit          # 关键CPU初始化
#endif

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

5.1 缓存和TLB无效化

assembly 复制代码
	mov	r0, #0
	mcr	p15, 0, r0, c8, c7, 0	# 无效化所有TLB
	mcr	p15, 0, r0, c7, c5, 0	# 无效化指令缓存
	mcr	p15, 0, r0, c7, c5, 6	# 无效化分支预测器
	mcr	p15, 0, r0, c7, c10, 4	# 数据同步屏障(DSB)
	mcr	p15, 0, r0, c7, c5, 4	# 指令同步屏障(ISB)

5.2 系统控制寄存器配置

assembly 复制代码
	mrc	p15, 0, r0, c1, c0, 0   # 读取SCTLR寄存器
	bic	r0, r0, #0x00002000     # 清除V位(向量表高地址)
	bic	r0, r0, #0x00000007     # 清除C、A、M位
	orr	r0, r0, #0x00000002     # 设置A位(对齐检查)
	orr	r0, r0, #0x00000800     # 设置Z位(分支预测)
	orr	r0, r0, #0x00001000     # 设置I位(指令缓存)
	mcr	p15, 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. 堆栈设置和板级初始化

assembly 复制代码
call_board_init_f:
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)  # 设置初始堆栈指针
	bic	sp, sp, #7                      # 8字节对齐
	ldr	r0,=0x00000000                  # 清零参数
	bl	board_init_f                     # 调用C语言板级初始化

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

7.1 参数保存和堆栈设置

assembly 复制代码
ENTRY(relocate_code)
	mov	r4, r0	# 保存堆栈指针地址
	mov	r5, r1	# 保存全局数据指针
	mov	r6, r2	# 保存目标地址

stack_setup:
	mov	sp, r4  # 设置堆栈指针

7.2 重定位检查

assembly 复制代码
	adr	r0, _start              # 获取当前运行地址
	cmp	r0, r6                  # 与目标地址比较
	moveq	r9, #0              # 如果相同,无需重定位
	beq	clear_bss               # 跳转到BSS清零

7.3 代码复制循环

assembly 复制代码
copy_loop:
	ldmia	r0!, {r9-r10}       # 批量加载8字节数据
	stmia	r1!, {r9-r10}       # 批量存储到目标地址
	cmp	r0, r2                  # 检查是否完成
	blo	copy_loop               # 继续循环

7.4 动态重定位修复

assembly 复制代码
fixloop:
	ldr	r0, [r2]                # 读取重定位地址
	add	r0, r0, r9              # 添加重定位偏移
	ldr	r1, [r2, #4]            # 读取重定位信息
	and	r7, r1, #0xff           # 获取重定位类型
	cmp	r7, #23                 # 相对重定位?
	beq	fixrel
	cmp	r7, #2                  # 绝对重定位?
	beq	fixabs

8. 异常处理框架

8.1 寄存器保存宏

assembly 复制代码
.macro	bad_save_user_regs
	sub	sp, sp, #S_FRAME_SIZE   # 在堆栈上开辟异常帧
	stmia	sp, {r0 - r12}      # 保存通用寄存器
	# ... 保存CPSR、PC、LR等状态寄存器
.endm

8.2 异常处理函数

assembly 复制代码
undefined_instruction:
	get_bad_stack           # 获取异常处理堆栈
	bad_save_user_regs      # 保存用户寄存器
	bl	do_undefined_instruction  # 调用C处理函数

prefetch_abort:
	get_bad_stack
	bad_save_user_regs
	bl	do_prefetch_abort   # 处理指令预取异常

9. 关键内存布局

9.1 符号定义

assembly 复制代码
.globl _TEXT_BASE
_TEXT_BASE:
	.word	CONFIG_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 堆栈空间

assembly 复制代码
.globl IRQ_STACK_START
IRQ_STACK_START:
	.word	0x0badc0de              # IRQ堆栈起始地址

.globl FIQ_STACK_START
FIQ_STACK_START:
	.word 0x0badc0de               # FIQ堆栈起始地址

10. 启动流程总结

系统复位 跳转到_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: 确认异常向量表、堆栈设置、处理函数地址是否正确。

相关推荐
南玖yy1 小时前
Linux 桌面市场份额突破 5%:开源生态的里程碑与未来启示
linux·运维·服务器·汇编·科技·开源·gradle
南玖yy3 天前
Linux权限管理:从“Permission denied“到系统安全大师
linux·运维·汇编·后端·架构·系统安全·策略模式
Kira Skyler3 天前
c++,从汇编角度看lambda
汇编·c++
暗流者4 天前
学习pwn需要的基本汇编语言知识
汇编·学习·网络安全·pwn
单车少年ing7 天前
ARM64---C中调用汇编指令
汇编
无小道8 天前
函数返回值问题,以及返回值的使用问题(c/c++)
c语言·开发语言·汇编·c++
菜菜why10 天前
详细解析单片机启动汇编文件:以startup_stm32f407xx.s为例
汇编·单片机·嵌入式硬件·嵌入式软件
马里奥的蘑菇云11 天前
ARM GCC内联汇编
汇编·arm
AI迅剑11 天前
模块三:现代C++工程实践(4篇)第二篇《性能调优:Profile驱动优化与汇编级分析》
汇编·c++