Chinaunix首页 | 论坛 | 博客
  • 博客访问: 520279
  • 博文数量: 174
  • 博客积分: 4177
  • 博客等级: 上校
  • 技术积分: 1827
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-15 14:12
文章分类

全部博文(174)

文章存档

2018年(1)

2017年(1)

2013年(3)

2012年(9)

2010年(12)

2009年(5)

2008年(106)

2007年(37)

我的朋友

分类: LINUX

2007-10-24 22:11:57

#include
#include
#include


//global声明一个符号可被其它文件引用,相当于声明了一个全局变量,.globl与.global相同。
//该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。
.globl _start
_start: b    reset
    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

// .word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long与.int作用与之相同。
_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

// .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign的作用同.align。
// .align {alignment} {,fill} {,max}
//  其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0填充。max是填充字节数最大值,如果填充字节数超过max,
//  就不进行对齐,例如:
//  .align 4  /* 指定对齐方式为字对齐 */

    .balignl 16,0xdeadbeef


/*
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from RAM!
 * - relocate armboot to ram
 * - setup stack
 * - jump to second stage
 */

// TEXT_BASE在开发板相关的目录中的config.mk文件中定义, 它定义了
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
_TEXT_BASE:
    .word    TEXT_BASE

// 声明 _armboot_start 并用 _start 来进行初始化,在board/u-boot.lds中定义。
.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 reset code                            */
/*                                        */
/****************************************************************************/

//  MRS {} Rd,CPSR|SPSR 将CPSR|SPSR传送到Rd
//  使用这两条指令将状态寄存器传送到一般寄存器,只修改必要的位,再将结果传送回状态寄存器,这样可以最好地完成对CRSP或者SPSR的修改
//  MSR {} CPSR_|SPSR_,Rm 或者是 MSR {} CPSR_f|SPSR_f,#<32-bit immediate>
//  MRS与MSR配合使用,作为更新PSR的“读取--修改--写回”序列的一部分
//   bic r0,r1,r2  ;r0:=r1 and not r2
//   orr ro,r1,r2  ;r0:=r1 or r2
//  这几条指令执行完毕后,进入SVC模式,该模式主要用来处理软件中断(SWI)
reset:
    mrs    r0,cpsr        /* set the cpu to SVC32 mode        */
    bic    r0,r0,#0x1f        /* (superviser mode, M=10011)        */
    orr    r0,r0,#0x13
    msr    cpsr,r0

    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
//
// B----转移指令,跳转到指令中指定的目的地址
// BL---带链接的转移指令,像B一样跳转并把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程序的调用
// 该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。
//
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl    cpu_init_crit        /* we do sys-critical inits        */
#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
//调试阶段的代码是直接在RAM中运行的,而最后需要把这些代码固化到Flash中,因此U-Boot需要自己从Flash转移到
//RAM中运行,这也是重定向的目的所在。
//通过adr指令得到当前代码的地址信息:如果U-boot是从RAM开始运行,则从adr,r0,_start得到的地址信息为
//r0=_start=_TEXT_BASE=TEXT_BASE=0xa3000000;如果U-boot从Flash开始运行,即从处理器对应的地址运行,
//则r0=0x0000,这时将会执行copy_loop标识的那段代码了。
// _TEXT_BASE 定义在board/pxa255_idp/config.mk中
relocate:                /* relocate U-Boot to RAM        */
    adr    r0, _start        /* r0 <- current position of code   */
    ldr    r1, _TEXT_BASE    /* test if we run from flash or RAM */
    cmp    r0, r1            /* don't reloc during debug        */
    beq    stack_setup        /* 如果是从RAM启动,则开始设置堆栈 */

// 如果不是从RAM运行的话,则将代码拷贝到_TEXT_BASE标识的RAM中。
    ldr    r2, _armboot_start
    ldr    r3, _bss_start
    sub    r2, r3, r2        /* r2 <- size of armboot        */
    add    r2, r0, r2        /* r2 <- source end address        */

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 */

    /* Set up the stack    */
