(针对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