Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3185
  • 博文数量: 6
  • 博客积分: 165
  • 博客等级: 入伍新兵
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-15 22:26
文章分类

全部博文(6)

文章存档

2011年(6)

我的朋友
最近访客

分类: 嵌入式

2011-10-22 22:43:49

    u-boot-1.1.6源码学习主要讲述和总结了本人在学习u-boot中的每个步骤,由于水平有限,难免有误,欢迎指正。
 
6. u-boot源码分析——第一阶段之start.S
   
    有u-boot.lds可知,首先执行的程序是start.S,那么我们就打开smdk2410要运行的第一个程序cpu/arm920t/start.S(即u-boot的stage1部分)。
 
    cpu/arm920t/start.S开头有如下的代码:
 
#include
#include

.globl _start        //声明_start,并告诉链接器此变量是全局的,外部可以访问
 
_start: b       reset     // _start是一个标号,_start的值就是这个代码的位         
            // 置,此处即为代码的最开始,相对的0位置。而此处最开始的相对的0位置,
            // 在程序开始运行的时候,如果是从NorFlash启动,那么其地址是0;
            // 如果是重新relocate代码之后,就是我们定义的值了,即TEXT_BASE
            // TEXT_BASE是在board/smdk2410/config.mk中定义,TEXT_BASE = 0x33F80000
 
 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
.balignl 16,0xdeadbeef    // 接下来的代码都要16字节对齐,不足之处用0xdeadbeef填充
 
 
以上代码设置了ARM异常向量表,各个异常向量介绍如下:

1   ARM异常向量表

地址

异常

进入模式

描述

0x00000000

复位

管理模式

复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行

0x00000004

未定义指令

未定义模式

遇到不能处理的指令时,产生未定义指令异常

0x00000008

软件中断

管理模式

执行SWI指令产生,用于用户模式下的程序调用特权操作指令

0x0000000c

预存指令

中止模式

处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常

0x00000010

数据操作

中止模式

处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常

0x00000014

未使用

未使用

未使用

0x00000018

IRQ

IRQ

外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常

0x0000001c

FIQ

FIQ

快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常

 
    cpu/arm920t/start.S中还有这些异常对应的异常处理程序。当一个异常产生时,CPU根据异常号在异常向量表中找到对应的异常向量,然后执行异常向量处的跳转指令,CPU就跳转到对应的异常处理程序执行。
   
    接下来继续看代码:
 

_TEXT_BASE:

    .word TEXT_BASE  // TEXT_BASE是在board/smdk2410/config.mk中定义,为0x33F80000

 

.globl _armboot_start  
_armboot_start:
    .word _start             //  这几行含义可用C语言表示为:*(_armboot_start) = _start


.globl _bss_start
_bss_start:
     .word __bss_start      //  这几行含义可用C语言表示为:*(_bss_start) = __bss_start__bss_start       

                                      //  __bss_start是在u-boot.lds中定义的                      

.globl _bss_end
_bss_end:
    .word _end               //   这几行含义可用C语言表示为:*(_bss_end) = _end

                                    //   _end是在u-boot.lds中定义的

 

#ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START           //  声明一个全局变量IRQ_STACK_START
IRQ_STACK_START:
    .word 0x0badc0de


.globl FIQ_STACK_START          // 声明一个全局变量FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de


#endif

 
    在u-boot.lds中指定入口地址为_start,而由_start: b reset可知,程序的执行跳转到reset处,接下来看reset处的代码:
 

reset:

         mrs  r0,cpsr

         bic    r0,r0,#0x1f

         orr    r0,r0,#0xd3

         msr  cpsr,r0                  // 关闭中断,切换处理器到管理模式

 

#if defined(CONFIG_S3C2400)

 

# define pWTCON             0x15300000

# define INTMSK                0x14400008    

# define CLKDIVN    0x14800014  

  

#elif defined(CONFIG_S3C2410)

 

# define pWTCON             0x53000000

# define INTMSK                0x4A000008    

# define INTSUBMSK        0x4A00001C

# define CLKDIVN    0x4C000014                // 寄存器地址定义,可查看datasheet

 

#endif

 

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

         ldr     r0, =pWTCON

         mov     r1, #0x0

         str     r1, [r0]                                   // 关闭看门狗

        

         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!

          */

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

         ldr    r1, _TEXT_BASE                     /* test if we run from flash or RAM */

         cmp     r0, r1                                   /* don't reloc during debug         */

         beq     stack_setup

 

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

         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

 

#if 0

                                    /* try doing this stuff after the relocation */

         ldr     r0, =pWTCON

         mov     r1, #0x0

         str     r1, [r0]

 

         mov r1, #0xffffffff

         ldr    r0, =INTMR

         str    r1, [r0]

 

         ldr    r0, =CLKDIVN

         mov r1, #3

         str    r1, [r0]

 

#endif

 

         ldr    pc, _start_armboot

_start_armboot:      .word start_armboot         // 把_start_armboot地址处的值也就是start_armboot

                                 //   绝对地址值移到pc,终于跳到C代码了 

 

        这部分代码还是很好理解的,注释也很详细,稍微懂点汇编的应该都能看懂吧,这里就不细说了,接着往下看代码:  

      

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

 

cpu_init_crit:

       

         mov r0, #0

         mcr  p15, 0, r0, c7, c7, 0        /*使指令cache和数据cache无效 */

         mcr  p15, 0, r0, c8, c7, 0         /* 使TLB无效 */

 

                             //  disable MMU stuff and caches   

         mrc  p15, 0, r0, c1, c0, 0                     // 读出c1控制寄存器的值

         bic    r0, r0, #0x00002300                //  clear bits 13, 9:8 (--V- --RS)

         bic    r0, r0, #0x00000087               // 小端对齐,关闭数据cache,关闭错误检测,关闭MMU

         orr    r0, r0, #0x00000002               // 使能错误检测

         orr    r0, r0, #0x00001000                // 使能指令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.

          */

          /* 在把u-boot重定位到RAM前,我们必须先把RAM的时序设置好,内存时序是依板子而定 的,所以这里的初始化应该由我们提供,一般在我们的板子所在目录下有个lowlevel_init.S来负责这件事情*/

         mov ip, lr

         bl      lowlevel_init

         mov lr, ip

         mov pc, lr            

 

#endif                           /* CONFIG_SKIP_LOWLEVEL_INIT */

 

 

 

继续往下看代码:

 

#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文件也就结束了,但我们还有两个函数没去分析,一个是C入口函数start_armboot,另一个就是内存的初始化函数lowlevel_init.S,下面继续逐个分析。

 

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