uboot120启动代码分析Word文档格式.docx

上传人:b****5 文档编号:16634811 上传时间:2022-11-25 格式:DOCX 页数:13 大小:311.42KB
下载 相关 举报
uboot120启动代码分析Word文档格式.docx_第1页
第1页 / 共13页
uboot120启动代码分析Word文档格式.docx_第2页
第2页 / 共13页
uboot120启动代码分析Word文档格式.docx_第3页
第3页 / 共13页
uboot120启动代码分析Word文档格式.docx_第4页
第4页 / 共13页
uboot120启动代码分析Word文档格式.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

uboot120启动代码分析Word文档格式.docx

《uboot120启动代码分析Word文档格式.docx》由会员分享,可在线阅读,更多相关《uboot120启动代码分析Word文档格式.docx(13页珍藏版)》请在冰豆网上搜索。

uboot120启动代码分析Word文档格式.docx

_irq:

.wordirq

_fiq:

.wordfiq

.balignl16,0xdeadbeef

在start.S文件的开头,就定义了一个全局变量_start(地址为0x0),能被其他文件所引用。

中断向量表是放在地址为0x0开始的地方,其中,每个异常中断的排序是事先规定好的,比如第一个必须是reset异常,第二个必须是未定义指令异常。

系统上电时会从地址为0x0地方取指令,而地址0x0处放置的是reset标签,故会直接跳去reset标签处去启动系统了。

这里使用了ldr指令,ldr指令的label,都用一个.word伪操作来定义的。

.word伪操作符分配了一段字内存单元(字对齐),并用伪操作中的值进行初始化,表示把该label的编译地址写入当前地址,label是不占用任何指令的。

当发生异常时,都将执行u-boot-1.2.0/cpu/arm920t/interrupts.c中定义的中断函数,即start.S中要跳转的这些中断子程序的代码,均在u-boot-1.2.0/cpu/arm920t/interrupts.c中定义。

2.2u-boot存储器映射的定义

该段代码段主要是定义了u-boot需要使用的一些映射区的label,比如用户堆区、用户栈区、全局数据结构区等。

如下图所示:

(非常经典的u-boot映射图)

_TEXT_BASE:

.wordTEXT_BASE

.globl_armboot_start

_armboot_start:

.word_start

.globl_bss_start

_bss_start:

.word__bss_start

.globl_bss_end

_bss_end:

.word_end

#ifdefCONFIG_USE_IRQ

/*IRQstackmemory(calculatedatrun-time)中断的堆栈设置*/

.globlIRQ_STACK_START

IRQ_STACK_START:

.word0x0badc0de

/*IRQstackmemory(calculatedatrun-time)*/

.globlFIQ_STACK_START

FIQ_STACK_START:

#endif

代码的解析:

1)声明_TEXT_BASE标号并用TEXT_BASE来初始化(把TEXT_BASE的值存储在当前位置即标号的位置),TEXT_BASE在u-boot-1.2.0/board/smdk2410/config.mk中定义,它的值为0x33F80000。

2)声明_armboot_start为全局变量,并用_start来初始化,_start定义在board/smdk2410/u-boot.lds中,在FLASH中运行时,_start的地址为0x0;

在SDRAM中运行时,_start的地址为0x33F80000。

3)__bss_start和_end是在链接脚本board/smdk2410/u-boot.lds中给出定义的,在编译u-boot的时候产生的,声明_bss_start和_bss_end为全局变量,并用_bss_start和_bss_end来初始化。

4)声明IRQ_STACK_START和FIQ_STACK_START为全局变量,如果宏定义了CONFIG_USE_IRQ在cpu/arm920t/cpu.c中的cpu_init()函数将用到这两个全局变量。

2.3上电后设CPU为SVC模式

reset:

/*

*setthecputoSVC32mode

*设置CPU的状态类型为特权模式,该模式主要用来处理软件中断(SWI)

*/

mrsr0,cpsr

bicr0,r0,#0x1f

