tiny4412裸机程序——代码重定位

在前面介绍exynos4412芯片启动过程时,我们知道:一上电,exynos4412首先执行固化在iROM中的代码,iROM首先设置程序运行环境(比如关看门狗、关中断、关MMU、设置栈、设置栈、启动PLL等),然后根据OM引脚确定启动设备(NAND Flash/SD卡/其他),把BL1从里面读出存入iRAM的0x02021400地址处,然后开始启动BL1;BL1从SD卡适当的位置读入14K字节的数据,存在iRAM地址0x02023400处,所以BL2不能大于(14K–4) 字节,这里引出了为什么写这一节的原因:如果我们的程序很大,大于14K怎么办?

运行地址和链接地址:

运行地址是程序当前所处的地址,即程序在运行时,所处的当前地址。
链接地址是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以在链接脚本中指定程序的链接地址。

对于tiny4412而言,前面我们已经说过:启动时BL1只会从sd等启动设备中拷贝14K的代码到iRAM中,那么当我们的程序超过14K怎么办?那就需要我们在前14K的代码中将整个程序完完整整地拷贝到LPDDR等其他更大存储空间,然后再跳转到LPDDR中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。

本章中讲解学习如何重定位,但是并不会涉如何使用到LPDDR,而是简单地将代码从iRAM的0x02023400处拷贝到iRAM的0x02026400处,然后跳转到0x02026400处继续运行我们的代码。

程序文件介绍:

1.start.S文件内容介绍:

.text
.global _start
_start:
	//关闭看门狗;关于看门狗的设置可以查看Spec 1357页
	ldr r0, =0x10060000		//将0x10060000数字保存到R0寄存器中
	mov r1, #0x0			//将0x0数字保存到R1寄存器中
	str r1, [r0]			//将R1寄存器中的数字(0)保存到R0寄存器数字表示的地址中

	//重定位整个代码到0x0202_6400地址处;这个地址位于iRAM里面
	adr r0, _start			//将_start标号(程序的开始地址)位于iRAM里的实际地址保存到R0寄存器中;也是开始拷贝程序的地址

	ldr r1, =_start			//获取链接地址;也就是想将程序运行的地址;将拷贝的程序从这个地址开始保存

	ldr r2, =bss_start		//将链接地址中的bss_start标识地址保存到R1寄存器中;也是拷贝程序结束的地址;R1-R2的大小也就是要
							//重定位代码的大小

	cmp r1, r2				//比较两个地址是否相等,如果相等在直接去清除bss段即可;
	beq clear_bss			//跳转到清零bss处

reload_loop:
	ldr r3, [r0], #4		//将R0数字表示地址处的数据加载到R3寄存器中;并将R0+4
	str r3, [r1], #4		//将R3中的数据保存到R1寄存器数字表示的地址中,并将R1+4
	cmp r1, r2
	bne reload_loop			//循环拷贝

clear_bss:		//将bss段清零
	ldr r0, =bss_start		//将bss段的开始地址保存到R0寄存器
	ldr r1, =bss_end		//将bss段的结束地址保存到R1寄存器
	mov r2 ,#0x0			//将0数字保存到R2寄存器中
	cmp r0, r1				//如果相等则表示bss清零完毕,跳转执行点亮LED
	beq run_address

clear_loop:
	str r2, [r0], #4		//将0保存到R0寄存器地址,并将R0+4
	cmp r0, r1
	bne	clear_loop			//如果不相等则表示没有清零完成

run_address:				//点亮LED灯
	ldr sp, =0x02027400		//设置栈
	ldr pc, =main			//使用绝对跳转指令
	//bl main
halt_loop:					//死循环
	b halt_loop

程序中已经做了详细的注释,这里就不再详细介绍。

2.main.c文件详细介绍:

//定义两个宏,方便操作使用到的寄存器
#define GPM4_CON (*(volatile int *)0x110002E0)
#define GPM4_DAT (*(volatile int *)0x110002E4)

int main()
{
	//设置GPM4_0引脚为输出
	GPM4_CON &= ~0xFF;			//GPM4CON寄存器的低8位清零
	GPM4_CON |= 0x11;			//GPM4CON寄存器的bit0/4置1,设置为输出引脚

	//设置GPM4_0引脚为低电平
	GPM4_DAT &= ~0x3;			//GPM4DAT寄存器bit0/1清零,输出低电平
	return 0;
}

程序中已经做了详细的介绍,这里不再介绍。

3.链接脚本:

SECTIONS {
	. = 0x02026400;		/* 链接地址 */
	. = ALIGN(4);
	.text : 
	{ 
		*(.text) 
	}
	
	. = ALIGN(4);
	.rodata : 
	{
		*(.rodata)
	}
	
	. = ALIGN(4);
	.data : 
	{ 
		*(.data) 
	}
	
	. = ALIGN(4);
	bss_start = .;	/* bss段的开始位置 */
	.bss : 
	{ 
		*(.bss) *(.COMMON) 
	}
	bss_end = .;	/* bss段的结束位置 */
}

链接脚本的内容很简单,起始地址是0x02026400,并获取了bss段的起始和结束地址。

按照前面文章讲解的编译和烧写命令,将程序烧写到SD卡中,设置SD卡启动,观察现象,发现LED1/2被点亮。说明程序重定位成功。

完毕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值