加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

四极管:Uboot运行分析(三)

发布时间:2020-12-15 06:19:35 所属栏目:百科 来源:网络整理
导读:??????? 接下来就是start.S了。。本文源码来源于u-boot-1.1.6。 ??????? 源码的分析参考网上的诸多博客的整理。如http://home.eeworld.com.cn/my/space.php?uid=135723do=blogid=25548。http://www.51hei.com/mcu/1132.html等。 ????? 都说bootloader分为两

??????? 接下来就是start.S了。。本文源码来源于u-boot-1.1.6。

??????? 源码的分析参考网上的诸多博客的整理。如http://home.eeworld.com.cn/my/space.php?uid=135723&do=blog&id=25548。http://www.51hei.com/mcu/1132.html等。


????? 都说bootloader分为两个阶段。。四极管也来看看这两个阶段都做了什么事情。

一、阶段1

阶段1通常包括以下步骤(以执行的先后顺序)

??? 1、一些基本硬件初始化工作

??? 2、为加载映像2准备RAM空间(RAM足够的情况下可以省略)

??? 3、把映像2拷贝到RAM空间

??? 4、跳转到映像2的入口点(一般是C入口点)

一般阶段1都会有如下具体工作:

??? 1、定义ARM各个运行模式

??? 2 、定义ARM各个运行模式堆栈的大小

??? 3、根据处理器工作状态确定编译方式

? ? 4、初始化异常中断向量表

??? 5、禁止看门狗

??? 6、屏蔽中断

??? 7、屏蔽子中断

??? 8、设置时钟,初始化使能SDRAM

??? 9、为各操作模式设置堆栈指针,将系统模式置为监管模式(SVC)并设置SP

?? 10、将映像2拷贝到SDRAM的指定处。。。通过跳转进入阶段2

现在看源码分析:

 
 

Uboot?start.S分析

四极管?2012-3-8

/*

?*??cpu/s3c24xx/start.S

?*

?*??U-Boot?-?Startup?Code?for?S3C24XX

?*

?*??Copyright?(c)?2006,??Samsung?Electronics

?*??All?rights?reserved.

?*

?*??Based?on?cpu/arm926ejs/start.S

?*

?*?This?program?is?free?software;?you?can?redistribute?it?and/or?modify

?*?it?under?the?terms?of?the?GNU?General?Public?License?version?2?as

?*?published?by?the?Free?Software?Foundation.

?*

?*?$Id:?start.S,v?1.8?2008/05/23?00:26:34?eyryu?Exp?$

?*/

/*

?*??mod?by?sc.suh@samsung.com

?*

?*??Our?U-Boot?Memory?Map

?*??????????????????????????????????????(offset)

?*???????--------------------------?????0x04000000

?*???????|?????Stack?????(512KB)??|

?*???????--------------------------?????0x03f80000

?*???????|?????Heap???????(1MB)???|

?*???????--------------------------?????0x03e80000

?*???????|?????IRQ?Stack??(4KB)???|?<------------------------?if?exists

?*???????--------------------------?????0x03e70000

?*???????|?????FIQ?Stack??(4KB)???|?<------------------------?if?exists

?*???????--------------------------?????0x03e60000

?*???????|?????GBL???????(128B)???|

?*???????--------------------------?????0x03exxxxx

?*???????|?????BSS?and?Reserved???|

?*???????--------------------------?????0x03e40000

?*???????|?????U-Boot????(256KB)??|

?*???????--------------------------?????0x03e00000

?*/

#include?<config.h>

#include?<version.h>

#ifdef?CONFIG_ENABLE_MMU

#include?<asm/proc/domain.h>

#endif

#ifndef?CONFIG_ENABLE_MMU

#ifndef?CFG_PHY_UBOOT_BASE

#define?CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE

#endif

#endif

#define?no_compile?0

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

?*

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

?*

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

.globl?_start

_start:??/*系统复位位置,各个异常向量对应的跳转代码,ARM中规定了异常向量的地址*/

b reset?????//复位?0x0

ldr pc,?_undefined_instruction?//未定义的指令异常?0x4

ldr pc,?_software_interrupt??//软件中断异常

ldr pc,?_prefetch_abort//预取指令0xC

ldr pc,?_data_abort//数据0x10

ldr pc,?_not_used?//未使用0x14

ldr pc,?_irq//慢速中断异常0x18

ldr pc,?_fiq//快速中断异常0x1C

/*.word伪操作作用于分配一段字内单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long于.int作用与//相同*/

//以下.word?的含义如下:

.Word为GNU?ARM汇编特有的伪操作,为分配一段字节内容单元(分配的单元为字对齐的),可以使用.word把标识符作为常量使用,如_irq:.word?irq即把fiq存入内存变量_irq中,也即是把fiq放到地址_irq中。

_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?/*定义fiq变量到_fiq地址里面去,_fiq地址就是上面对应的,比如_fiq是0x0000?001C*/

.balignl?16,0xdeadbeef

/*对于这句话的理解内容就比较多了。。。。在Nunca?Muer?to?的空间里面有详细的对比分析。。为了以后难找,我还是把那段话敲出来。。。

先要弄明白.balignl的意思,这个其实应该算是一个伪操作符,伪操作符的意思就是机器码里,并没有一个汇编指令与其对应,是编译器来实现其功能的,.balignl是.balign的变体,.balign的意思是,在以当前地址开始,地址计数器必须是以第一个参数为整数倍的地址为尾,在前面记录一个字节长度的信息,信息内容为第二个参数。

.balignl??8,0xde

它的意思就是在以当前地址开始,在地址为8的倍数的位置的前面填入一个字节内容为0xde的内容。如果当前地址正好是8的倍数,则没有东西被写入到内存。

关于.balignl?16,0xdeadbeef这句,功能说明没有错,就是想在某个位置插入0xdeadbeef这个特殊的内存值。错就错在我对这个16的理解上面,16就是16个字节,这是没有错的,但是这个16的由来,并不是我所理解的至少16个字节,才能在任何情况下保证插入这个特殊的内存值。我在博客留言中回答,举了个例子pc=0x0000007地址,偏移量为8个字节时,这个时候就不够用4个字节的内容了,以此推导出的,至少有16个字节才能保证这个特殊的内存值的插入也是完全错误的。

举个反例,如果给那位网友的解释,那就算有16个字节的偏移量,那如果PC地址为0x000000F时,也只需要一个字符的空间,那这个0xdeadbeef的值是不够的,以此类推,就算这个值为任意一值,按我之前的解释的错误逻辑,也都有不满足的情况,呵呵,所以我之前的推论有误,我现在把16这个值的由来进行说明。

ARM920T处理器核心,支持32与16位两种指令长度,16位的指令叫做thumb指令集,由于我使用的是32位指令集,所有一切都是以32位指令集进行说明。

既然是32位指令集,所以一条指令就占32位,即4个字节,所以在调试器中,地址显示也是4字节一跳的,所以PC的值,也是4字节一跳的,并不存在可能PC的值为0x00000007的情况。

这个地方填16个偏移量,是因为

.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//占四个字节的内存

ldr pc,?_fiq//占四个字节的内存

占了4x8?=?32?字节内存。

_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//占四个字节的内存

占了4X7=28个字节内存。

所以在这个.balignl?16,0xdeadbeef指令之前,一共占了4X15=60个字节的内存,所以本代码的作者当时就简单的在15这个数上,加了一个1,即16,把前面的指针移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。

我不知道这个地方时作者的一个错误呢,歪打正着呢,还是怎么回事,其实这个偏移量的值有好多种情况,如果说最小值的话,那么也可以写成.balignl?8,0xdeadbeef,也同样可以达到相同的目的,因为60不是8的倍数,但是64是8的倍数(60到64之前都不是8的倍数,同样也不是16的倍数,所以写8和16都可行)如果写8,也正好插入到64前面,也即60这个内存起始地址,如果更大一点儿呢,那么填32也可以达到同样的效果,即.balignl?32,0xdeadbeef,道理同上。当然,不能为4,因为PC值在任何时候,都是4的倍数(64是4的倍数),只要不为0就为4的倍数,呵呵,这个值不行,如果用了这个值,0xdeadbeef永远也插不进去。

*/

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

?*

?*?Startup?Code?(reset?vector)

?*

?*?do?important?init?only?if?we?don't?start?from?memory!//做一些初始化,如果我们不是SDRAM启动的话

?*?setup?Memory?and?board?specific?bits?prior?to?relocation.

?*?relocate?armboot?to?ram?//重定位代码到SDRAM中

?*?setup?stack//设置堆栈空间

?*?*******************************************************************/

/*保存变量的数据区*/

_TEXT_BASE:

.word TEXT_BASE??//在TEXT_BASE定义在boardsmdk2416、config.mk文件中这段话表示,用户告诉编译器编译地址的起始(或者说可以理解是为加载的地址,这样就能做到编译地址和运行地址的统一了)