orrr0,r0,#0xd3

msrcpsr,r0

CPU复位后,系统会立即被设置为SVC模式,首先用mrs指令把CPSR寄存器中的值传送到通用寄存器r0中,用bic指令清除想修改的bit位,然后用orr指令来保证其他bit位不被改动,以达到修改低5位值的目的,最后用msr指令把r0的值给CPSR寄存器,让ARM进入SVC特权模式。

2.4关闭看门狗

1)首先定义寄存器的基地址:

#ifdefined(CONFIG_S3C2400)

#definepWTCON0x15300000

#defineINTMSK0x14400008/*Interupt-Controllerbaseaddresses*/

#defineCLKDIVN0x14800014/*clockdivisorregister*/

#elifdefined(CONFIG_S3C2410)

#definepWTCON0x53000000/*看门狗定时器控制寄存器的基地址*/

#defineINTMSK0x4A000008/*中断屏蔽寄存器的基地址*/

#defineINTSUBMSK0x4A00001C/*中断次级屏蔽寄存器的基地址*/

#defineCLKDIVN0x4C000014/*时钟分频控制寄存器的基地址*/

2)关闭看门狗

#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)

ldrr0,=pWTCON

movr1,#0x0

strr1,[r0]

由S3C2440的手册可知,系统启动后,看门狗寄存器是被使能的,如果不在预计的时间内“喂狗”,则系统会发生复位,故要关闭看门狗。

上述代码是将数据0写进看门狗定时器控制寄存器(WTCON),即禁止看门狗定时器的复位功能。

2.5禁止所有中断

/*maskallIRQsbysettingallbitsintheINTMR-default

*禁止所有中断

movr1,#0xffffffff

ldrr0,=INTMSK

strr1,[r0]/*屏蔽所有中断源*/

#ifdefined(CONFIG_S3C2410)

ldrr1,=0x3ff

ldrr0,=INTSUBMSK/*屏蔽有关中断源*/

strr1,[r0]

#endif

作用:

屏蔽所有的irq中断源,要屏蔽中断源只要把中断屏蔽寄存器(INTMSK)的所有bit位置1即可;

这个代码貌似有点多余,因为CPU复位时,这个寄存器的值就是0xFFFFFFFF,以防止发生异常中断。

2.6设置时钟分频控制寄存器(CLKDIVN)

/*FCLK:

HCLK:

PCLK=1:

2:

4*/

/*defaultFCLKis120MHz!

ldrr0,=CLKDIVN

movr1,#3

将0x3写入CLKDIVN寄存器,则分频比FCLK:

4

2.7调用cpu_init_crit

#ifndefCONFIG_SKIP_LOWLEVEL_INIT

blcpu_init_crit

如果未定义CONFIG_SKIP_LOWLEVEL_INIT就执行blcpu_init_crit,该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在lr寄存器中,以使得执行完后能够正常返回。

#ifndefCONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

/*flushv4I/Dcaches*/

movr0,#0

mcrp15,0,r0,c7,c7,0

mcrp15,0,r0,c8,c7,0

/*disableMMUstuffandcaches*/

mrcp15,0,r0,c1,c0,0

bicr0,r0,#0x00002300@clearbits13,9:

8(--V---RS)

bicr0,r0,#0x00000087@clearbits7,2:

0(B----CAM)

orrr0,r0,#0x00000002@setbit2(A)Align

orrr0,r0,#0x00001000@setbit12(I)I-Cache

mcrp15,0,r0,c1,c0,0

*beforerelocating,wehavetosetupRAMtiming

*becausememorytimingisboard-dependend,youwill

*findalowlevel_init.Sinyourboarddirectory.

movip,lrbllowlevel_init

movlr,ip

movpc,lr

#endif/*CONFIG_SKIP_LOWLEVEL_INIT*/

代码分析:

1)设置CP15寄存器使失效Icache(指令cache)和Dcache(数据cache),然后禁止MMU和cache。

这样设置的原因主要是:

如果只按复位键而不关掉电源重新上电,就会造成cache中可能残留之前对cache操作的数据,称之为“脏数据”,它会映像我们的调试结果,造成假象。

还有就是在系统初始化阶段,只有一个任务在运行,程序看到的地址都是物理地址,没有必要也不允许使用地址变换,因此最好关闭MMU。

2)调用子程序lowlevel_init,在调用之前把lr寄存器中存储的返回地址保存在scratch寄存器(ip)中,当程序返回时再恢复它。

2.8调用lowlevel_init子程序

这个函数在board/smdk2410/lowlevel_init.S文件中,主要完成对存储控制器的配置,特别对SDRAM的初始化,为后面搬运代码至SDRAM作准备。

.globllowlevel_init//全局变量lowlevel_init被start.s文件调用

lowlevel_init:

/*memorycontrolconfiguration*/

/*maker0relativethecurrentlocationsothatit*/

/*readsSMRDATAoutofFLASHratherthanmemory!

ldrr0,=SMRDATA

ldrr1,_TEXT_BASE

subr0,r0,r1

ldrr1,=BWSCON

addr2,r0,#13*4

0:

ldrr3,[r0],#4

strr3,[r1],#4

cmpr2,r0

bne0b

/*everythingisfinenow*/

.ltorg

SMRDATA:

//变量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))

/*以上是对BANKCON0~BANKCON5的时钟周期进行设置*/

.word((B6_MT<

15)+(B6_Trcd<

2)+(B6_SCAN))

.word((B7_MT<

15)+(B7_Trcd<

2)+(B7_SCAN))

/*以上是对BANKCON6~BANKCON7的设置*/

.word((REFEN<

23)+(TREFMD<

22)+(Trp<

20)+(Trc<

18)+(Tchr<

16)+REFCNT)

.word0x32/*BANKSIZE寄存器的设置*/

.word0x30/*MRSRB6寄存器的设置*/

.word0x30/*MRSRB7寄存器的设置*/

1)使用伪指令ltorg,用于声明一个数据文字池的开始,把SDRAM控制器初始化需要用到的13个寄存器的值先保存至文字池(literalpools)中,然后通过ldr指令来访问这个文字池,以获取寄存器的值赋值到对应的寄存器地址中去。

2)SMRDATA标号表示存放存储控制器13个寄存器所需值的开始地址,SMRDATA标号的地址是u-boot编译时确定下来的内存文字池的地址,在内存中的地址为0x33F8xxxx,用SMRDATA减去_TEXT_BASE的值就是要计算出地址SMRDATA相对于地址0x0的大小,即计算出SMRDATA相对地址;

因为u-boot编译时所有地址都是相对于内存地址TEXT_BASE(0x33F80000)计算出来的,而程序存放的实际地址应该NORFLASH的0x0地址(或者内部4KSRAM的0x0地址),ARM一上电总是从0x0的地址开始运行程序,程序代码还没有搬运到TEXT_BASE(0x33F80000)这个位置,所以不能使用这些label的,只能找对一个相对与0x0的地址,才能得到真正的数据,这样SMRDATA在NORFLASH(或者内部4KSRAM)的地址就可以确定下来了。

3)在计算出NORFLASH(或者内部4KSRAM)的存放地址SMRDATA后加上13*4,然后将结果保存在r2中,13个寄存器,每个寄存器占4个字节。

并读取地址SMRDATA后文字池中的数据初始化BWSCON寄存器,这样就完成了SDRAM的初始化工作,SDRAM就开始工作了,以后就可以正常访问0x30000000开始的SDRAM空间。

2.9代码的搬运工作

#ifndefCONFIG_SKIP_RELOCATE_UBOOT

relocate:

/*relocateU-BoottoRAM*/

adrr0,_start/*r0<

-currentpositionofcode_*/

ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/

cmpr0,r1/*don'

trelocduringdebug*/

beqstack_setup

ldrr2,_armboot_start

ldrr3,_bss_start

