uboot

来源:互联网 发布:多进程编程定义 编辑:程序博客网 时间:2024/04/19 08:12
  • CU论坛首页
  • CU博客首页
公告:缅怀C语言&unix之父获奖名单公布
专注于linux开发

mutes.blog.chinaunix.net

专注于过程,将结果交给命运。   
 
首页 |博文目录 | 相册 | 博客圈 | 关于我 | 留言
个人资料
mutes
微博论坛
发纸条打招呼 加关注 加好友
  • 博客访问:41886
  • 博文数量:118
  • 博客积分:4566
  • 博客等级:上校
  • 注册时间:2008-03-01 14:44:33
文章分类
全部博文(118)
硬件调试(6)
ARM学习(0)
bootloader研究(7)
linux内核研究(15)
linux驱动开发(16)
linux应用开发(17)
开源程序移植(2)
SDL开发(1)
QT图形编程学习(0)
mplayer学习(5)
gtk+学习(2)
minigui学习(0)
ucgui学习(1)
ARMS3C2410平台相关(8)
MIPS8634平台相关(1)
PC机linux使用笔记(25)
windows程序开发(11)
应用程序开发(6)
driver(0)
C/C++(6)
项目开发(5)
前辈经验(1)
iphone开发(1)
生活随笔(5)
未分类博文(0)
订阅我的博客
  • 订阅
  • 订阅到鲜果
  • 订阅到抓虾
  • 订阅到Google
字体大小:大 中 小博文
U-Boot启动第一阶段代码分析 (2011-09-24 15:28)
标签: 分析 face 官方下载 style class  分类:bootloader研究

 

u-boot官方下载地址(包含了各个版本及当前最新版本)ftp://ftp.denx.de/pub/u-boot/

这里我选择下载u-boot-1.1.6.tar.bz26402K

之后的移植我再选择最新版本u-boot-2011.06.tar.bz28272K

 

  U-Boot启动第一阶段代码分析

 

1cpu自身的初始化:包括MMU,catch,时钟系统,SDRAM控制系统的初始话。

 

2:重定位:把自己从flash中搬到SDRAM

 

3:分配堆栈空间,设置堆栈指针

 

4:清零BSS数据段

 

5:跳转到第二阶段入口函数。

 

 第一阶段对应的文件是cpu/arm920t/start.Sboard/smdk2140/lowlevel_init.S

根据cpu/arm920t/u-boot.lds中指定的连接方式:

 

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

;指定输出可执行文件是elf格式,32ARM指令,小端

/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/

OUTPUT_ARCH(arm)

;指定输出可执行文件的平台为ARM

ENTRY(_start)

;指定输出可执行文件的起始代码段为_start

SECTIONS

{

      . = 0x00000000; ;从0x0位置开始

 

      . = ALIGN(4); ;代码以4字节对齐

      .text      :  ;指定代码段

      {

        cpu/arm920t/start.o    (.text)   ;代码的第一个代码部分   

        *(.text)      ;其它代码部分

      }

 

      . = ALIGN(4);

      .rodata : { *(.rodata) }    ;指定只读数据段

 

      . = ALIGN(4);

      .data : { *(.data) }     ;指定读\写数据段

 

      . = ALIGN(4);

      .got : { *(.got) }    ;指定got段,got段是u-boot自定义的一个段,非标准段

 

      . = .;

      __u_boot_cmd_start = .;    ;把__u_boot_cmd_start赋值为当前位置,即起始位置

      .u_boot_cmd : { *(.u_boot_cmd) }  ;指定u_boot_cmd段,uboot把所有的uboot命令放在该段

      __u_boot_cmd_end = .;    ;把__u_boot_cmd_end赋值为当前位置,即bss段的开始位置

 

      . = ALIGN(4);

      __bss_start = .;    ;把__bss_start赋值为当前位置,即bss段的开始位置

      .bss : { *(.bss) }   ;指定bss

      _end = .;   ;把_end赋值为当前位置,即bss段的结束位置

}

第一个链接的是cpu/arm920t/start.o,因此u-boot.bin的入口代码在cpu/arm920t/start.o中,其源代码在cpu/arm920t/start.S中。下面我们来分析cpu/arm920t/start.S的执行。

1.硬件设备初始化

1)设置异常向量

      cpu/arm920t/start.S开头有如下的代码:

 

