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

发布于:2025-07-27 ⋅ 阅读:(13) ⋅ 点赞:(0)

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 <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行)

.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构建模式:

_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:
	bl	save_boot_params    # 保存bootloader传递的参数

4.2 CPU模式设置

	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 向量基地址设置

	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 低级初始化调用

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	bl	cpu_init_cp15          # 初始化协处理器CP15
	bl	cpu_init_crit          # 关键CPU初始化
#endif

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

5.1 缓存和TLB无效化

	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 系统控制寄存器配置

	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. 堆栈设置和板级初始化

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 参数保存和堆栈设置

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

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

7.2 重定位检查

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

7.3 代码复制循环

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

7.4 动态重定位修复

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 寄存器保存宏

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

8.2 异常处理函数

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 符号定义

.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 堆栈空间

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


网站公告

今日签到

点亮在社区的每一天
去签到