(笔记)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: 确认异常向量表、堆栈设置、处理函数地址是否正确。

相关推荐
我在人间贩卖青春5 天前
汇编之伪指令
汇编·伪指令
我在人间贩卖青春6 天前
汇编之伪操作
汇编·伪操作
济6176 天前
FreeRTOS基础--堆栈概念与汇编指令实战解析
汇编·嵌入式·freertos
myloveasuka6 天前
汇编TEST指令
汇编
我在人间贩卖青春6 天前
汇编编程驱动LED
汇编·点亮led
我在人间贩卖青春6 天前
汇编和C编程相互调用
汇编·混合编程
myloveasuka7 天前
寻址方式笔记
汇编·笔记·计算机组成原理
请输入蚊子7 天前
《操作系统真象还原》 第六章 完善内核
linux·汇编·操作系统·bochs·操作系统真像还原
myloveasuka7 天前
指令格式举例
汇编·笔记·计算机组成原理
我在人间贩卖青春7 天前
汇编之分支跳转指令
汇编·arm·分支跳转