#include <config.h>

#include <version.h>

/*

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

 *

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

 *

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

 */

@设置异常向量表,其中_startGNU汇编的默认入口标签。注意ldr r0,0x1234是把0X1234中的内容写到R0中,ldr r0,=0x1234,是将1234这个值写到R0中,以及ADR是用来加载地址。

.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                 /*  irq中断向量 */

      ldr   pc, _fiq                 /*  fiq中断向量 */

/* 中断向量表入口地址 */

@.wordGUN汇编分配一段字内存单元,下面几句话相当于是C语言中的变量名和变量值。

_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

以上代码设置了ARM异常向量表,各个异常向量介绍如下:

 

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

其中复位异常向量的指令“b reset”决定了U-Boot启动后将自动跳转到标号“reset”处执行。

 

/*

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

 *

 * 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  @board/smdk2410/config.mk中定义为3ff80000..UBOOT映像文件所在地址

.globl _armboot_start

_armboot_start:

      .word _start

 

/*

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

*/

@下面主要在u-boot.lds链接脚本中定义

 

.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

 

2)设置CPU进入SVC模式

/*

 * the actual reset code

系统上电或reset后,cpuPC一般都指向0x0地址,在0x0地址上的指令是

 */

reset:

      /*

       * set the cpu to SVC32 mode

       */

      mrs  r0,cpsr     //CPSR状态寄存器读取,保存到R0

      bic   r0,r0,#0x1f     /*工作模式位清零 */

      orr   r0,r0,#0xd3    /*工作模式位设置为“10011”(管理模式),并将中断禁止位和快中断禁止位置1 */

      msr  cpsr,r0

 

以上代码将CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止位置‘1’,从而屏蔽了IRQFIQ中断。

 

3)设置控制寄存器地址

/* 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) /* s3c2410s3c2440下面4个寄存器地址相同 */

# define pWTCON       0x53000000  /* WATCHDOG控制寄存器地址 */

# define INTMSK        0x4A000008/*中断子屏蔽寄存器地址*/

# define INTSUBMSK  0x4A00001C /* 中断子屏蔽寄存器地址 */

# define CLKDIVN      0x4C000014   /* clock divisor register CLKDIVN寄存器地址,用来设置FCLKHCLKPCLK三者的比例。*/

#endif

      对与s3c2410开发板,以上代码完成了WATCHDOGINTMSKINTSUBMSKCLKDIVN四个寄存器的地址的设置。各个寄存器地址参见数据手册。这里如果移植到2440,将#elif defined(CONFIG_S3C2410)修改为#elif defined(CONFIG_S3C2440)即可,因为s3c2410s3c24404个寄存器地址是相同的。

4)关闭看门狗

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

      ldr     r0, =pWTCON

      mov     r1, #0x0

      str     r1, [r0]  /* 看门狗控制器的最低位为0时,看门狗不输出复位信号 */

以上代码向看门狗控制寄存器写入0,关闭看门狗。否则在U-Boot启动过程中,CPU将不断重启。如果移植到2440,这里一样。

5)屏蔽中断

      /*

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

       */

      mov r1, #0xffffffff  /* 某位被置1则对应的中断被屏蔽 */

      ldr   r0, =INTMSK

      str    r1, [r0]

INTMSK是主中断屏蔽寄存器,每一位对应SRCPND(中断源引脚寄存器)中的一位,表明SRCPND相应位代表的中断请求是否被CPU所处理。

根据数据手册,INTMSK寄存器是一个32位的寄存器,每位对应一个中断,向其中写入0xffffffff就将INTMSK寄存器全部位置一,从而屏蔽对应的中断。

# if defined(CONFIG_S3C2410)

      ldr   r1, =0x3ff

      ldr   r0, =INTSUBMSK

      str    r1, [r0]

# endif

INTSUBMSK每一位对应子中断屏蔽寄存器SUBSRCPND中的一位,表明SUBSRCPND相应位代表的中断请求是否被CPU所处理。

