分店英文代表:UBOOT1.3.1代码导读(1)-start.S

来源:百度文库 编辑:中财网 时间:2024/05/05 12:21:06
来源: ChinaUnix博客  日期: 2008.10.13 21:17 (共有条评论) 我要评论
作者:chenzhufly(空灵)     发表于2008/03/17       email:chenzhufly@126.com
要做毕业设计了,写论文前,还是分析分析代码吧,这样更加清楚一些,这些代码将在我设计的AT91RM9200板子上做实验,呵呵,开始了哦。。。。。
..\u-boot-1.3.1\cpu\arm920t\start.S
这个文件的任务是设置处理器状态、初始化中断和内存时序等,并确定是否需要对整个U-Boot代码重定位,最终从Flash中跳转到定位好的内存位置执行
#include
#include
#include
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
//异常处理向量表
.globl _start
_start:    b       start_code
ldr    pc, _undefined_instruction
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
_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
// .word expressions:定义一个字,并为之分配空间, 4bytes.
.balignl 16,0xdeadbeef
/***********************************************************************
.balign[wl] abs-expr, abs-expr, abs-expr
增加位置计数器(在当前子段)使它指向规定的存储边界。第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,单位为字节。例如,
'.balign 8’向后移动位置计数器直至计数器的值等于8的倍数。如果位置计数器已经是8的倍数,则无需移动。第2个表达式参数(结果必须是纯粹的
数字)给出填充字节的值,用这个值填充位置计数器越过的地方。第2个参数(和逗点)可以省略。如果省略它,填充字节的值通常是0。但在某些系统上,如果本
段标识为包含代码,而填充值被省略,则使用no-op指令填充空白区。第3个参数的结果也必须是纯粹的数字,这个参数是可选的。如果存在第3个参数,它代
表本对齐命令允许跳过字节数的最大值。如果完成这个对齐需要跳过的字节数比规定的最大值还多,则根本无法完成对齐。您可以在边界基准参数后简单地使用两个
逗号,以省略填充值参数(第二参数);如果您在想在适当的时候,对齐操作自动使用no-op指令填充,本方法将非常奏效。
.balignw和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。.balignl使用4字节来填充。例
如,.balignw 4,0x368d将地址对齐到4的倍数,如果它跳过2个字节,GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理
器的存储方式而定)。  如果它跳过1或3个字节,则填充值不明确。 ******************************************************************************/
/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/
//TEXT_BASE代表代码在运行时所在的地址
//TEXT_BASE在..\u-boot-1.3.1\board\at91rm9200dk\config.mk
_TEXT_BASE:
.word    TEXT_BASE
// 声明 _armboot_start 并用 _start 来进行初始化
// 标号_start在前面有定义
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
// 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在与板相关的u-boot.lds中。
// _bss_start保存的是__bss_start这个标号所在的地址, 这里涉及到当前代码所在
// 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时
// 地址的影响. _bss_end也是同样的道理.
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word    0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
/*
* the actual start code
*/
start_code:
/*
* set the cpu to SVC32 mode
*/
//  MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd
//  使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样可以最好地完成对CRSP或者SPSR的修改
//  MSR {} CPSR_|SPSR_,Rm 或者是 MSR {} CPSR_f|SPSR_f,#
//  MRS与MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分
//   bic r0,r1,r2  ;r0:=r1 and not r2
//   orr ro,r1,r2  ;r0:=r1 or r2
//  这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI)
mrs    r0,cpsr
//
取得当前程序状态寄存器cpsr到r0。
bic    r0,r0,#0x1f
// 把中断全部清除,只置位模式控制位
orr    r0,r0,#0xd3
// 1     1      0    10011//IRQ   FIQ   STATE   MODE// 禁止IRQ,FIQ中断,使用ARM指令,工作在supervisor模式
msr    cpsr,r0
//
设置cpsr
bl coloured_LED_init
bl red_LED_on
//coloured_LED_init()和red_LED_on()
//在..\u-boot-1.3.1\board\at91rm9200dk\led.c
#if    defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
/*
* relocate exception table
*/
//把异常向量表从_start开始的16个32位数拷贝到0x00地址
ldr    r0, =_start
ldr    r1, =0x0
mov    r2, #16
copyex:
subs    r2, r2, #1
ldr    r3, [r0], #4
str    r3, [r1], #4
bne    copyex
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)//这地方不考虑。。。。。。。。
/* turn off the watchdog */
# if defined(CONFIG_S3C2400)
#  define pWTCON        0x15300000
#  define INTMSK        0x14400008    /* Interupt-Controller base addresses */
#  define CLKDIVN    0x14800014    /* clock divisor register */
#else
#  define pWTCON        0x53000000
#  define INTMSK        0x4A000008    /* Interupt-Controller base addresses */
#  define INTSUBMSK    0x4A00001C
#  define CLKDIVN    0x4C000014    /* clock divisor register */
# endif
ldr     r0, =pWTCON
mov     r1, #0x0
str     r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov    r1, #0xffffffff
ldr    r0, =INTMSK
str    r1, [r0]
# if defined(CONFIG_S3C2410)
ldr    r1, =0x3ff
ldr    r0, =INTSUBMSK
str    r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr    r0, =CLKDIVN
mov    r1, #3
str    r1, [r0]
#endif    /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
//这个可以看看在..\u-boot-1.3.1\u-boot-1.3.1\include\configs\at91rm9200dk.h中是否定义
//如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,跳到cpu_init_crit
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl    cpu_init_crit
#endif
#ifdef    CONFIG_AT91RM9200
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:                /* relocate U-Boot to RAM        */
adr    r0, _start        /* r0 //把_start的相对地址移到r0
//代码的当前位置
ldr    r1, _TEXT_BASE        /* test if we run from flash or RAM */
//_TEXT_BASE地址,就是UBOOT在RAM中运行地址
//测试判断是从Flash启动,还是RAM,如果相同,就已经在RAM运行,否则就是FLASH中运行
//其中TEXT_BASE在..\u-boot-1.3.1\board\at91rm9200dk\config.mk
cmp     r0, r1                  /* don't reloc during debug         */
beq     stack_setup
//如果在FLASH中运行,要把FLASH中的BOOT代码移到RAM中,然后再运行
ldr    r2, _armboot_start
ldr    r3, _bss_start
sub    r2, r3, r2        /* r2 //r2保存UBOOT代码大小
add    r2, r0, r2        /* r2 //r2保存UBOOT代码最后地址
copy_loop:
ldmia    r0!, {r3-r10}        /* copy from source address [r0]    */
//从源地址[r0]读取8个字节到寄存器,每读一个就更新一
次r0地址
stmia    r1!, {r3-r10}        /* copy to   target address [r1]    */
//拷贝寄存器r3-r10的值保存到 [r1]指明的地址,每写一
个字节,就增加1
cmp    r0, r2            /* until source end addreee [r2]    */
//判断是否拷贝到[r2]地址,就是引导代码结束位置
ble    copy_loop
#endif    /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
/* Set up the stack                            */
//建立堆栈
stack_setup:
ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   */
sub    r0, r0, #CFG_MALLOC_LEN    /* malloc area                      */
sub    r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub    sp, r0, #12        /* leave 3 words for abort-stack    */
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...                    */
add    r0, r0, #4
cmp    r0, r1
ble    clbss_l
ldr    pc, _start_armboot    //跳到C代码
_start_armboot:    .word start_armboot
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
//
MCR 指令的格式为:   //MCR{条件} 协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。
//MCR 指令用于将ARM
处理器寄存器中的数据传送到协处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1 和协处理器操作码2
为协处理器将要执行的操作,源寄存器为ARM 处理器的寄存器,目的寄存器1 和目的寄存器2 均为协处理器的寄存器
//ARM的存储器管理是通过系统控制协处理器CP15完成的。CP15包含16个32位寄存器C0~C15    //在系统模式下访问CP15中的寄存器需要使用MCR和MRC两条指令。    //在用户模式下访问CP15中的寄存器需要使用软中断(SWI)调用的方式
mov    r0, #0
mcr    p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */
mcr    p15, 0, r0, c8, c7, 0    /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
//C1是一个控制寄存器,它控制MMU(MPU)的使能,数据Cache或统一Cache的使能,指令Cache的使能,写缓冲使能等
mrc    p15, 0, r0, c1, c0, 0
bic    r0, r0, #0x00002300    @ clear bits 13, 9:8 (--V- --RS)
bic    r0, r0, #0x00000087    @ clear bits 7, 2:0 (B--- -CAM)
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
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov    ip, lr
#if    defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
//这个地方是不是应该加一句bl    lowlevel_init//初始化sdram等,这样是不是就可以直接从0x0地址直接执行uboot了,需要做个实验。。。。
#else
bl    lowlevel_init
#endif
mov    lr, ip
mov    pc, lr
#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
sub    sp, sp, #S_FRAME_SIZE
stmia    sp, {r0 - r12}            @ Calling r0-r12
ldr    r2, _armboot_start
sub    r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub    r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
ldmia    r2, {r2 - r3}            @ get pc, cpsr
add    r0, sp, #S_FRAME_SIZE        @ restore sp_SVC
add    r5, sp, #S_SP
mov    r1, lr
stmia    r5, {r0 - r3}            @ save sp_SVC, lr_SVC, pc, cpsr
mov    r0, sp
.endm
.macro    irq_save_user_regs
sub    sp, sp, #S_FRAME_SIZE
stmia    sp, {r0 - r12}            @ Calling r0-r12//入栈
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 //寄存器R13在ARM指令中常用作堆栈指针
ldr    r13, _armboot_start        @ setup our mode stack
sub    r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
sub    r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack
str    lr, [r13]            @ save caller lr / spsr
mrs    lr, spsr
str     lr, [r13, #4]
mov    r13, #MODE_SVC            @ prepare SVC-Mode
@ msr    spsr_c, r13
msr    spsr, r13
mov    lr, pc
movs    pc, lr
.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
参考:
1) U-boot-13.0-rc3 start.S 分析http://bbs.21ic.com/club/bbs/list.asp?boardid=8&t=2756460&tp=U-boot-13.0-rc3+start.S+%B7%D6%CE%F6
2) uboot中c语言对汇编语言标号的引用http://blog.chinaunix.net/u/26710/showart_403988.html
3) 如何开发arm(3)
http://dayu.spaces.eepw.com.cn/articles/article/item/15636
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/78300/showart_1296412.html