u-boot第一阶段start.S分析

(针对s3c2440,从nand flash启动的情况,u-boot-2010.6)

一、u-boot第一阶段任务

对于s3c2440来说,开机的时候芯片自动把nand_flash的前4k拷贝到芯片内部自带的4k的SRAM中,但是这个容量对于u-boot来说还是不够的。

u-boot第一阶段的任务:

             关看门狗---------------------禁止自动复位

             关中断------------------------禁止中断打扰

             初始化时钟------------------为外设提供时钟

             初始化SDRAM-------------代码将在SDARM运行

             初始化NAND Flash-------操作NAND Flash读取u-boot代码

             u-boot代码重定位----------将u-boot代码从NAND Flash拷贝到SDRAM中

做完这些后,uboot就跳转到第二阶段了

二、u-boot汇编指令

u-boot的第一阶段使用汇编编写,下面对比较重要的汇编知识介绍下。

(1)运行地址:程序实际运行的地址

     绝对地址:程序编译连接后的地址,每条指令,每个标号都有一个绝对地址

     绝对跳转:从指令A跳转到标号B    PC=标号B绝对地址

     相对跳转:从指令A跳转到标号B    PC=当前PC+(B绝对地址-A绝对地址)


期望:指令的运行地址==绝对地址,但是当u-boot第一阶段代码重定位完成前,运行地址和绝对地址不一致。这个时候就不能使用绝对跳转,只能使用相对跳转。

  

(2).global  _start

说明_start这个标号是个全局的标号,外部文件可调用

(3)_start  .word  start

_start地址上存储的内容是start

(4) b   reset

      指令A

      .......

     reset:

             .........

PC值=当前PC值+(reset绝对地址-b指令绝对地址),相对寻址

(5)  bl   reset

       指令A

       .........

       reset:

          ...........

       mov  pc ,lr

b和bl的区别就是 bl跳转时会将bl的下一条指令的地址保存在lr寄存器中,当子程序的末尾可以通过mov pc lr来实现返回到bl指令的下一条的执行。对于bl指令,指令A能够被执行,对于b指令,指令A不会被执行。

(5)ldr  r0,_start  

    将标号_start地址内的值放到r0中,是相对寻址,读内存数据到寄存器

    ldr  r0,=_start 

    将标号_start绝对地址放到r0中

(6)adr r0,_start

     计算标号_start运行地址:   指令adr的运行地址+(_start绝对地址-adr绝对地址)

(7)str r0  [r1]

   将r0内的值保存在地址为r1的内存单元中,写寄存器数据到内存

(8)mov r0   r1

   将r1的值写到r0中,寄存器之间传输数据

三、start.S代码解析

(简化版)
#include <common.h>
#include <config.h>
.globl _start 
_start: b start_code //开始代码跳转到标号start_code处
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
_TEXT_BASE: .word TEXT_BASE//定义变量_TEXT_BASE,该值在board/samsung/smdk2410/config.mk指定
.globl _armboot_start
	_armboot_start: .word _start//定义变量_armboot_start 
//以下变量在arch/arm/cpu/arm920t/u-boot.lds中定义
.globl _bss_start
	_bss_start: .word __bss_start
.globl _bss_end
	_bss_end: .word _end
//----------------------------起始代码------------------------------------
        //cpu进入到管理模式,设置相应状态字
start_code:
	mrs r0, cpsr
	bic r0, r0, #0x1f
	orr r0, r0, #0xd3
	msr cpsr, r0

#  define pWTCON	0x53000000
#  define INTMSK	0x4A000008	
#  define INTSUBMSK	0x4A00001C
#  define CLKDIVN	0x4C000014
        //关看门狗
	ldr	r0, =pWTCON
	mov	r1, #0x0
	str	r1, [r0]

	//屏蔽中断
	mov	r1, #0xffffffff
	ldr	r0, =INTMSK
	str	r1, [r0]

	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]


//初始化SDRAM
#ifndef CONFIG_SKIP_LOWLEVEL_INIT 
	bl cpu_init_crit 
#endif
//设置堆栈,为后面的c语言函数的调用做准备
//在include/configs/smdk2410.h中定义了start.S使用的宏 
stack_setup:
	ldr r0, _TEXT_BASE
	sub r0, r0, #CONFIG_SYS_MALLOC_LEN
	sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE
#ifdef CONFIG_USE_IRQ 
	sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif 
	sub sp, r0, #12 

//时钟的初始化,c语言实现,用户自定义
	bl clock_init

//代码重定位
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:
	adr r0, _start         //得到_start的运行地址
	ldr r1, _TEXT_BASE     //得到_start的绝对地址
	cmp r0, r1             //计算运行地址和绝对地址是否一致
	beq clear_bss          //相同的话就去清bss段,否则重定位
	ldr r2, _armboot_start //uboot代码开始处的绝对地址
	ldr r3, _bss_start     //uboot代码结束处的绝对地址
	sub r2, r3, r2         //计算uboot代码大小 
//CopyCode2Ram c语言实现,用户自定义 
	bl CopyCode2Ram        //从nand flash读取代码到sdram中,重定位后运行地址和绝对地址重合
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */

clear_bss:
	ldr r0, _bss_start //bss段开始地址
	ldr r1, _bss_end //bss段结束地址
	mov r2, #0x00000000clbss_l:str r2, [r0] //循环清0
	add r0, r0, #4
	cmp r0, r1
        ble clear_bss

ldr pc, _start_armboot//跳转到uboot第二阶段,绝对跳转,这是在外接sdram中运行的第一个程序函数
_start_armboot: .word start_armboot

参考资料:《u-boot-2010.6移植到tq2440》http://download.csdn.net/detail/hongwazi_2010/5776649

你可能感兴趣的:(u-boot,TQ2440)