stack_setup:
    ldr    r0, _TEXT_BASE        /* upper 128 KiB: relocated uboot   */
    sub    r0, r0, #CFG_MALLOC_LEN     /* malloc area  CFG_MALLOC_LEN----(CFG_ENV_SIZE(256K) + 128*1024)    */
    sub    r0, r0, #CFG_GBL_DATA_SIZE  /* bdinfo CFG_GBL_DATA_SIZE    128---size in bytes reserved for initial data */    
// 这里如果需要使用IRQ, 还有给IRQ保留堆栈空间, 一般不使用.
#ifdef CONFIG_USE_IRQ
    sub    r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  //二者均为4K
#endif
    sub    sp, r0, #12        /* leave 3 words for abort-stack    */

//该部分将未初始化数据段_bss_start----_bss_end中的数据清零。
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

// 通过该语句跳转到C代码执行,stage1的使命也算完成。
    ldr    pc, _start_armboot

// start_armboot位于 lib_arm/board.c 中,是一个系统初始化的接口函数
_start_armboot: .word start_armboot


/****************************************************************************/
/*                                        */
/* CPU_init_critical registers                        */
/*                                        */
/* - setup important registers                        */
/* - setup memory timing                            */
/*                                        */
/****************************************************************************/
/* mk@tbd: Fix this! */
#ifdef CONFIG_CPU_MONAHANS
#undef ICMR
#undef OSMR3
#undef OSCR
#undef OWER
#undef OIER
#endif

/* Interrupt-Controller base address */
IC_BASE:       .word       0x40d00000
#define ICMR    0x04

/* Reset-Controller */
RST_BASE:    .word    0x40f00030
#define RCSR    0x00

//            OS定时器寄存器
//
//     地  址         名称        描    述
//  0x40a0 0000   OSMR0   OS定时器符合寄存器0
//  0x40a0 0004   OSMR1   OS定时器符合寄存器1
//  0x40a0 0008   OSMR2   OS定时器符合寄存器2
//  0x40a0 000C   OSMR3   OS定时器符合寄存器3
//  0x40a0 0010   OSCR    OS定时器计数寄存器
//  0x40a0 0014   OSSR    OS定时器状态寄存器
//  0x40a0 0018   OWER    OS定时器看门狗允许寄存器
//  0x40a0 001C   OIER    OS定时器中断寄存器
/* Operating System Timer */
OSTIMER_BASE:    .word    0x40a00000
#define OSMR3    0x0C
#define OSCR    0x10
#define OWER    0x18
#define OIER    0x1C

/* Clock Manager Registers */
//    地    址      名称        描   述
// 0x4130 0000   CCCR    核时钟配置寄存器
// 0x4130 0004   CKEN    时钟允许寄存器
// 0x4130 0008   OSCC    振荡配置寄存器
//
#ifdef CONFIG_CPU_MONAHANS
# ifndef CFG_MONAHANS_RUN_MODE_OSC_RATIO
#  error "You have to define CFG_MONAHANS_RUN_MODE_OSC_RATIO!!"
# endif
# ifndef CFG_MONAHANS_TURBO_RUN_MODE_RATIO
#  define CFG_MONAHANS_TURBO_RUN_MODE_RATIO 0x1
# endif
#else /* ! CONFIG_CPU_MONAHANS */
#ifdef CFG_CPUSPEED
CC_BASE:    .word    0x41300000
#define CCCR    0x00
cpuspeed:    .word    CFG_CPUSPEED
#else
#error "You have to define CFG_CPUSPEED!!"
#endif
#endif /* CONFIG_CPU_MONAHANS */