/*

?*?Below?variable?is?very?important?because?we?use?MMU?in?U-Boot.

?*?Without?it,?we?cannot?run?code?correctly?before?MMU?is?ON.

?*?by?scsuh.

?*/

_TEXT_PHY_BASE:

.word CFG_PHY_UBOOT_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

/*上面这些代码,主要保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者其他的使用。还有一些变量的值是通过连接脚本得到的,比如TEXT_BASE位于/u-boot-1.1.6/board/xxx(开发板目录名称)/config.mk文件里,_bss_start、_end位于/u-boot-1.1.6/board/xxx(开发板目录名称)/u-boot.lds文件里,具体值是由编译器算出来的。

*/

/*

?*?the?actual?reset?code??//系统复位代码。系统一上电,就跳转到这里运行

?*/

reset:

/*

?*?set?the?cpu?to?SVC32?mode?//svc为操作系统保护模式

?*/

mrs r0,cpsr??//取得当前程序状态寄存器cpsr到r0

bic r0,r0,#0x1f?//这里是位清除指令,把中断全部清除,只置位模式控制位。为中断提供服务的通常是0S,设备驱动程序的责任,因此在Bootloader的执行过程中可以不必响应任何中断。

orr r0,#0xd3?//计算为超级保护模式

msr cpsr,r0//设置cpsr为超级保护模式

/*以上设置的作用:

设置CPU运行在SVC32模式,ARM共有7种模式:

用户模式(usr):arm处理器正常的程序执行状态

快速中断模式(fiq):用于高速数据传输或通道处理

超级保护模式(svc):操作系统使用的保护模式

数据访问终止模式(abt):当数据或指令预终止时进入该模式,可用于虚拟存储及存储保护

系统模式(sys):运行具有特殊的操作系统任务

未定义指令中止模式(uud):当未定义的指令执行时进入该模式。可用于支持硬件协处理器的软件仿真。

通过设置ARM的CPSR寄存器,让CPU运行在操作系统保护模式,为后面进行其他操作做好准备工作。

*/

#if?defined(CONFIG_S3C2443)?||defined(CONFIG_S3C2450)?||?defined(CONFIG_S3C2416)

/*

?*?Retention?IO?power?will?be?turen?off?whel?sleep?mode,

?*?but,?when?wakeup?process?starts,?User?should?write?'1'

?*?produce?power?on?retention?IO.?PM?check

?*/

ldr r0,?=0x4c00006c

ldr r1,?=0x4c000064

ldr r2,?[r0]

tst? r2,?#0x8

ldreq r2,?[r1]

orreq r2,?r2,?#0x10000??/*?(1<<16)?*/

streq r2,?[r1]

#endif

/*

?*?we?do?sys-critical?inits?only?at?reboot,

?*?not?when?booting?from?ram!

?*/

/*

1、关闭MMU和CPU内部指令/数据(I/D)cache

2、设置CPU的速度和时钟频率

3、RAM初始化

*/

cpu_init_crit:

/*

?*?flush?v4?I/D?caches

?*/

mov r0,?#0

mcr p15,?0,?r0,?c7,?0 /*?flush?v3/v4?cache?*/

mcr p15,?c8,?0 /*?flush?v4?TLB?*/

/*

MCR指令用于将ARM处理器寄存器中的数据传输到协处理器寄存器中,格式为:

MCR?协处理器编码?,协处理器操作码?1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。

其中协处理器操作码1和协处理器操作码2为协处理器将要执行的操作,源寄存器为ARM处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄存器。

*/

/*

?*?disable?MMU?stuff?and?caches禁止MMU和chache

?*/

mrc p15,?c1,?c0,?0?//先把c1和c0寄存器的各位置0(r0=0)

bic r0,?#0x00002300 /*?clear?bits?13,?9:8?(--V-?--RS)?*/

bic r0,?#0x00000087 /*?clear?bits?7,?2:0?(B---?-CAM)?*/

orr r0,?#0x00000002 /*?set?bit?2?(A)?Align?*/

orr r0,?#0x00001000 /*?set?bit?12?(I)?I-Cache?*/

mcr p15,?0

/*

??*?led?GPH12?on

?*/

#ifdef?no_comiple

test1:

mov r1,#0x56000000

add r1,r1,#0x20 //?set?offset?address

ldr r2,=(1<<6)

