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

本文详细解析了 U-Boot 启动代码中的关键部分,包括异常中断向量表、复位代码、初始化代码及中断处理机制,旨在帮助开发者深入理解 U-Boot 启动流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 *  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.youkuaiyun.com/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内存图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值