根据数据手册,INTSUBMSK寄存器是一个32位的寄存器,但是只使用了低10位。向其中写入0x3ff就是将INTSUBMSK寄存器全部有效位(低10位)置一,从而屏蔽对应的中断。注意:对于2440,这里写入的是0x7fff,根据2440数据手册,它使用了低15位。向其中写入0x7fff就是将INTSUBMSK寄存器全部有效位(低15位)置一,从而屏蔽对应的中断。

 (6)设置时钟分频控制寄存器。

 /* FCLK:HCLK:PCLK = 1:2:4 * /FCLK为核心提供时钟,HCLKAHBARM920T,内存控制器,中断控制器,LCD控制器,DMA和主USB模块)提供时钟,PCLKAPB(看门狗、IISI2CPWMMMCADCUARTGPIORTCSPI)提供时钟

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

 

7)关闭MMUcache,执行CPU初始话。

      接着往下看:

      /*

       * we do sys-critical inits only at reboot,

       * not when booting from ram!

       */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

      bl    cpu_init_crit @如果没有定义CONFIG_SKIP_LOELEVEL_INIT,则执行cpu_init_crit.

 #endif

cpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-BootRAM中启动则应该注释掉这段代码。后面再对它分析。

@重新定位u-bootSDRAM

这里将整个U-Boot的代码(包括第一、第二阶段)都复制到SDRAM中,这在cpu/arm920t/start.S中实现:

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate:                      /* relocate U-Boot to RAMU-Boot复制到RAM         */

      adr   r0, _start        /* r0 <- current position of code r0 = 当前代码的开始地址 */

@判断U-Boot是否是下载到RAM中运行,若是,则不用再复制到RAM中了,这种情况通常在调试U-Boot时才发生,通过adr指令得到当前代码的地址信息:如果U-boot是从RAM开始运行,则从adr,r0,_start得到的地址信息为 r0=_start=_TEXT_BASE=TEXT_BASE=0x3ff80000;如果U-bootFlash开始运行,即从处理器对应的地址运行,则r0=0x0000,这时将会执行copy_loop标识的那段代码了。

      ldr   r1, _TEXT_BASE         /* r1 =代码段的连接地址test if we run from flash or RAM */

      cmp     r0, r1      /*测试现在是在Flash中还是在RAM中,_start等于_TEXT_BASE说明是在RAM中运行,路过搬移代码*/

      beq     stack_setup   @如果r0等于r1,已经在RAM(这通常是调试时,直接下载到RAM),则不需要复制。

 

      ldr   r2, _armboot_start   @_armboot_start在前面定义,是第一条指令的运行地址即_start的内容写入r2

      ldr   r3, _bss_start       @在连接脚本u-boot.lds中定义,是代码段的结束地址

      sub  r2, r3, r2        /* @计算armboot所占字节大小r2=代码段长度*/

      add  r2, r0, r2        /* r2 <- source end address @armboot结束地址,r2 = NOR Flash上代码段的结束地址*/

 

copy_loop:  @实现从flash中拷贝到_TEXT_BASE0x3ff80000)所在的地址中去

      ldmia      r0!, {r3-r10}         /* copy from source address [r0] ,从地址[r0]处获得数据,即从地址为[r0]NOR Flash中读入8个字的数据  */

      stmia       r1!, {r3-r10}         /* copy to target address [r1] r3r10寄存器的数据复制给地址为[r1] */

      cmp r0, r2                    /* until source end addreee [r2]   判断是否复制完毕*/

      ble   copy_loop  /* 没复制完,则继续 */

#endif    /* CONFIG_SKIP_RELOCATE_UBOOT */

 

      /* Set up the stack        

@设置堆栈                            */

栈的设置灵活性很大,只要让sp寄存器指向一段没有使用的内存即可。

stack_setup:    

      ldr   r0, _TEXT_BASE         /* _TEXT_BASE为代码段的开始地址,值为0x33F80000 upper 128 KiB: relocated uboot*/

      sub  r0, r0, #CFG_MALLOC_LEN      /* malloc area@代码段下面,留出一段内存以实现malloc */

      sub  r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo再留出一段内存,存一些全局参数,这里跳过这个全局数据区 */

#ifdef CONFIG_USE_IRQ

      sub  r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)@为IRQFIQ留出空间,分配IRQFIQ模式的栈

#endif

      sub  sp, r0, #12             /* leave 3 words for abort-stack @最后,留出12字节的内存给abort异常,往下的内存就都是栈了,将当前的地址赋给sp,这样就为内存栈设置好了,之后如果在u-boot中运行程序时需要使用栈的时候就从这里开始。  */

