start.S进一步、更详细的、深入的解释和分析 2013.04.26更新(五)

转自:http://zqwt.012.blog.163.com/blog/static/12044684201332663357278/

 

copy_loop:

       ldmia    r0!, {r3-r10}   

/* copy from source address [r0] _start,即uboot的入口地址   */

      stmia    r1!, {r3-r10}        /* copy to  target address [r1](_TEXT_BASE)   */

      cmp     r0, r2                   /* until source end address [r2]    */

       ble     copy_loop    //Branch if Less than or Equal

    /* 在这个循环中,r0的值是不断增大的,直到大于r2,r2也就是BSS段的起始地址(即uboot代码存放的结束地址)*/

#endif   /* CONFIG_SKIP_RELOCATE_UBOOT */

l   设置堆栈(设置uboot在SDRAM里的基地址(即加载地址)_TEXT_BASE = 0x33F80000)

这里需要注意的是堆栈在代码段的下方!宏CFG_MALLOC_LEN和CFG_GBL_DATA_SIZE在目标板的头文件中定义u-boot\include\configs\smdk2410.h,可以按下面这张图来理解:

start.S进一步、更详细的、深入的解释和分析 2013.04.26更新(五)_第1张图片

stack_setup:

      ldr  r0, _TEXT_BASE 

/* upper 128 KiB: relocated uboot 这句话意思是,_TEXT_BASE上面是128 KiB重定位之后的u-boot */

sub  r0, r0, #CFG_MALLOC_LEN    

/* malloc area _TEXT_BASE向下是内存分配空间 */

sub  r0, r0, #CFG_GBL_DATA_SIZE

/* bdinfo 然后是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 给堆栈异常留3个字的空间 */

l   这里是所谓BSS段清零

BSS(Block Started by Symbol)段是可执行文件中的一种数据段。通常ARM编译器生成的可执行文件由两部分数据组成,分别是代码段和数据段。代码段又分为可执行代码段(text)和只读数据段(rodata);数据段又分为初始化数据段(data)和未初始化数据段(bss)。

clear_bss:

       ldr  r0, _bss_start           /* 找到bss段的开始地址 */

       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

… …

l   跳转到start_armboot函数入口(去sdram执行代码),_start_armboot保存函数入口指针(其实,可以在这一句之前添加vivi的copy_myself函数,通过c语言来将nandflash的前4k代码搬运到sdram中)

      ldr  pc, _start_armboot

_start_armboot: .word start_armboot

/* start_armboot()在lib_arm\board.c中定义,

* 它类似于Linux内核的start_kernel(),

* 它们都是一种系统初始化的接口函数:

* 在start_kernel()中集中完成了内核几乎所有资源的初始化,

* 包括CPU相关的资源和外设接口等;

* 而在start_armboot()中也要完成一些初始化工作。

*/

/*

* CPU_init_critical registers

* CPU_init_critical临界区寄存器

* setup important registers

 * setup memory timing

* 此处要设置一些重要的寄存器,并进行内存测试。*/

 *************************************************************************

 */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

l   设置CP15寄存器

 CP15寄存器是系统控制协处理器,用于连接在内存中的页表描述符此外还用于决定对MMU的操作。设置CP15寄存器的目的是失效Icache(指令cache)和Dcache(数据cache),然后禁止MMU和cache。

cpu_init_crit:

       /*

        * flush v4 I/D caches

      使I/D caches失效

        */

      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

        */

      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

l   想进一步了解协处理器CP15,可以点击链接:

http://zqwt.012.blog.163.com/blog/static/120446842010473171279/

       /*

        * before relocating, we have to setup RAM timing

      在搬运代码之前,我们必须设置好sram的时钟

        * because memory timing is board-dependend, you will

      因为sram时序是依赖于具体的开发板的,你将会 

 * find a lowlevel_init.S in your board directory.

      在自己的开发板目录board目录下发现一个

lowlevel_init.S文件。实际上,这个文件所做的工作主要就是内存的初始化。

        */

l   配置内存控制寄存器(第三个要修改的地方

因为内存控制寄存器是和开发板密切相关的,寄存器的具体值由开发商或者硬件工程师提供,如果对总线周期和外围芯片非常熟悉,也可以自己定义。在uboot中的设置文件是board/diamond2410/lowlevel_init.S,该文件包含lowlevel_init程序段,用于内存控制配置。

l   lr为链接寄存器,看了这段文字之后,就很容易理解了:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

    相对寻址

与基址变址寻址方式相类似,相对寻址以程序计数器PC的当前值为基地址指令中的地址标号作为偏移量将两者相加之后得到操作数的有效地址。以下程序段完成子程序的调用和返回,跳转指令BL采用了相对寻址方式:

l   BL    NEXT           @跳转到子程序,到NEXT处执行

@此时LR自动接收来自R15(PC)的拷贝,即程序当前运行的地址,以便之后从子程序返回

       ……                                           

       NEXT

       ……                                           

       MOV      PC,LR           @从子程序返回

注意:

l   pc: 总是包含下一个要被执行的指令的位置。

l   lr: 当程序Branch和Link(BL)的时候,总是接受一个来自R15(PC)的拷贝

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@此时lr里应该是”bl   cpu_init_crit”这条指令后面紧接着的一条指令的地址

      mov      ip, lr  

      bl   lowlevel_init  /*此时lr里应该是” bl lowlevel_init(start.S中)”这条指令后面紧接着的一条指令的地址*/

      mov      lr, ip  /*此时lr里应该是”bl      cpu_init_crit”这条指令后面紧接着的一条指令的地址*/

      mov      pc, lr

@此时,程序从”bl cpu_init_crit”这条指令后面紧接着的一条指令开始执行

#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

      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

 

你可能感兴趣的:(start.S进一步、更详细的、深入的解释和分析 2013.04.26更新(五))