欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

S3C2440启动代码中应用程序执行环境的初始化

程序员文章站 2022-06-08 21:33:59
...

S3C2440启动代码中应用程序执行环境的初始化

一、基础知识

我们编写的源文件(.c 或.s)经过ARM 编译器的编译生成ELF 格式的目标文件(后缀名为.o),目标文件经过ARM 连接器连接以后生成ELF 格式的映像文件(后缀名为.axf),此时的映像文件还包含一些调试信息,我们还需要通过fromelf 工具将其转换成适合在ROM 或RAM 中运行的二进制代码(后缀名为.bin),这时生成的二进制映像文件就可以被烧写入目标板的ROM 或FLASH 中,当目标板上电后可以通过各种方式在ROM 或RAM 中运行。
一个可执行程序的映像文件由一个或多个域组成,域分为两种:一种是映像文件在存储器中存放的地址,称为加载域;另一种是映像文件运行时的地址,称为运行域。每个域由一个或3 个输出段组成,每个输出段则由一个或多个输入段组成。输入段包含程序代码、已经初始化的数据、未经初始化的存储区、被初始化为0 的存储区,输入段据此可分为三种属性:RO(只读,包括代码和常量)、RW(可读可写,包括已经初始化的全局变量和静态变量)、ZI(未初始化的变量,需初始化为0), 连接器根据属性将输入段分组,组成不同的输出段。一个输出段是有具有相同属性的输入段组成的,输出段的属性与其中输入段的属性相同,因而输出段也分为三种。域由不同属性的输出段组成,输出段在域中的排列顺序为RO 输出段排在最前,然后是RW 输出段,RW 输出段和RO 输出段可以不连续,最后是ZI 输出段,ZI 输出段是紧接着RW 输出段的(加载域只包含RO、RW 输出段,原因见后述)。
可执行镜像一开始一般是存储在系统的ROM 或FLASH 中,RO 段是只读的,在运行的时候我们不能改变它,所以RO 段在运行的时候可以驻留在ROM 或FLASH 中,也可以拷贝到运行速度更快的RAM 中;RW 段在运行的时候,我们需要对其读写,在运行前这一段必须被拷贝至RAM 中;ZI 段为未初始化的全局变量段,只需要在程序运行之前建立ZI 并将其所在区域全部清零即可,因此镜像装载域不必包含ZI 输出段,但在运行域需要包含ZI,并且ZI 必须处于RAM。
通过以上说明,我们知道如果某个镜像只有RO 段的话,程序可以不必拷贝至RAM,但是如果程序包含RW 段的话,RW 段是必需要拷贝至RAM 中的,如果有必要的话还需在RAM 中创建ZI 段,并将其清零。为保证程序的正确执行,而进行必要的数据拷贝和清零,就是应用程序执行环境的初始化。

二、S3C2440启动的基本原理

Nand Flash启动

当S3C2440 开发板采用的是Nand Flash 启动,镜像一开始是存储在Nand Flash 中,而Nand Flash只能作为存储程序和数据之用,无法在其中运行程序,所以S3C2440 开发板启动代码中应用环境初始化这一步和上述步骤稍有不同。S3C2440 镜像文件加载和运行时的地址映射关系如下图所示:

S3C2440启动代码中应用程序执行环境的初始化
S3C2440 没有上电之前映像文件存储在Nand Flash 中,Nand Flash 有专门的控制器控制,不占用存储器BANK。当开发板上电时,Nand Flash 的前4K 被复制到S3C2440 芯片内部的一块容量为4K 的SRAM(被称为“Steppingstone”),然后这块SRAM 被映射到地址0x00000000 处,程序从此处开始运行。因为Nand Flash 中不能运行程序,所以在这4K 的代码中必须包含一段代码将Nand Flash 中的程序拷贝至S3C2440 的SDRAM 中(0x30000000 开始)。应用环境初始化应该包含这段代码。
Nand Flash 中的映像文件被拷贝至从0x30000000 开始的SDRAM,这时候映像文件还没有真正被执行,此时是加载状态,加载域如上图所示,包括所有RO 属性的输出段和RW 属性的输出段,ZI 属性的输出段此时还不存在。在映像文件运行时,会生成3 个运行域,如上图所示,RO 和RW 属性的运行域的起始地址和加载时是相同的,所以在应用程序执行环境初始化中不需要对其进行拷贝,ZI 运行域则需要在映像开始被执行前建立并被初始化为0,所以应用程序执行环境初始化中也要包含这类代码。(注意:RO 和RW 属性的运行域的起始地址和加载时是相同的,即拷贝到SDRAM后就不用再移动了。ADS中设置的RO Base和RW Base决定了程序的链接地址

Nor Flash启动

当S3C2440采用Nor Flash启动时,代码可以在上面直接运行。但为了运行的效率,还是把程序拷贝到SDRRAM中运行。加载时地址关系和运行时地址关系和Nand Flash的基本相似。Nand Flash启动时,会将RO段和RW段同时拷贝到SDRAM中,然后再建立ZI段。从Nor Flash启动时是先拷贝RO段,然后再拷贝RW段,最后建立ZI段。

三、相关启动代码分析

;一个arm 程序是由R0,RW,ZI 三个段组成。其中R0 为代码段,RW 是已经初始化的全局变量,ZI 是未
;初始化的全局变量,启动代码要将RO段和RW段复制到RAM 中并将ZI 段清零。编译器使用下列变量
;来记录各段的起始地址和结束地址。这些标号的值是通过编译器的设定来确定的如ADS中对ro-base 和
;rw-base 的设定。
IMPORT  |Image$RO$Base|	; Base of ROM code
IMPORT  |Image$RO$Limit|  ; End of ROM code (=start of ROM data)
IMPORT  |Image$RW$Base|   ; Base of RAM to initialise
IMPORT  |Image$ZI$Base|   ; Base and limit of area
IMPORT  |Image$ZI$Limit|  ; to zero initialise


;===========================================================
	
	ldr	r0, =BWSCON
	ldr	r0, [r0]
	ands	r0, r0, #6	;通过判断OM[1:0] != 0, 得知是NOR FLash boot
	bne	copy_proc_beg	;不用读取 nand flash
	adr	r0, ResetEntry	;OM[1:0] == 0, 从NAND FLash 启动
	cmp	r0, #0		;再比较入口是否为0地址处,如果不是则用了仿真器
	bne	copy_proc_beg	;用仿真器的情况也不要用 nand flash启动
	;nop
;===========================================================
nand_boot_beg  ;这一段代码完成从NAND读代码到RAM
	[ {TRUE}
		bl RdNF2SDRAM
	]


	ldr	pc, =copy_proc_beg  ;此时的PC已经在0x30000000以后,是copy_proc_beg连接时的地址
;这个标号下面的代码完成的功能就是把nor flash 的内容拷贝到ram 当中。
;===========================================================
copy_proc_beg
	adr	r0, ResetEntry 		 ;装载地址,ResetEntry值->r0
	ldr	r2, BaseOfROM 		 ;BaseOfROM值
	cmp	r0, r2  			 ;比较RO,R2
	ldreq	r0, TopOfROM 	 ;如果相等的话(说明在内存中运行),TopOfROM->r0   当从Nand Flash中启动时r0=r2,当从Nor Flash启动时则不相等
	beq	InitRam        			 ;同时跳到InitRam	
;下面这个是针对代码在NOR FLASH时的拷贝方法
;功能为把从ResetEntry起,TopOfROM-BaseOfROM大小的数据拷到BaseOfROM
;TopOfROM和BaseOfROM为|Image$RO$Limit|和|Image$RO$Base|
;|Image$RO$Limit|和|Image$RO$Base|由连接器生成为生成的代码的代码段运行时的起启和终止地址
;BaseOfBSS和BaseOfZero为|Image$RW$Base|和|Image$ZI$Base|
;|Image$RW$Base|和|Image$ZI$Base|也是由连接器生成,两者之间就是初始化数据的存放地放
	ldr r3, TopOfROM
0	
	ldmia	r0!, {r4-r7}
	stmia	r2!, {r4-r7}
	cmp	r2, r3
	bcc	%B0
	
	sub	r2, r2, r3  ;这两句代码是修正字非对齐的情况,因为是按4个字节拷贝的,但RO段大小不一定是4个字节对齐的
	sub	r0, r0, r2				
		
InitRam	
	ldr	r2, BaseOfBSS
	ldr	r3, BaseOfZero	
0
	cmp	r2, r3
	ldrcc	r1, [r0], #4
	strcc	r1, [r2], #4
	bcc	%B0	;这一段是对ResetEntry 里面定义好的数据拷贝到RW 段。


	mov	r0,	#0
	ldr	r3,	EndOfBSS
1	
	cmp	r2,	r3
	strcc	r0, [r2], #4
	bcc	%B1    ;初始化ZI段
	
	ldr	pc, =%F2		;goto compiler address
2
	
;	[ CLKDIV_VAL>1 		; means Fclk:Hclk is not 1:1.
;	bl	MMU_SetAsyncBusMode
;	|
;	bl MMU_SetFastBusMode	; default value.
;	]


    [ :LNOT:THUMBCODE
 		bl	Main	;不要用main()因为main()是ADS默认入口,编译器会添加其他代码
 		b	.      ;跳转到Main不成功则挂起
    ]


    [ THUMBCODE	 ;for start-up code for Thumb mode
 		orr	lr,pc,#1
 		bx	lr
 		CODE16
 		bl	Main	;Do not use main() because ......
 		b	.
		CODE32
    ]


BaseOfROM	DCD	|Image$RO$Base|
TopOfROM	DCD	|Image$RO$Limit|
BaseOfBSS	DCD	|Image$RW$Base|
BaseOfZero	DCD	|Image$ZI$Base|
EndOfBSS	DCD	|Image$ZI$Limit|