到了这一步,读者可以知道内存的使用情况了,如下图所示(图中与上面的划分稍有不同,这是因为在cpu/arm920t/cpu.c中的cpu_init函数中才真正为IRQFIQ模式划分了栈)

U-boot内存使用情况:

5)跳转到第二阶段代码的C入口点。

在跳转之前,还要清除BSS(初始值为0、无初始值的全局变量、静态变量放在BSS),代码如下:

clear_bss: @清空用户堆区

      ldr   r0, _bss_start         /* find start of bss segmentBSS段的开始地址,它的值在连接脚本u-boot.lds中确定*/

      ldr   r1, _bss_end          /* stop hereBSS段的结束地址,它的值在连接脚本u-boot.lds中确定*/

      mov       r2, #0x00000000           /* clear */r2中写入0

 

clbss_l:str      r2, [r0]           /* clear loop...  BSS段中写入0                 */

      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

@现在,C函数的运行环境已经完全准备好,通过如下命令直接跳转(这之后,程序才在内存中执行),它将调用lib_arm/board.c中的start_armboot函数,这是第二阶段的入口点,这样就到了u-boot的第二阶段了。

 

      ldr   pc, _start_armboot  

_start_armboot:     .word start_armboot

 

 下面分析一下cpu_init_crit到底做了什么:

cpu_init_crit这段代码在U-Boot正常启动时才需要执行,若将U-BootRAM中启动则应该注释掉这段代码。

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

      /*

       * flush v4 I/D caches  使数据cache与指令cache无效

       */

      mov r0, #0

      mcr  p15, 0, r0, c7, c7, 0       /* flush v3/v4 cache c7写入0将使ICacheDCache无效*/

      mcr  p15, 0, r0, c8, c7, 0       /* flush v4 TLB c8写入0将使TLB失效*/

代码中的c0c1c7c8都是ARM920T的协处理器CP15的寄存器。其中c7cache控制寄存器,c8TLB控制寄存器。上面二行代码将0写入c7c8,使CacheTLB内容无效。

 

      /*

       * disable MMU stuff and caches关闭mmucache

   */

@MRC指令的格式为:

