Chinaunix首页 | 论坛 | 博客
  • 博客访问: 114179
  • 博文数量: 15
  • 博客积分: 1423
  • 博客等级: 上尉
  • 技术积分: 140
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-15 18:40
文章分类

全部博文(15)

文章存档

2011年(1)

2010年(9)

2009年(5)

分类: 嵌入式

2010-01-11 00:06:39

因为其他的事情,关于u-boot的学习搁浅了有几周了,想要了解u-boot.很好的移植u-boot到一块新的板子上,有必要了解启动代码,从最开始的start.s学习起。

/*

 *  armboot - Startup Code for ARM920 CPU-core

 *

 *  Copyright (c) 2001 Marius Grer <mag@sysgo.de>

 *  Copyright (c) 2002 Alex Zke <azu@sysgo.de>

 *  Copyright (c) 2002 Gary Jennejohn <gj@denx.de>

 *

 * 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

 */

 

 

#include <config.h>

//包含头文件,这个文件在目录../u-boot-1.1.6/include/config.h

//其实这个头文件里只包含有一句:”#include

//这个头文件的创建要回到mkconfig里后面才知道,在这里有

// 85  echo “#include”>>config.h

//这个头文件就是对硬地址的定义

#include <version.h>

//版本信息

 

/*

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

 *

 * Jump vector table as in table 3.1 in [1]

 *跳转中断向量表

 *

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

 */

 

 

.globl _start                              @.global  全局声明标志,这样声明的标号将可以被外部使用。(armasm中的EXPORT相同)

