En 0755-86038900
公司新闻

4412开发板Linux开发指南10

发布时间:2015-04-07

Linux平台下UT4412BV03裸机开发指南(十)

第一章 重定位代码到SDRAM-DDR3

第一节 重定位

对于程序而言,我们需要理解两个概念,一是程序当前所处的地址,即程序在运行时,所处的当前地址;二是程序的链接地址,即程序运行时应该位于的运行地址。编译程序时,可以指定程序的链接地址。

对于Exynos 4412而言,启动时只会从iNAND Flash/sd等启动设备中拷贝BL1(三星提供,无源码),在由BL1拷贝BL2(14K,其中4字节为校验码)代码到IRAM(连接地址0x02023400)中,那么当我们的程序超过14K-4,怎么办?且IRAM

只有256K大小。那么我们就需要将我们程序分为2部分,BL2BL3BL214KBL1拷贝IRAM中,跳到BL2执行,再BL2BL3拷贝DRAM中,然后再跳转到DRAM中继续运行我们的代码,这个拷贝然后跳转的过程就叫重定位。

从这章开始我们的程序结构发生了一些变化,前几个实验我们只生成一个文件,从这个实验开始我们生成两个文件,BL2.binBL3.bin,其中BL2.bin文件的链接地址是0x02023400 (使用的是位置无关码,程序可以在任意可用的内存中运行) ;BL3.bin 文件的链接地址是0x41000000(使用的并不是位置无关码,所有程序必须位于该地址处才能正常运行)。需要在SD卡上烧写三部分程序,分别是:

1.BL1(由三星提供):实现一些初始化

2.BL2(我们自己编写源码,用mkbl2工具生成):板级初始化,并完成代码重定位到SDRAM,完成跳转

3.BL3:实现我们想要的功能

三部分代码在SD卡的位置如下:

程序在SD卡的位置分布

从图中可以看出,BL1.bin烧写到SD卡扇区1BL2.bin烧写到sd卡的扇区17BL3.bin烧写到sd卡的扇区49处。

整个程序的运行过程大致如下:系统上电后,首先将sd卡扇区1处的BL1拷贝到IRAM0x02020000地址处,然后运行该部分代码,该部分代码首先又会加载BL2.binIRAM0x02023400地址处,BL2.bin会进行时钟和DRAM初始化,然后把位于sd卡中扇区49处的BL3.bin拷贝到DRAM0x41000000地址处,最后跳转到该地址处继续运行。

第二节 程序相关讲解

完整代码见目录9.link_sdram10.link_sdram_printf,10.link_sdram_printf代码的BL3部分加入了串口打印和命令的功能,现在简单讲解下9.link_sdram,代码分为BL2BL3部分,上面已经介绍.

1. BL2/start.S

.text

.globl _start

 

_start:

//关看门狗

ldr r1, = 0x10060000

mov r0, #0x0

str r0, [r1]

 

//使能IcacheP15协寄存器的第12

orr r0, r0, #0x00001000

mcr p15, 0, r0, c1, c0, 0

 

//设置栈

ldr sp, =0x02050000

 

bl system_clock_init

 

bl ddr3_mem_init

 

//重新设置栈到SDRAM

ldr sp, =0x43000000

 

bl leds_init

 

bl uart_init

 

bl copy_code_to_dram

 

halt:

b halt

以上先关闭看门狗,使能icache,接着初始化时钟内存、led、串口,最后调用copy_code_to_dram函数拷贝BL3SDRAM0x41000000

2. BL2/ mmc_relocate.c

#define SDMMC_ReadBlocks(uStartBlk, uNumOfBlks, uDstAddr)

(((void(*)(unsigned int, unsigned int, unsigned int*))(*((unsigned int *)0x02020030)))(uStartBlk, uNumOfBlks, uDstAddr))

 

void copy_code_to_dram (void)

{

void (*BL3) (void);

 

printf("Copy start ... ");

 

SDMMC_ReadBlocks(49,32,(unsigned int *)0x41000000);

 

printf("Copy over !!!! ");

 

#if 0

unsigned int *p;

int i, j;

p = (unsigned int *) 0x41000000;

for (j = 0; j < 32; j++)

{

printf("%8x: ", (unsigned int)p);

for (i = 0; i < 2; i++)

printf("%8x ", *p++);

printf(" ");

}

#endif

 

printf("Start BL3... ");

/*跳转到DRAM*/

BL3 = (void *)0x41000000;

(*BL3)();

}

函数只要是调用三星固化好在芯片里的SD卡拷贝函数SDMMC_ReadBlocksSD卡的BL3程序拷贝到0x41000000然后跳到0x41000000执行BL3.

《Android_Exynos4412_iROM_Secure_Booting_Guide_Ver.1.00.00.pdf》Exynos 4412启动和拷贝函数有所介绍。

 

 

 

3. BL3/start.S

.global _start

 

_start:

bl main    

 

halt:

b halt

BL3程序的start直接跳转到main函数执行。

4. BL3/main.c

int main(void)

{

// 设置GPX0CON的bit[0:15],配置GPJ0_5/7引脚为输出功能

GPX0CON |= (0x1 << 20) | (0x1 << 28);

// 设置GPX2CON的bit[0:15],配置GPJ0_4/5引脚为输出功能

GPX2CON |= (0x1 << 16) | (0x1 << 20); 

 

while(1)

{

 

// 设置GPX0DAT的bit[0:15],使GPJ0_5/7引脚输出低电平,LED亮

GPX0DAT &= ~((0x1 << 5) | (0x1 << 7)); 

// 设置GPX2DAT的bit[0:15],使GPJ0_4/5引脚输出低电平,LED亮

GPX2DAT &= ~((0x1 << 4) | (0x1 << 5)); 

 

delay(0x100000);

 

// 设置GPX0DAT的bit[0:15],使GPJ0_5/7引脚输出高电平,LED灭

GPX0DAT |= (0x1 << 5) | (0x1 << 7); 

// 设置GPX2DAT的bit[0:15],使GPJ0_4/5引脚输出高电平,LED灭

GPX2DAT |= (0x1 << 4) | (0x1 << 5); 

 

delay(0x100000);

}

return 0;

}

main函数及时BL3实现功能的代码,在此实现LED闪烁的功能。

5. sd_fusing.sh

sudo dd iflag=dsync oflag=dsync if=/work/UT4412BV03/NO_OS/tools/E4412_N.bl1.bin of=/dev/sdb seek=1

 

sudo dd iflag=dsync oflag=dsync if=./BL2/bl2.bin of=/dev/sdb seek=17

 

sudo dd iflag=dsync oflag=dsync if=./BL3/bl3.bin of=/dev/sdb seek=49

脚本程序的功能大家也可以看出,就是分别将BL1BL2和BL3拷贝到SD的1扇区17扇区49扇区

第三节 编译程序和烧写运行

sd卡插入PCUbuntu终端执行如下命令:

#cd 9.link_sdram

#make all

#./sd_fusing.sh

第四节 实验现象

sd卡插入UT4412BV03中,选择sd卡启动,然后上电。

 

串口打印出这三话后就看见LED灯在闪烁。

 了解更多的信息在http://www.urbetter.net     http://www.urbetter.com.cn或是到友坚论坛进行发贴讨论:http://bbs.urbetter.com