// .macro伪操作符标识宏定义的开始,.endm标识宏定义的结束。二者包含的一段代码,称为宏定义体,这样在程序中就可通过宏指令多次调用该代码段。
//  格式:
// .macro macroname {parameter{,parameter}...}
//  ...
// .endm
// 宏的参数可直接使用斜线“\字符”来引用,如下“\reg”所示。
// MRC指令的格式为:
// MRC{条件} 协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2。
// MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1和协处
// 理器操作码2为协处理器将要执行的操作,目的寄存器为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。
//  指令示例:
//   MRC   P3,3,R0,C4,C5,6    ;该指令将协处理器P3的寄存器中的数据传送到ARM处理器寄存器中。
/*  
* Arm MMU采用二级页表结构:一级页表(L1)和二级页表(L2)。一级页表L1中的页表项包括:用于转换1MB页的页表项和指向二级页表起始地址的页表项。
* L1主页表将4GB的地址空间划分为多个1MB的段,它包含4096个页表项,占据16KB的空间。L2页表有两种:L2粗(Coarse)页表和L2细 (fine)页表。
* L2粗页表可映射1MB的空间,支持4KB和64KB的页表项,页表项个数为256个(64KB的页表项要重复16次),占据1kB的空间(在L1表中L2粗页表的目录
* 项应在1KB地址边缘)。L2细页表可映射1MB的地址空间,支持1KB、4KB和64KB的页表项,页表项个数为 1024个(4KB表项重复4次,64KB表项重复64次),
* 占据4KB的空间(在L1表中L2细页表的目录项应在4KB地址边缘)。CP15的C2寄存器保存这转换表基地址,指向L1表的起始地址(位于16KB地址边缘)
*/
// 该宏的作用就是读取转换表基地址并将其存放在reg寄存器中。
    /* takes care the CP15 update has taken place */
    .macro CPWAIT reg
    mrc  p15,0,\reg,c2,c0,0
    mov  \reg,\reg
    sub  pc,pc,#4
    .endm

cpu_init_crit:

// 中断控制器共有6个寄存器
//
//    地 址        名称         描      述
// 0x40D0 0000  ICIP  中断控制器IRQ Pending寄存器
// 0x40D0 0004  ICMR  中断控制器屏蔽寄存器
// 0x40D0 0008  ICLR  中断控制器级别寄存器
// 0x40D0 000C  ICFR  中断控制器FIQ Pending寄存器
// 0x40D0 0010  ICPR  中断控制器Pending寄存器
// 0x40D0 0014  ICCR  中断控制器控制寄存器
// 一般的引导装入程序都不采用中断,即使采用中断也得在完成中断机制的初始化之前先关闭中断,以免干扰,所以这里的第一步就是屏蔽掉所有中断请求。
/* CONFIG_CPU_MONAHANS 定义在中,用来进行芯片选择,Monahans是XScale PXA27X系列的新成员*/
    /* mask all IRQs     */