@MRC{条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,协处理器操作码2

@MRC指令用于将协处理器寄存器中的数据传送到ARM处理器寄存器中,若协处理器不能成功完成操作,则产生未定义指令异常。其中协处理器操作码1和协处理器操作码2为协处理器将要执行的操作,目的寄存器为ARM处理器的寄存器,源寄存器1和源寄存器2均为协处理器的寄存器。 指令示例: MRC  P33R0C4C56   ;该指令将协处理器P3的寄存器中的数据传送到ARM处理器寄存器中。

       */

      mrc  p15, 0, r0, c1, c0, 0

      bic   r0, r0, #0x00002300      @ clear bits 13, 9:8 (--V- --RS), 1398bit清零(13—异常向量表基地址:0x0 9Disable System Protection, 8Disable ROM Protection

      bic   r0, r0, #0x00000087      @ clear bits 7, 2:0 (B--- -CAM), 7,2,1,0bit清零(7—为0的时候表示小端字节序,2-- Data Cache Disabled1-- Alignment Fault checking disabled0—为0的话MMU disabled)

      orr   r0, r0, #0x00000002      @ set bit 2 (A) Align, bit 1设置为1表示Fault checking enabled

      orr   r0, r0, #0x00001000      @ set bit 12 (I) I-Cache, bit 12设置为1表示使能 I-Cache

      mcr  p15, 0, r0, c1, c0, 0   @保存r0到控制寄存器

 

 

  这几行代码关闭了MMU。这是通过修改CP15c1寄存器来实现的,将c1 M位置零,关闭了MMU。先看CP15c1寄存器的格式(仅列出代码中用到的位):

2.3 CP15c1寄存器格式(部分)

      各个位的意义如下:

 

V : 表示异常向量表所在的位置,0:异常向量在0x000000001:异常向量在 0xFFFF0000

I : 0 :关闭ICaches1:开启ICaches

RS :用来与页表中的描述符一起确定内存的访问权限

B : 0 CPU为小字节序;1 CPU为大字节序

C : 0:关闭DCaches1:开启DCaches

A : 0:数据访问时不进行地址对齐检查;1:数据访问时进行地址对齐检查

M : 0:关闭MMU1:开启MMU

 

     

      /*

       * 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前,先要完成其中内存初始化的工作,lowlevel_init就完成了内存初始化的工作,由于内存初始化是依赖于开发板的,因此lowlevel_init的代码一般放在board下面相应的目录中。对于2410lowlevel_initboard/smdk2410/lowlevel_init.S中。

      mov ip, lr   @保存当前链接寄存器中的值

      bl    lowlevel_init   @主要是初始话存储控制器件即初始化内存,共13个。只需要设置BWSCONBANKCONxx0-5),而BANK6,BANK7SDRAM,除了设置 BWSCONBANKCONxx67),还需要设置其他四个寄存器,而这13个寄存器的地址是连续的,BWSCON是第一个寄存器。

 

      mov lr, ip

      mov pc, lr  @返回执行relocate

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

 

下面分析一下lowlevel_init,代码如下:

#include <config.h>

#include <version.h>

 

 

/* some parameters for the board */

 

/*

 *

 * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S

 *

 * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com>

 *

 */

 

#define BWSCON 0x48000000   /* 13个存储控制器的开始地址 */

 

/* BWSCON */

#define DW8             (0x0)

#define DW16                  (0x1)

#define DW32                  (0x2)

#define WAIT            (0x1<<2)

#define UBLB            (0x1<<3)

 

#define B1_BWSCON        (DW32)

#define B2_BWSCON        (DW16)

#define B3_BWSCON        (DW16 + WAIT + UBLB)

#define B4_BWSCON        (DW16)

#define B5_BWSCON        (DW16)

#define B6_BWSCON        (DW32)

#define B7_BWSCON        (DW32)

 

/* BANK0CON */

#define B0_Tacs                0x0  /*  0clk */

#define B0_Tcos                0x0  /*  0clk */

#define B0_Tacc                0x7  /* 14clk */

#define B0_Tcoh               0x0  /*  0clk */

#define B0_Tah                 0x0  /*  0clk */

#define B0_Tacp               0x0

#define B0_PMC               0x0  /* normal */

 

/* BANK1CON */

#define B1_Tacs                0x0  /*  0clk */

#define B1_Tcos                0x0  /*  0clk */

#define B1_Tacc                0x7  /* 14clk */

#define B1_Tcoh               0x0  /*  0clk */

#define B1_Tah                 0x0  /*  0clk */

#define B1_Tacp               0x0

#define B1_PMC               0x0

 

#define B2_Tacs                0x0

#define B2_Tcos                0x0

#define B2_Tacc                0x7

#define B2_Tcoh               0x0

#define B2_Tah                 0x0

#define B2_Tacp               0x0

#define B2_PMC               0x0

 

#define B3_Tacs                0x0  /*  0clk */

#define B3_Tcos                0x3 /*  4clk */

#define B3_Tacc                0x7  /* 14clk */

#define B3_Tcoh               0x1  /*  1clk */

#define B3_Tah                 0x0  /*  0clk */

#define B3_Tacp               0x3     /* 6clk */

#define B3_PMC               0x0  /* normal */

 

#define B4_Tacs                0x0  /*  0clk */

#define B4_Tcos                0x0  /*  0clk */

#define B4_Tacc                0x7  /* 14clk */

#define B4_Tcoh               0x0  /*  0clk */

#define B4_Tah                 0x0  /*  0clk */

#define B4_Tacp               0x0

#define B4_PMC               0x0  /* normal */

 

#define B5_Tacs                0x0  /*  0clk */

#define B5_Tcos                0x0  /*  0clk */

#define B5_Tacc                0x7  /* 14clk */

#define B5_Tcoh               0x0  /*  0clk */

#define B5_Tah                 0x0  /*  0clk */

#define B5_Tacp               0x0

#define B5_PMC               0x0  /* normal */

 

#define B6_MT                 0x3  /* SDRAM */

#define B6_Trcd              0x1

#define B6_SCAN             0x1  /* 9bit */

 

#define B7_MT                 0x3  /* SDRAM */

#define B7_Trcd               0x1  /* 3clk */

#define B7_SCAN             0x1  /* 9bit */

 

/* REFRESH parameter */

#define REFEN                0x1  /* Refresh enable */

#define TREFMD              0x0  /* CBR(CAS before RAS)/Auto refresh */

#define Trp                0x0  /* 2clk */

#define Trc                0x3  /* 7clk */

#define Tchr              0x2  /* 3clk */

#define REFCNT              1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */

/**************************************/

 

_TEXT_BASE:

      .word      TEXT_BASE

 

.globl lowlevel_init

lowlevel_init:

      /* memory control configuration */

      /* make r0 relative the current location so that it */

      /* reads SMRDATA out of FLASH rather than memory ! */

      ldr     r0, =SMRDATA

      ldr   r1, _TEXT_BASE

      sub  r0, r0, r1    /* SMRDATA _TEXT_BASE就是13个寄存器的偏移地址 */

      ldr   r1, =BWSCON      /* Bus Width Status Controller */

      add     r2, r0, #13*4

0:

      ldr     r3, [r0], #4   /*13个寄存器的值逐一赋值给对应的寄存器*/

      str     r3, [r1], #4

      cmp     r2, r0

      bne     0b

 

      /* everything is fine now */

      mov pc, lr

 

      .ltorg

/* the literal pools origin */

/* 下面是13个寄存器的值 */

SMRDATA:

   .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))

   .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))

   .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))

   .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))

   .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))

   .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))

   .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))

   .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))

   .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))

   .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)

   .word 0x32

   .word 0x30