str???? r2,[r1,#0x0] //?set?GPC3?as?output

ldr? r2,=(0<<6)

str r2,#0x8] //?disable?pull-up/down

ldr r2,=(1<<3)

str r2,#0x4] //?output?low?level

#endif?

#ifdef?CONFIG_ONENAND

/*

?*?With?this?check,?we?can?change?boot?sequence?as?we?want?in?run-time.?*?XXX:?must?modify?to?use?"swp"?not?"ldr?and?str".

?*/

check_onenand_boot:

mov r0,?#0x1e400 /*?check?OneNAND?via?start?buffer?reg?*/

ldr r1,?=0xfffffffe /*?very?tweaky?and?may?occur?bugs?*/

ldr r2,?=0x00000f02

ldr r3,?[r0]

str r1,?[r0]

ldr r1,?[r0]

str r3,?[r0]

cmp r1,?r2

bne 1024f

/*?OneNAND?is?detected?as?boot?device

?*?So,?load?<0x400?~?0xc00>?to?DataRam0

?*/

fill_onenand_dr:

mov r2,?#0

ldr r3,?=0x0001e200

ldr r5,?=0x0002 /*?0x400?~?0x800?*/

ldr r6,?=0x0001e400

ldr r7,?=0x0802 /*?fill?1KB?in?DR0?*/

100: strh r2,?[r3] /*?block?=?0,?data?buffer?=?0?*/

strh r2,?[r3,?#0x2] /*?block?=?0,?data?buffer?=?0?*/

strh r5,?#0xe] /*?set?page,?sector?addr?*/

strh r7,?[r6] /*?set?start?buffer?and?count?*/

strh r2,?[r6,?#0x82] /*?reset?int?status?*/

strh r2,?#0x40] /*?send?LOAD?command?*/

1: ldrh r8,?#0x82] /*?check?int?status?*/

tst r8,?#(1<<15)

beq 1b

tst r5,?#4;

ldr r5,?=0x0004 /*?0x800?~?0xc00?*/

add r7,?r7,?#0x0200 /*?fill?next?1KB?0x0a02?*/

beq 100b

b 1024f

.ltorg /*?without?it,?variables?may?go?too?far.?*/

1024:

#endif

/*

?*?Go?setup?Memory?and?board?specific?bits?prior?to?relocation.

?*/

bl lowlevel_init /*?go?setup?pll,mux,memory?*/

/*进入lowlevel_init,这里主要是初始化存储寄存器,S3C2416的是Bank0-Bank6,比如位宽等,这个要根据自己的板子来进行响应的配置,比如网卡放在几个Bank,位宽多少,SDRAM放在那里,多大等。位于board/smdk2416/lowlevel_init.S:用于完成芯片存储器的初始化,执行完成后返回*/

#ifdef?CONFIG_S3C2442

#ifdef?CONFIG_PM

@?Check?if?this?is?a?wake-up?from?sleep

ldr?r1,?PMST_ADDR

ldr?r0,?[r1]

tst?r0,?#0x8?@?PMST_SMR

bne?WakeupStart

#endif

#endif

/*?when?we?already?run?in?ram,?we?don't?need?to?relocate?U-Boot.

?*?and?actually,?memory?controller?must?be?configured?before?U-Boot

?*?is?running?in?ram.

?*/

check_boot_device:

ldr r0,?=0xff000fff

bic r1,?pc,?r0 /*?r0?<-?current?base?addr?of?code?*/

ldr r2,?_TEXT_BASE /*?r1?<-?original?base?addr?in?ram?*/

bic r2,?r0 /*?r0?<-?current?base?addr?of?code?*/

cmp?????r1,?r2??????????????????/*?compare?r0,?r1??????????????????*/

beq?????after_copy /*?r0?==?r1?then?skip?flash?copy???*/

#ifdef?CONFIG_BOOT_MOVINAND

ldr sp,?_TEXT_PHY_BASE

bl movi_bl2_copy

b after_copy

#endif

/*?check?boot?device?is?nand?or?nor?*/

ldr r0,?=0x00000000

ldr r3,?=0xfffffffe

str r1,?[r0]

ldr r2,?r2

#if?defined(CONFIG_S3C2450)?||?defined(CONFIG_S3C2416)

/*?Now?iROM?on?2450?is?not?support?eFuse?*/

#if?1

b nand_copy

#else

beq nand_copy

#endif

#else

beq nand_copy

#endif

#ifdef?CONFIG_ONENAND

ldr r3,?[r0,?#0x400]

ldr r1,?#0x400]

ldr r2,?#0x400]

str r3,?#0x400]

cmp r1,?r2

beq jump_to_onenand

#endif

/*?nor?copy?*/

relocate: /*?relocate?U-Boot?to?RAM ????*/

adr r0,?_start /*?r0?<-?current?position?of?code???*/

//取得_start的地址到r0。如果是在flash中运行,则_start的值就是0,如果是在RAM中运行,则_start=_TEXT_BASE=TEXT_BASE=0X33F80000。

(_TEXT_BASE在board/smdk2416/config.mk中定义)

@ ldr r1,?_TEXT_BASE//把_TEXT_BASE地址处的值_TEXT_BASE,也就是BOOT在RAM中运行地址移到r1。测试时在flash还是在ARM

ldr r1,?_TEXT_PHY_BASE /*?r1?<-?destination????????????????*/

ldr r2,?_armboot_start?/*把_armboot_start?地址处的值也就是_start绝对地址(也就是在内存中的地址,这个绝对地址是在Link的时候确定的,如0x81008000)移到r2*/

ldr r3,?_bss_start?/*把_bss_start地址处的值也就是_bss_start绝对地址(也即在内存中的地址,这个绝对地址是在Link的时候确定的)移到r3*/

sub r2,?r3,?r2 /*?r2?<-?size?of?armboot*//*计算引导代码大小并存放到r2*/

add r2,?r2 /*?r2?<-?source?end?address*//*计算引导代码最后相对地址并存入R2*/

copy_loop:??//重定位代码

ldmia r0!,?{r3-r10} /*?copy?from?source?address?[r0]????*/

/*从源地址[r0]读取32个字节到寄存器,并更新r0*/

stmia r1!,?{r3-r10} /*?copy?to???target?address?[r1]????*/

/*拷贝寄存器R3-R10的32个字节值保存到[r1]指明的地址,并更新R1的值*/

cmp r0,?r2 /*?until?source?end?addreee?[r2]????*/

/*循环拷贝,直到把所有的引导代码移植到内存*/

ble copy_loop

b after_copy

nand_copy:

mov r0,?#0x1000

bl copy_from_nand

#ifdef?CONFIG_ONENAND

b after_copy

jump_to_onenand:

bl temp_copy_onenand

onenand_copy:

mov r0,?#0x400

bl copy_from_nand

#endif

after_copy:

#ifdef?CONFIG_ENABLE_MMU

enable_mmu:

/*?enable?domain?access?*/

ldr r5,?=0x0000ffff

mcr p15,?r5,?c3,?0 @?load?domain?access?register

/*?Set?the?TTB?register?*/

ldr r0,?_mmu_table_base

ldr r1,?=CFG_PHY_UBOOT_BASE

ldr r2,?=0xfff00000

bic r0,?r2

orr r1,?r1

mcr p15,?r1,?c2,?0

/*?Enable?the?MMU?*/

mmu_on:

mrc p15,?0

orr r0,?#1 /*?Set?CR_M?to?enable?MMU?*/

mcr p15,?0

nop

nop

nop

nop

#endif

/*?Set?up?the?stack*/

//初始化堆栈,为第二阶段的C语言做准备

stack_setup:

#ifdef?CONFIG_MEMORY_UPPER_CODE

ldr sp,?=(CFG_UBOOT_BASE?+?CFG_UBOOT_SIZE?-?0xc)

#else

ldr r0,?_TEXT_BASE /*?upper?128?KiB:?relocated?uboot???*/

sub r0,?#CFG_MALLOC_LEN /*?malloc?area??????????????????????*/

sub r0,?#CFG_GBL_DATA_SIZE?/*?bdinfo????????????????????????*/

#ifdef?CONFIG_USE_IRQ

sub r0,?#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp,?#12 /*?leave?3?words?for?abort-stack????*/

#endif

//数据段_bss_start??à_bss_end的初始化

clear_bss:

ldr r0,?_bss_start /*?find?start?of?bss?segment*/

/*把_bss_start地址处存储的绝对地址移到r0*/

ldr r1,?_bss_end /*?stop?here*/

/*把_bss_end?的地址处存储的绝对地址移到R1*/

mov? r2,?#0x00000000 /*?clear*/

//初始化直接使用汉字,一次就是64个位

clbss_l:str r2,?[r0] /*?clear?loop...*/

/*str指令用于从源寄存器中r2将一个32位的字数据传送到寄存器[r0]*/

add r0,?#4

cmp r0,?r1

ble clbss_l?/*小于或者等于跳转*/

ldr pc,?_start_armboot??//跳转到stage2

/*

Stage1?到此结束,然后开始stage2。也就是跳转到u-boot-1.1.6/board.c?àstart_armboot中运行。把_start_armboot地址处的值也就是_start_armboot绝对地址移植到PC。

*/

_start_armboot:

.word?start_armboot

#ifdef?CONFIG_ENABLE_MMU

_mmu_table_base:

.word?mmu_table

#endif

#ifdef?CONFIG_ONENAND

temp_copy_onenand:

adr r0,?_start /*?r0?<-?current?position?of?code???*/

ldr r1,?_TEXT_PHY_BASE /*?test?if?we?run?from?flash?or?RAM?*/

ldr r2,?=0xbff

1: ldmia r0!,?{r3-r10} /*?copy?from?source?address?[r0]????*/

stmia r1!,?{r3-r10} /*?copy?to???target?address?[r1]????*/

cmp r0,?r2 /*?until?source?end?addreee?[r2]????*/

ble 1b

adr r0,?onenand_copy

ldr r1,?_TEXT_PHY_BASE

add r0,?r1

mov pc,?r0

.ltorg

#endif

/*

?*?copy?U-Boot?to?SDRAM?and?jump?to?ram?(from?NAND?or?OneNAND)

?*?r0:?size?to?be?compared

?*/

.globl?copy_from_nand

copy_from_nand:

mov r10,?lr /*?save?return?address?*/

mov r9,?r0

/*?get?ready?to?call?C?functions?*/

ldr sp,?_TEXT_PHY_BASE /*?setup?temp?stack?pointer?*/

sub sp,?sp,?#12

mov fp,?#0 /*?no?previous?frame,?so?fp=0?*/

#ifdef?CONFIG_ONENAND

cmp r9,?#0x1000

bne 2f

bl copy_uboot_to_ram

b 3f

2: bl onenand_cp

#else

mov r9,?#0x1000

bl copy_uboot_to_ram

#endif

3: tst? r0,?#0x0

bne copy_failed

#if?defined(CONFIG_S3C2450)?||?defined(CONFIG_S3C2416)

/*?Confirm?Booting?Status?NAND?Booting?or?iROM?NAND*/

ldr r6,?=0x40008000

ldr r7,?=0x24564236

swp r8,?[r6]

swp r5,?r8,?[r6]

cmp r7,?r5

/*?If?compare?value?is?same?between?r7?and?r5,?Booting?Device?is?iROM?*/

beq 444f

mov r0,?#0 /*?NAND?Booting?*/

b 555f

444:

mov r0,?#0x40000000 /*?iROM?booting?*/

#else

mov r0,?#0

#endif

555:

ldr r1,?_TEXT_PHY_BASE

1: ldr r3,?[r0],?#4

ldr r4,?[r1],?#4

teq r3,?r4

bne compare_failed /*?not?matched?*/

subs r9,?r9,?#4

bne 1b

4: mov lr,?r10 /*?all?is?OK?*/

mov pc,?lr

copy_failed:

nop /*?copy?from?nand?failed?*/

b copy_failed

compare_failed:

nop /*?compare?failed?*/

b compare_failed

/*

?*?we?assume?that?cache?operation?is?done?before.?(eg.?cleanup_before_linux())

?*?actually,?we?don't?need?to?do?anything?about?cache?if?not?use?d-cache?in?U-Boot

?*?So,?in?this?function?we?clean?only?MMU.?by?scsuh

?*

?*?void theLastJump(void?*kernel,?int?arch_num,?uint?boot_params);

?*/

#ifdef?CONFIG_ENABLE_MMU

.globl?theLastJump

theLastJump:

mov r9,?r0

ldr r3,?=0xfff00000

ldr r4,?_TEXT_PHY_BASE

adr r5,?phy_last_jump

bic r5,?r3

orr r5,?r4

mov pc,?r5

phy_last_jump:

/*

?*?disable?MMU?stuff

?*/

mrc p15,?0

bic r0,?0

mcr p15,?0 /*?flush?v4?TLB?*/

mov r0,?#0

mov pc,?r9

#endif

//以下是一些中断的定义和处理

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

?*

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

@?carve?out?a?frame?on?current?user?stack

sub sp,?#S_FRAME_SIZE

stmia sp,?{r0?-?r12} @?Save?user?registers?(now?in?svc?mode)?r0-r12

ldr r2,?_armboot_start

sub r2,?#(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub r2,?#(CFG_GBL_DATA_SIZE+8)??@?set?base?2?words?into?abort?stack

@?get?values?for?"aborted"?pc?and?cpsr?(into?parm?regs)

ldmia r2,?{r2?-?r3}

add r0,?#S_FRAME_SIZE @?grab?pointer?to?old?stack

add r5,?#S_SP

mov r1,?lr

stmia r5,?{r0?-?r3} @?save?sp_SVC,?lr_SVC,?cpsr

mov r0,?sp @?save?current?stack?into?r0?(param?register)

.endm

.macro irq_save_user_regs

sub sp,?{r0?-?r12} @?Calling?r0-r12

@?!!!!?R8?NEEDS?to?be?saved?!!!!?a?reserved?stack?spot?would?be?good.

add r8,?#S_PC

stmdb r8,?{sp,?lr}^ @?Calling?SP,?LR

str lr,?[r8,?#0] @?Save?calling?PC

mrs r6,?spsr

str r6,?#4] @?Save?CPSR

str r0,?#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,?#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,?#(CFG_GBL_DATA_SIZE+8)?@?reserved?a?couple?spots?in?abort?stack

str lr,?[r13] @?save?caller?lr?in?position?0?of?saved?stack

mrs lr,?spsr @?get?the?spsr

str lr,?[r13,?#4] @?save?spsr?in?position?1?of?saved?stack

mov r13,?#MODE_SVC @?prepare?SVC-Mode

@?msr spsr_c,?r13

msr spsr,?r13 @?switch?modes,?make?sure?moves?will?execute

mov lr,?pc @?capture?return?pc

movs pc,?lr @?jump?to?next?instruction?&?switch?modes.

.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

#ifdef?CONFIG_PM

.align?4

PMCTL1_ADDR: .long?0x56000080

PMST_ADDR: .long?0x4C000068

PMSR0_ADDR: .long?0x560000B8

GPBCON: .long?0x56000010

GPBDAT: .long?0x56000014

GPFCON_reg: .long?0x56000050

GPFDAT_reg: .long?0x56000054

.align?5

sleep_setting:

@?prepare?the?SDRAM?self-refresh?mode

ldr?r0,?=0x48000024 @?REFRESH?Register

ldr?r1,?[r0]

orr?r1,#(1<<22)?@?self-refresh?bit?set

@?prepare?MISCCR[19:17]=111b?to?make?SDRAM?signals(SCLK0,SCLK1,SCKE)?protected

ldr?r2,=0x56000080 @?MISCCR?Register

ldr?r3,[r2]

orr?r3,r3,#((1<<17)|(1<<18)|(1<<19))

@?prepare?the?Power_Off?mode?bit?in?CLKCON?Register

ldr?r4,=0x4c00000c @?CLKCON?Register

ldr?r5,=(1<<3)

b???set_sdram_refresh

.align?5

set_sdram_refresh:

str?r1,[r0]?????????????@?SDRAM?self-refresh?enable

@?wait?until?SDRAM?into?self-refresh

mov?r1,?#64

1:??subs????r1,?#1

bne?1b

@?set?the?MISCCR?&?CLKCON?register?for?power?off

str?r3,[r2]

str?r5,[r4]

nop?????????????????@?waiting?for?power?off

nop

nop

b???.

.align?5

WakeupStart:

@?Clear?sleep?reset?bit

ldr?r0,?PMST_ADDR

mov?r1,?#(1<<1)?@?PMST_SMR

str?r1,?[r0]

@?Release?the?SDRAM?signal?protections

ldr?r0,?PMCTL1_ADDR

ldr?r1,?[r0]

bic?r1,?#((1<<17)|(1<<18)|(1<<19))??@?(SCLKE?|?SCLK1?|?SCLK0)

str?r1,?[r0]

@?Max1718_Set();??@for?case?135?i.e?300MHz?operation

@ GPBCON?=?(GPBCON?&?~((3?<<?20)?|?(3?<<?16)?|?(3?<<?14)))?|?(1?<<?20)?|?(1?<<?16)?|?(1?<<?14);

ldr?r1,?GPBCON

ldr?r0,?[r1]

bic?r0,?#(?(3?<<?20)?|?(3?<<?16)?|?(3?<<?14)?)

orr?r0,?#(?(1?<<?20)?|?(1?<<?16)?|?(1?<<?14)?)

str?r0,?[r1]

//?GPB7,?8,?10?:?Output

@ GPFCON?=?(GPFCON?&?~(0xff?<<?8))?|?(0x55?<<?8); //?GPF4~7:?Output?,?shared?with?LED4~7

ldr?r1,?GPFCON_reg

ldr?r0,?#(?(0xff?<<?8)?)

orr?r0,?#(?(0x55?<<?8)?)

str?r0,?[r1]

@ GPBDAT?=?(GPBDAT?&?~(1?<<?7))?|?(0?<<?7);???//D4

ldr?r1,?GPBDAT

ldr?r0,?#(?(1?<<?7)?)

orr?r0,?#(?(0?<<?7)?)

str?r0,?[r1]

@ GPFDAT?=?(GPFDAT?&?~(0xf?<<?4))?|?(1?<<?7)?|?(0?<<?6)?|?(0?<<?5)?|?(0?<<?4);????//D3~0

ldr?r1,?GPFDAT_reg

ldr?r0,?#(?(0xf?<<?4)?)

orr?r0,?#(?(1?<<?7)?|?(0?<<?6)?|?(0?<<?5)?|?(0?<<?4)?) @D3~0

str?r0,?[r1]

@?Go...

ldr?r0,?PMSR0_ADDR??@?read?a?return?address

ldr?r1,?[r0]

mov?pc,?r1

nop

nop

1:??b???1b??????@?infinite?loop

#endif

对于UBOOT的relocate代码的深入理解。可以看看http://www.51hei.com/mcu/1131.html的解析。。我也把他记下来,以便以后自己复习。

relocate:??? /* relocate U-Boot to RAM???? */ ?adr r0,_start? /* r0 <- current position of code?? */ ?ldr r1,_TEXT_BASE? /* test if we run from flash or RAM */ ?cmp???? r0,r1????????????????? /* don't reloc during debug???????? */ ?beq???? stack_setup

???? 最初看到这个代码的时候,发现功能还是很简单的,就是判断uboot是放在哪里的,flash? or SDRAM?如果放在SDRAM中,就不需要再把uboot代码从flash中搬移到SDRAM中,直接跳到stack_setup;如果是放在flash里的话,则要把代码从flash中搬移到指定的SDRAM地址(TEXT_BASE)中。细看之下,又发现了点问题:它是怎么知道uboot到底放在哪呢;又要把uboot放到SDRAM的什么地址去呢,也即TEXT_BASE是多少。

??? 先说TEXT_BASE吧。TEXT_BASE在功能上是指示uboot将要SDRAM中存放的起始地址。(理解这个很重要)在ubootcpus3c44b0start.S中有如下声明和定义:_TEXT_BASE:。word TEXT_BASE 而在ubootboardB2config.mk文件中有如下赋值:TEXT_BASE = 0x0c100000。在基于daveB2板子的uboot是把uboot放在SDRAM中的0x0c100000处的。(

点击浏览下一页

个人暂时认为这个TEXT_BASE应该是可以修改的,比如TEXT_BASE=0x0c100004)再说这个_start:当uboot在flash中运行的时候,_start是程序的开始,也即地址0。而当uboot在SDRAM的时候,这个_start应该是多少呢??经过反复想,

点击浏览下一页

反复想之后,才发现,这个_start就应该是TEXT_BASE。

 由于_start是整个uboot的开头处,所以_start在uboot中的偏移地址_start_offset=0,这个无疑义。当uboot在flash中的时候,_start=0x00000000很好理解:flash映射起始地址为0x00000000。uboot放在flash当中的话,uboot起始地址就应该为0x00000000,而_start在uboot中的偏移地址为0,所以_start的绝对物理地址就应该是0x00000000。当uboot处于SDRAM中的时候,_start=??那么它为什么又会等于TEXT_BASE=0x0c1000000呢???原因就在于,我们要把(注意:是将要把,打算把)uboot搬到TEXT_BASE=0x0c100000(这个位置属于SDRAM的映射)处。那么uboot的绝对地址就应该是TEXT_BASE,而_start在uboot中的偏移地址是0,所以_start的绝对地址就是TEXT_BASE+0=TEXT_BASE。在ldr r1,_TEXT_BASE执行之后,r1=TEXT_BASE的;而adr r0,_start执行之后呢??adr指令是基于PC的相对寻址,执行之后r0=PC+_star_offset=PC。如果uboot放在SDRAM中的话,那么_start的绝对地址是TEXT_BASE,也即PC=TEXT_BASE。

 至此,才明白了是如何判断是否要进行代码搬移的。

?? 总结:开始一直以为,uboot在SDRAM中的话,其开始地址应该是SDRAM的映射开始地址,即0x0c000000,也即_start的绝对地址应该是0x0c000000。后来才发现,uboot放在SDRAM中的位置是由程序控制的,即放在TEXT_BASE处。这才明白上面那几行代码是怎么回事了~~~

 话外音::突然间想到---TEXT_BASE是uboot在SDRAM的开始处,所以在SDRAM中的时候_start=TEXT_BASE。只有这样才能判断正确~~

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读