#ifndef CONFIG_CPU_MONAHANS    
    ldr    r0, IC_BASE       
    mov    r1, #0x00
    str    r1, [r0, #ICMR]
#else
    /* Step 1 - Enable CP6 permission */
    mrc    p15, 0, r1, c15, c1, 0 @ read CPAR
    orr    r1, r1, #0x40
    mcr    p15, 0, r1, c15, c1, 0
    CPWAIT    r1

    /* Step 2 - Mask ICMR & ICMR2 */
    mov    r1, #0
    mcr    p6, 0, r1, c1, c0, 0    @ ICMR
    mcr    p6, 0, r1, c7, c0, 0    @ ICMR2

    /* turn off all clocks but the ones we will definitly require */
    ldr    r1, =CKENA
    ldr    r2, =(CKENA_22_FFUART | CKENA_10_SRAM | CKENA_9_SMC | CKENA_8_DMC)
    str    r2, [r1]
    ldr    r1, =CKENB
    ldr    r2, =(CKENB_6_IRQ)
    str    r2, [r1]
#endif

    /* set clock speed   设置时钟*/
#ifdef CONFIG_CPU_MONAHANS
    ldr    r0, =ACCR
    ldr    r1, =(((CFG_MONAHANS_TURBO_RUN_MODE_RATIO<<8) & ACCR_XN_MASK) | (CFG_MONAHANS_RUN_MODE_OSC_RATIO & ACCR_XL_MASK))
    str    r1, [r0]
#else /* ! CONFIG_CPU_MONAHANS */
#ifdef CFG_CPUSPEED
    ldr    r0, CC_BASE       //0x41300000
    ldr    r1, cpuspeed        //cpuspeed = CFG_CPUSPEED
    str    r1, [r0, #CCCR]   //CCCR = 0x00
    mov    r0, #2
    mcr    p14, 0, r0, c6, c0, 0  //进入频率变化顺序

setspeed_done:

#endif /* CFG_CPUSPEED */
#endif /* CONFIG_CPU_MONAHANS */

    /*
     * 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
     bl    lowlevel_init
     mov    lr,    ip

    /* Memory interfaces are working. Disable MMU and enable I-cache.   */
    /* mk: hmm, this is not in the monahans docs, leave it now but
     *     check here if it doesn't work :-) */

    ldr    r0, =0x2001        /* enable access to all coproc.        */
    mcr    p15, 0, r0, c15, c1, 0
    CPWAIT r0

    mcr    p15, 0, r0, c7, c10, 4    /* drain the write & fill buffers   */
    CPWAIT r0

    mcr    p15, 0, r0, c7, c7, 0    /* flush Icache, Dcache and BTB        */
    CPWAIT r0

    mcr    p15, 0, r0, c8, c7, 0    /* flush instuction and data TLBs   */
    CPWAIT r0

    /* Enable the Icache                            */
/*
    mrc    p15, 0, r0, c1, c0, 0
    orr    r0, r0, #0x1800
    mcr    p15, 0, r0, c1, c0, 0
    CPWAIT
*/
    mov    pc, lr


/****************************************************************************/
/*                                        */
/* 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

    /* use bad_save_user_regs for abort/prefetch/undef/swi ...        */

    .macro    bad_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            /* Calling r0-r12        */
    add    r8, sp, #S_PC

    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 - r4}            /* get pc, cpsr, old_r0        */
    add    r0, sp, #S_FRAME_SIZE        /* restore sp_SVC        */

    add    r5, sp, #S_SP
    mov    r1, lr
    stmia    r5, {r0 - r4}            /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
    mov    r0, sp
    .endm


    /* use irq_save_user_regs / irq_restore_user_regs for             */
    /* IRQ/FIQ handling                             */

    .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
    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
    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
    irq_save_user_regs        /* someone ought to write a more    */
    bl    do_fiq            /* effiction fiq_save_user_regs        */
    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

/****************************************************************************/
/*                                        */
/* Reset function: the PXA250 doesn't have a reset function, so we have to  */
/* perform a watchdog timeout for a soft reset.                    */
/*                                        
 The processor contains a 32-bits OS timer that is clocked by the 3.864 MHZ
 oscillator.The Operating System Count register(OSCR) is a free running
 up-counter.The OS timer also contains four 32-bit match registers (OSMR3,
 OSMR2,OSMR1,OSMR0).Developers can read and write to each register.
 When the value in the OSCR is equal to the value within any of the match
 register,and the interrupt enable bit is set,the corresponding bit in the
 OSSR is set.These bits are also routed to the interrupt controller where they
 can be programmed to cause an interrupt. OSMR3 also serves as a watchdog match
 register that resets the processor when a match occurs provided the OS Timer
 Watchdog Match Enable Register(OWER) is set.You must initialize the OSCR and
 OSMR registers and clear any set status bits before the FIQ and IRQ interrupts
 are enabled within the CPU
/****************************************************************************/

    .align    5
.globl reset_cpu

    /* FIXME: this code is PXA250 specific. How is this handled on        */
    /*      other XScale processors?                    */

reset_cpu:
/***************************************************************************
* This bit is set by writing a one to it and can only be cleared by
* one of the reset functions such as,hardware reset,sleep reset,watchdog
* reset,and GPIO reset
* 只有最低位可进行设置<31:1>不能设置
* 0-----OSMR3 match will not cause a reset of the processor
* 1-----OSMR3 match will cause a reset of the processor
****************************************************************************/

    /* We set OWE:WME (watchdog enable) and wait until timeout happens  */

    ldr    r0, OSTIMER_BASE            //0x40a00000
    ldr    r1, [r0, #OWER]            //OWER OS Timer Watchdog Enable Register
    orr    r1, r1, #0x0001            /* bit0: WME            */
    str    r1, [r0, #OWER]

    /* OS timer does only wrap every 1165 seconds, so we have to set    */
    /* the match register as well.                        */

    ldr    r1, [r0, #OSCR]            /* read OS timer OSCR:OS Timer Counter Register */
    add    r1, r1, #0x800            /* let OSMR3 match after    */
    add    r1, r1, #0x800            /* 4096*(1/3.6864MHz)=1ms   */
    str    r1, [r0, #OSMR3]

reset_endless:

    b    reset_endless

阅读(1043) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~