.word 0x30

 

lowlevel_init初始化了13个寄存器来实现RAM时钟的初始化。lowlevel_init函数对于U-BootNAND FlashNOR Flash启动的情况都是有效的。

board/samsung/mini2440/lowlevel_init.o将被链接到cpu/arm920t/start.o后面,因此board/samsung/mini2440/lowlevel_init.o也在U-Boot的前4KB的代码中。

      U-Boot.lds链接脚本有如下代码:

      .text :

 

      {

 

                    cpu/arm920t/start.o    (.text)

 

               board/samsung/mini2440/lowlevel_init.o (.text)

 

                board/samsung/mini2440/nand_read.o (.text)

 

             

 

      }

      U-BootNAND Flash启动时,lowlevel_init.o将自动被读取到CPU内部4KB的内部RAM中。因此lowlevel_init函数代码将从CPU内部RAM中复制寄存器的值到相应的寄存器中。

 

      对于U-BootNOR Flash启动的情况,由于U-Boot连接时确定的地址是U-Boot在内存中的地址,而此时U-Boot还在NOR Flash中,因此还需要在NOR Flash中读取数据到RAM中。

 

      由于NOR Flash的开始地址是0,而U-Boot的加载到内存的起始地址是TEXT_BASESMRDATA标号在Flash的地址就是SMRDATATEXT_BASE

 

      综上所述,lowlevel_init的作用就是将SMRDATA开始的13个值复制给开始地址[BWSCON]13个寄存器,从而完成了存储控制器的设置。

 

Start.S文件之后是

@.macro伪操作符标识宏定义的开始,.endm标识宏定义的结束。二者包含的一段代码,称为宏定义体,这样在程序中就可通过宏指令多次调用该代码段。格式:

.macro macroname {parameter{,parameter}...}

 ...

 .endm

宏的参数可直接使用斜线“/字符”来引用,如下“/reg”所示。

 

@以下就是各种中断的处理。

/****************异常处理程序 *******************/

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

……………………………..

@略过     

 

我的更多文章
  • c/c++写的小程序 (2011-11-12 09:58:17)
  • 自动调整linux系统时间和时区与Internet时间同步 (2011-11-08 09:07:04)
  • CRC计算方法与C实现 (2011-10-27 10:25:35)
  • 循环冗余校验码的单片机及 CPLD实现 (2011-10-27 10:23:39)
  • CRC校验源码分析 (2011-10-27 10:21:44)
  • s3c2440(2410) USB HOST不稳定的原因及解决方法 (2011-10-27 09:33:58)
分享到:新浪微博QQ空间开心网豆瓣人人网twitterfb
0
   
阅读(87)┊ 评论 (0)┊收藏(0)┊举报┊打印
前一篇:Bootloader的概述及相关资料
[发评论]评论 重要提示:警惕虚假中奖信息!
    亲,您还没有登录,请[登录]或[注册]后再进行评论
    原创粉丝点击