现在的位置: 首页 > 技术文章 > Bootloader > 正文

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

2014年08月06日 Bootloader ⁄ 共 5983字 ⁄ 字号 U-Boot启动第一阶段代码分析 (一)已关闭评论 ⁄ 阅读 2,043 次

预热

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

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

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

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异常向量表,各个异常向量介绍如下:

arm_vector

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

clk

 

接下来请看另一篇:

U-Boot启动第一阶段代码分析 (二) http://www.techbulo.com/1105.html

 

×