[uboot学习笔记(二)]uboot第一阶段start.S文件分析

时间:2022-02-17 04:05:06
/*
* armboot - Startup Code for ARM926EJS CPU-core
*
* Copyright (c) 2003 Texas Instruments
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
* Copyright (c) 2001 Marius Gr鰃er <mag@sysgo.de>
* Copyright (c) 2002 Alex Z黳ke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/


/**********************************************************************
*uboot version: 2009.08
*board version: freescale imx28
*UBOOT第一阶段启动代码
*path: /cpu/arm926ejs/start.S
*
**********************************************************************/


#include <config.h>
#include <common.h>
#include <version.h>

#if defined(CONFIG_OMAP1610)
#include <./configs/omap1510.h>
#elif defined(CONFIG_OMAP730)
#include <./configs/omap730.h>
#endif

/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/



.globl _start /*定义全局符号标签,相当于c语言的extern */
_start: /*异常中断向量表,CPU的几种异常中断跳转处理子函数*/
b reset /*复位跳转*/
ldr pc, _undefined_instruction /*未知代码异常中断处理。(PC跳转到标号指向的地址执行)*/
ldr pc, _software_interrupt /*软中断异常中断处理*/
ldr pc, _prefetch_abort /*预取指令异常中断处理*/
ldr pc, _data_abort /*数据操作异常中断处理*/
ldr pc, _not_used
ldr pc, _irq /*慢中断处理*/
ldr pc, _fiq /*快中断处理*/

_undefined_instruction:
.word undefined_instruction /*.word 分配4字节空间*/
/*值等于undefined_instruction子函数的绝对地址*/
/*相当于C的函数指针,以下类同*/
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq

.balignl 16,0xdeadbeef /*当前地址的前面,找到16字节对齐的地址*/
/*写入参数二的值*/
/*dead beef 死牛肉。(作标记用)*/


/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/


_TEXT_BASE:
.word TEXT_BASE /*定义一个4字节空间,值为TEXT_BASE = 0x41008000*/
/*定义在board/freescare/mx28_evk/config.mk*/

.globl _armboot_start
_armboot_start:
.word _start /*定义一个4字节变量*/
/*值是标号的绝对地址(链接地址)*/
/*
* These are defined in the board-specific linker script.
*/

.globl _bss_start
_bss_start:
.word __bss_start /*u-boot.lds定义的链接地址 __bss_start = .; */

.globl _bss_end
_bss_end:
.word _end /*u-boot.lds定义的链接地址 _end = .;*/

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de /*0x bad code :不需要IRQ栈空间*/

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de /*0x bad code :不需要FRQ栈空间*/
#endif


/*
* 实际的reset代码
*/

.globl reset
reset:
/*
* set the cpu to SVC32 mode
*设置为管理模式,禁止中断FIQ,IRQ
*/

/*
@把CPSR内容存入r0.使用了mrs指令:专用寄存器到通过寄存器的存取.
@CPSR当前程序状态寄存器格式如下:

@ 31 30 29 28 27 26 25 24 ~ ~ ~ 8 7 6 5 4 3 2 1 0
@ ___ ___ ___ ___ ___ ___ ___ ___ _ _ _ _ ___ ___ ___ ____ ____ ____ ____ ____
@| N | Z | C | V | * | * | * | * | * * * | I | F | T | M4 | M3 | M2 | M1 | M0 |
@| N | Z | C | V | * | * | * | * | * * * | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
@*/

mrs r0,cpsr /*mrs: mv reg <- stat.状态寄存器传递到普通寄存器*/
bic r0,r0,#0x1f /*bic: 清bit[0-4] set svc mode*/
orr r0,r0,#0xd3 /*orr:或0xd3 disable irq/fiq*/
msr cpsr,r0 /*msr: mv stat <- reg.普通寄存器传递到状态寄存器*/

/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM 自拷贝代码 */
adr r0, _start /* r0 <- current position of code */
/*adr为相对寻址指令。此处r0等于实际运行的地址:_start*/
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
/*此处r1为_TEXT_BASE宏定义的值 */
/*TEXT_BASE = 0x41008000在board/freescale/mx28_evk/config.mk定义*/
cmp r0, r1 /* don't reloc during debug */
beq stack_setup /*如果相等,说明uboot已经被搬运到期望的_TEXT_BASE定义的地址*/
/*adr/ldr区别参考博文:http://blog.csdn.net/gujintong1110/article/details/44246915*/
/*求 boot代码大小*/
ldr r2, _armboot_start /*r2=_start 绝对地址(链接地址)*/
ldr r3, _bss_start /*r3=_bss_start 绝对地址(链接地址)*/
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */

/*自搬移 FLASH->RAM 拷贝整个可执行文件*/
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

/* 设置栈指针地址,指向
*_TEXT_BASE-CONFIG_SYS_MALLOC_LEN-CONFIG_SYS_GBL_DATA_SIZE-
*CONFIG_STACKSIZE_IRQ-CONFIG_STACKSIZE_FIQ-12
*PATH: /include/configs/mx28_evk.h
*/

stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area 定义include/configs/mx28_evk.h */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bd info */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */

/*清bss段*/
clear_bss:
ldr r0, _bss_start /* find start of bss segment 绝对地址(链接地址)*/
ldr r1, _bss_end /* stop here 绝对地址(链接地址)*/
mov r2, #0x00000000 /* clear */

clbss_l:str r2, [r0] /* clear loop...清零bss段 */
add r0, r0, #4
cmp r0, r1
ble clbss_l

/*bl指令-> B:跳转,L: Branch with Link, 跳转时将下一条指令的地址拷贝到R14(lr)中*/
bl coloured_LED_init /*led等初始化*/
bl red_LED_on /*亮红灯*/

ldr pc, _start_armboot /*去c文件 /lib_arm/board.c*/
/*注意:_start_armboot指向的地址是start_armboot*/
/*start_armboot是C函数绝对地址(链接地址),地址在RAM中*/
/*uboot第一阶段在flash中运行,程序执行地址和链接地址
/*是不相同的。由于第一阶段指令都是相对寻址,所以不会出错*/

/*_start_armboot开始uboot第二阶段C程序部分。*/
_start_armboot:
.word start_armboot /*分配4字节空间,保存C函数地址*/


/*
*************************************************************************
* 初始化CPU关键寄存器,如MMU ,cache
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:

/*
* flush v4 I/D caches
*/

mov r0, #0

/*CP15协处理器介绍参考《ARM体系结构与编程》杜春雷5.5.2章节CP15寄存器*/
/*CP15协寄存器组(c0-c15) mcr/mrc协处理操作指令*/
/*指令前半段:[mcr p15, 0,]固定格式*/
/*指令后半段:[r0, c7, c7, 0]表示r0-->c7. [c7,0]组合成操作码*/
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache c7寄存器为高速缓存和写缓存*/
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB c8寄存器为TLB控制*/

/*
* disable MMU stuff and caches
*/

mrc p15, 0, r0, c1, c0, 0 /*c1:多种功能控制位寄存器*/
/*V:选中断向量表处低端地址0x0-0x1c*/
/*RS:rom/system保护位*/
bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
/*B:小端存储.*/
/*CAM:disable cache/地址对齐检查标志位/mmu*/
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
/*A:字节对齐标志位*/
orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache 使能*/
mcr p15, 0, r0, c1, c0, 0

/*
* Go setup Memory and board specific bits prior to relocation.
*/

/*
使用汇编器预处理器的功能,你可以定义 R0 等名字。
APCS 对我们通常称为 R0 到 R14 的寄存器起了不同的名字。

寄存器名字
Reg # APCS 意义
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必须保护
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 栈限制
R11 fp 桢指针
R12 ip
R13 sp 栈指针
R14 lr 连接寄存器
R15 pc 程序计数器

译注:ip 是指令指针的简写。
*/

/*1.保存本函数的返回地址LR到R12*/
/*2.BL跳转(保存返回地址的跳转PC->LR)*/
/*3.恢复本函数返回地址*/
/*4.函数返回*/
mov ip, lr /* perserve link reg across call */
bl lowlevel_init /* go setup pll,mux,memory */
/*板级相关初始化*/
/*详见board/freescale/mx28_evk/lowlevel_init.S*/

mov lr, ip /* restore link */
mov pc, lr /* back to my caller */
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/


@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72

#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52

#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0

#define MODE_SVC 0x13
#define I_BIT 0x80

/*异常处理 保存寄存器组和栈
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/


.macro bad_save_user_regs /*定义一个宏代码段相当于c的inline内联函数*/
@ carve out a frame on current user stack
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12

ldr r2, _armboot_start
sub r2, r2, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
@ get values for "aborted" pc and cpsr (into parm regs)
ldmia r2, {r2 - r3}
add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp @ save current stack into r0 (param register)
.endm

.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ Calling SP, LR
str lr, [r8, #0] @ Save calling PC
mrs r6, spsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
.endm

.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm

.macro get_bad_stack
ldr r13, _armboot_start @ setup our mode stack
sub r13, r13, #(CONFIG_STACKSIZE+CONFIG_SYS_MALLOC_LEN)
sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

str lr, [r13] @ save caller lr in position 0 of saved stack
mrs lr, spsr @ get the spsr
str lr, [r13, #4] @ save spsr in position 1 of saved stack
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13 @ switch modes, make sure moves will execute
mov lr, pc @ capture return pc
movs pc, lr @ jump to next instruction & switch modes.
.endm

.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm

.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm

/*
* exception handlers
*/

.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction

.align 5
software_interrupt:
get_bad_stack
bad_save_user_regs
bl do_software_interrupt

.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort

.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort

.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used

#ifdef CONFIG_USE_IRQ

.align 5
irq:
get_irq_stack
irq_save_user_regs
bl do_irq
irq_restore_user_regs

.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs

#else

.align 5
irq:
get_bad_stack
bad_save_user_regs
bl do_irq

.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq

#endif

[uboot学习笔记(二)]uboot第一阶段start.S文件分析