第九课JZ2440裸板操作之重定位

前言,这节课会涉及到重定位、位置无关码,不是很了解的请先看我的这篇文章:
链接地址、运行地址、加载地址、存储地址、位置相关与位置无关

一、重定位引入

首先我们知道我们的代码是烧写在flash中的,而且我们的设备是区分nor flash与nand flash;
nor启动:
如果我们使用nor启动,这时nor flash就会被映射成0地址,但是由于nor flash特性,我们不能按照SDRAM对nor flash进行写操作,所以需要将全局变量及静态变量放到SDRAM中。
nand启动:
如果我们使用nand启动,由于cpu不能对nand flash进行跟SDRAM一样的数据读写,所以启动的时候,硬件会实现一个复制的功能,既将nand flash前4K的内容复制到片内的4Ksram,这个时候,片内的4Ksram会被映射到0地址。所以nand 启动我们可以实现像读写SDRAM一样的功能。但是当文件大于4K,我们就需要将整体复制到SDRAM,复制的实现部分就应该放到前4K的代码中。
以上两种启动方法,在文件大于4K的情况下,都需要将代码或数据复制到SDRAM,这就叫做重定位。

二、链接脚本的介绍

我们知道程序中分代码段、只读数据段、数据段、.bss段、.common。
链接脚本的语法:

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

解释:

 secname  :段名
 start  :起始地址:运行时的地址(runtime addr);重定位地址(relocate addr)
 AT ( ldadr ) :可有可无(load addr:加载地址) 不写时LoadAddr = runtime addr
 { contents } 的内容: 
 start.o //内容为start.o文件
 *.text)所有的代码段文件
 start.o *(.text)文件

如果loadaddr != runtimeaddr程序本身要重定位
如果bin文件的位置不等于runtimeaddr程序本身要重定位
下面列出uboot中的一个一体式链接脚本(一体式即代码段、只读数据段、数据段、.bss段 .common连在一起)

SECTIONS
{
	. = 0x30000000;  //链接地址,SDRAM的地址

	. = ALIGN(4);   //向4字节对齐
	.text      :
	{
	  *(.text)
	}

	. = ALIGN(4);
	.rodata : { *(.rodata) }

	. = ALIGN(4);
	.data : { *(.data) }

	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) *(.COMMON) }
	_end = .;
}

有上面的脚本可知,我们的程序加载地址跟运行地址都是0x30000000,但是我们把它烧写到nor flash 中,因为nor启动是,nor flash的地址是0地址,所以也需要重定位,将nor flash中的代码复制到0x30000000处。
在这里插入图片描述

三、代码编写

修改start.S如下:

.text
.global _start

_start:

	/* 关闭看门狗 */
	ldr r0, =0x53000000
	ldr r1, =0
	str r1, [r0]

	/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
	/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
	ldr r0, =0x4C000000
	ldr r1, =0xFFFFFFFF
	str r1, [r0]

	/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
	ldr r0, =0x4C000014
	ldr r1, =0x5
	str r1, [r0]

	/* 设置CPU工作于异步模式 */
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA
	mcr p15,0,r0,c1,c0,0

	/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 
	 *  m = MDIV+8 = 92+8=100
	 *  p = PDIV+2 = 1+2 = 3
	 *  s = SDIV = 1
	 *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
	 */
	ldr r0, =0x4C000004
	ldr r1, =(92<<12)|(1<<4)|(1<<0)
	str r1, [r0]

	/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
	 * 然后CPU工作于新的频率FCLK
	 */


	/* 设置内存: sp 栈 */
	/* 分辨是nor/nand启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	 */
	mov r1, #0
	ldr r0, [r1] /* 读出原来的值备份 */
	str r1, [r1] /* 0->[0] */ 
	ldr r2, [r1] /* r2=[0] */
	cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */
	ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
	moveq sp, #4096  /* nand启动 */
	streq r0, [r1]   /* 恢复原来的值 */

	bl sdram_init

	/* 重定位text, rodata, data段整个程序 */
	mov r1, #0
	ldr r2, =_start 	    /* 第1条指令运行时的地址 */
	ldr r3, =__bss_start    /* bss段的起始地址 */

cpy:
	ldr r4, [r1]
	str r4, [r2]
	add r1, r1, #4
	add r2, r2, #4
	cmp r2, r3
	ble cpy


	/* 清除BSS段 */
	ldr r1, =__bss_start
	ldr r2, =_end
	mov r3, #0
clean:
	str r3, [r1]
	add r1, r1, #4
	cmp r1, r2
	ble clean

	//bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
	ldr pc, =main  /* 绝对跳转, 跳到SDRAM */

halt:
	b halt

四、编译烧写
编译文件之后,在生成的bin文件里,代码保存的位置是0x30000000。随后烧写到NOR Flash的0地址,但代码的结构没有变化。之后再重定位到SDRAM。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值