_start:     b       reset                    @跳转到复位函数reset,这个函数在下面定义,这里使用b是不带返回的跳转,即不将PC值保存到LR寄存器里

                                        @这里_start的链接地并不是0x00000000而是TEXT_BASE(这个在../board/smdk2410/config.mk,但它却是程序

                                        @的入口位置

       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

 

 

/*

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

 *

 * Startup Code (reset vector)

 *

 * do important init only if we don't start from memory!

 * relocate armboot to ram

 * setup stack

 * jump to second stage

 *

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

 */

 

_TEXT_BASE:

       .word      TEXT_BASE

 

.globl _armboot_start

_armboot_start:

       .word _start

 

/*

 * These are defined in the board-specific linker script.

 */

.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

 */

 

reset:

       /*

        * set the cpu to SVC32 mode

        */

       mrs  r0,cpsr             @设置程序状态寄存器,设置为ARM指令,超级用户状态

       bic   r0,r0,#0x1f         @先将相应位清零

       orr   r0,r0,#0xd3         @再置位相应的位

       msr  cpsr,r0             @将值写回CPSR

 

/* turn off the watchdog */     @关闭看门狗

#if defined(CONFIG_S3C2400)

# define pWTCON        0x15300000

# define INTMSK         0x14400008    /* Interupt-Controller base addresses */

# define CLKDIVN       0x14800014    /* clock divisor register */

#elif defined(CONFIG_S3C2410)

# define pWTCON        0x53000000

# define INTMSK         0x4A000008   /* Interupt-Controller base addresses */

# define INTSUBMSK   0x4A00001C

# define CLKDIVN       0x4C000014   /* clock divisor register */

#endif

 

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

       ldr     r0, =pWTCON    @将寄存器pWTCON的地装载至r0寄存器,以便赋值

       mov     r1, #0x0        @将立即数0x0装载到r1

       str     r1, [r0]          @r1内的数值存入到pWTCON中,即修改了pWTCON内的值

 

//对于特殊寄存器的操作,据根手册得知需要用指令LDR/STR进行操作,或者使用整型指针

 

       /*

        * mask all IRQs by setting all bits in the INTMR – default   @屏蔽所有的中断,通过设置INTMSR寄存器里的所有位

        */

       mov r1, #0xffffffff                     

       ldr   r0, =INTMSK                      @在这里我一直有个疑问,为什么反汇编后,这里会变成ldr  r0,  [pc, #864]

       str    r1, [r0]

# if defined(CONFIG_S3C2410)

       ldr   r1, =0x3ff           @如果是S3C2410还得屏蔽中断服务

       ldr   r0, =INTSUBMSK    @在这里我也疑问,为什么反汇编后,这里会变成ldr  r0,  [pc, #860]

       str    r1, [r0]

# endif

 

       /* FCLK:HCLK:PCLK = 1:2:4 */

       /* default FCLK is 120 MHz ! */

       ldr  r0, =CLKDIVN       @设置时钟,设置分频比,想修改时钟频率就可以在这里修改  反汇编后,这里会变成ldr  r0,  [pc, #856]

       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          @如果配置了底层初始化就跳转至 子函数处初始化cpu_init_crit,这里使用的是带返回的跳转指令BL

                                                 @跳转同时还将当前PC值保存到LR,以便程序返回

#endif

 

#ifndef CONFIG_SKIP_RELOCATE_UBOOT     @如果配置了重定位项就执行下面程序

relocate:                       /* relocate U-Boot to RAM       */  @U-boot代码搬运至RAM

       adr   r0, _start        /* r0 <- current position of code   */  @读取当前程序起始位置地址,adr是将基于当前pc注意还是在flash)地址加载到r0

       ldr   r1, _TEXT_BASE         /* test if we run from flash or RAM */  @要搬运的基地,在这里是内存的基地址

       cmp     r0, r1                  /* don't reloc during debug */   @比较确定是否已在内存中运行

       beq     stack_setup                                         @如果是调试则跳到stack_setup中执行,建立堆栈

 

       ldr   r2, _armboot_start               @u-boot要搬运的代码的起始地址装载到r2

       ldr   r3, _bss_start                   @bss段起始地址

       sub  r2, r3, r2        /* r2 <- size of armboot            */  @计算出u-boot要搬运代码的大小

       add  r2, r0, r2        /* r2 <- source end address         */   @代码的结束地址

 

copy_loop:

       ldmia      r0!, {r3-r10}         /* copy from source address [r0]    */ @先从flash中拷贝出来,这里r0保存的是要拷贝的代码地址

       stmia       r1!, {r3-r10}         /* copy to   target address [r1]    */  @再放到内存中,这里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                      */  @向下为动态内存分配空间,即为malloc分配空间

       sub  r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */    @bd结构分配空间

#ifdef CONFIG_USE_IRQ

       sub  r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)   

#endif

       sub  sp, r0, #12             /* leave 3 words for abort-stack    */ @abort异常预留12字节的空间,并将当前的地址赋给sp,这样就为内存栈

@设置好了,之后如果在u-boot中运行程序时需要使用栈的时候就从这里开始。

 

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]

 

       /*

        * mask all IRQs by setting all bits in the INTMR - default

        */

       mov r1, #0xffffffff

       ldr   r0, =INTMR

       str    r1, [r0]

 

       /* FCLK:HCLK:PCLK = 1:2:4 */

       /* default FCLK is 120 MHz ! */

       ldr   r0, =CLKDIVN

       mov r1, #3

       str    r1, [r0]

       /* END stuff after relocation */

#endif

 

       ldr   pc, _start_armboot   @第一次跳入bank6的内存执行

 

_start_armboot:      .word start_armboot  @跳转到_start_armboot,也就是函数 start_armboot

@此函数存放在u-boot-2009.03/lib_arm/board.c,这样就到了u-boot的第二阶段了

 

 

/*

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

 *

 * 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

       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

 

       /*

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

        */

       @在重定位之前,我们必须对RAM时序进行初始化,因存储时序是与开发板相关的,所以你可以在你的

       @开发板目录下可以找到lowlevel_init.S这个文件(这是移植要修改的文件之一)

       mov ip, lr           @将保存在lr内的值写入ip,即将上次跳转函数时的程序指针保存,以便在子函数再跳转

       bl    lowlevel_init     @跳转至函数lowlevel_init当前的程序指针保存入lr,以便返回

       mov lr, ip           @ip的值赋给lr,就是恢复到跳转入此子函数时保存的程序指针

       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

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