subr2,r3,r2/*r2<

-sizeofarmboot*/

addr2,r0,r2/*r2<

-sourceendaddress*/

copy_loop:

ldmiar0!

{r3-r10}/*copyfromsourceaddress[r0]*/

stmiar1!

{r3-r10}/*copytotargetaddress[r1]*/

cmpr0,r2/*untilsourceendaddreee[r2]*/

blecopy_loop

#endif/*CONFIG_SKIP_RELOCATE_UBOOT*/

1)首先取得标号_start的地址存储到r0,当代码在NORFLASH(或内部4KSRAM)中执行时,r0=_start=0x0;

当在SDRAM中执行时,r0=_start=_TEXT_BASE,测试是从FLASH启动,还是从RAM中启动,若在SDRAM中运行时,则不需要搬运代码直接跳转至stack_setup标号处执行,进行堆栈设置。

若u-boot从flash启动时,则搬运代码至SDRAM中,并计算出u-boot镜像大小的结束地址并保存在寄存器r2,循环搬运代码时使用多寄存器寻址方式。

2)搬运代码的原因:

flash的读写速度远小于SDRAM的读写速度,搬运至SDRAM后,可大幅提高程序的运行效率;

如果是nandflash启动模式,那么只有4KB的空间可供用户使用,实际的代码远大于4KB,因此需要重新开辟空间进行代码的运行工作;

还有就是考虑到价钱的原因,(nandflash和norflash每兆价格相差悬殊),把boot代码放在norflash里面(为什么不放在nandflash里面,因为nandflash读需要驱动支持,norflash可以直接读),boot通常很小,只需要占用几十k的空间,所以只需要很小的norflash芯片,这样很便宜,而应用程序通常很大,所以用价格低廉nandflash来储存。

2.10堆栈空间的设置

stack_setup:

ldrr0,_TEXT_BASE/*upper128KiB:

relocateduboot*/

subr0,r0,#CFG_MALLOC_LEN/*mallocarea*/

subr0,r0,#CFG_GBL_DATA_SIZE/*bdinfo*/

#ifdefCONFIG_USE_IRQ

subr0,r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

subsp,r0,#12

这段代码的作用是用来分配各个栈空间,包括分配动态内存区,全局数据区,IRQ和FIQ的栈空间等。

2.11BSS段的清零

clear_bss:

/*BSS段清零*/

ldrr0,_bss_start/*findstartofbsssegment找*/

ldrr1,_bss_end/*stopherebss段的结束地址存放r1中*/

movr2,#0x00000000/*clear把0传送给r2寄存器*/

clbss_l:

strr2,[r0]/*clearloop...将bss段循环清零*/

addr0,r0,#4

cmpr0,r1

bleclbss_l

这段代码先设置了BSS段的起始地址与结束地址,然后循环清除所有的BSS段。

至此,所有的CPU初始化工作(stage1阶段)已经全部结束了。

后面的代码,将通过ldrpc,_start_armboot,进入C程序代码执行,启动C语言程序,同时也是整个u-boot的主函数。

3、stage2:

C代码的分析

3.1为gd_t全局数据结构的指针gd与bd分配空间

gd=(gd_t*)(_armboot_start-CFG_MALLOC_LEN-sizeof(gd_t));

__asm____volatile__("

"

:

:

memory"

);

memset((void*)gd,0,sizeof(gd_t));

gd->

bd=(bd_t*)((char*)gd-sizeof(bd_t));

memset(gd->

bd,0,sizeof(bd_t));

代码解析:

把gd所指的内存区域清零,大小为sizeof(gd_t),初始化数据结构体指针bd_t,即为开发板数据变量bd分配内存空间,计算gd->

bd的起始地址,把bd所指的内存区域清零,大小为sizeof(bd_t)。

代码中的这句话:

目的就是告诉编译器内存被修改过了。

3.2初始化列表函数

for(init_fnc_ptr=init_sequence;

*init_fnc_ptr;

++init_fnc_ptr)

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1