Nor Flash启动
Nor Flash:SST39VF1601 ---2MB
SDRAM: HY57V561620FTP-H,容量:256Mb(16M×16bit)=32MB,频率:133MHZ,开发板带2片* 32MB=64MB
前记:
关于这一步的移植花费了很大的时间。我们知道,在gdb调试时,是直接load代码到CONFIG_SYS_TEXT_BASE 所对应的SDRAM地址处,CONFIG_SYS_TEXT_BASE 在文件u-boot-2011.03boardsamsungmini2440config.mk中定义。假设CONFIG_SYS_TEXT_BASE=0x33000000,那么调试时就将uboot的所有内容加载到0x33000000 SDRAM地址处。运行时设置CPU模式à关中断à设置时钟à调用函数board_init_f (u-boot-2011.03archarmlibboard.c),在board_init_f计算出uboot要拷贝的地址addr,在start.S(u-boot-2011.03archarmcpuarm920tstart.S)文件的relocate_code处将_start(_start=CONFIG_SYS_TEXT_BASE=_TEXT_BASE)地址处的uboot内容拷贝到addr地址处,比如addr=0x33f00000。如下图所示。
其中,__bss_end__,_end都是在u-boot-2011.03archarmcpuarm920tu-boot.lds文件中定义的。
同样,如果把目标代码烧写到Nor flash中,那么从Nor flash启动时,从地址0处运行,同样是设置CPU模式à关中断à设置时钟à调用函数board_init_f,在board_init_f计算出uboot要拷贝的地址。虽然过程应该是这样走的,但是却不能正常运行。因为在board_init_f函数里,调用了一些其他的函数,而这些函数都是在地址0x33000000之后的,是SDRAM的地址。而此时如果去调用这些函数,直接跳转过去是无法运行的,因为此时0x33000000地址处是没有任何代码的(调试时可以是因为调试时是直接load到此处的),也就是现在SDRAM里面是没有任何代码的。那么为什么board_init_f可以调用,这就涉及到了绝对跳转指令和相对跳转指令。可参考http://www.cnblogs.com/myblesh/archive/2012/04/17/2454162.html。虽然board_init_f的编译地址在SDRAM的0x33000000之后,但调用board_init_f (board_init_f函数是在uboot的最前4kB)是在start.S里以相对跳转指令调用的,所以可以成功调用board_init_f,但里面的函数就无法正常运行了。网上有些人说将board_init_f作为第一阶段可以启动,但目前还没有发现怎么让它去运行。因为在board_init_f函数调用了编译地址在SDRAM 0x33000000之后的函数,而且这些函数不是位于uboot的前4kB,而且目前还不知道怎么在C语言里面实现相对跳转。因此在start.S里,在board_init_f之前加入如下代码:
/*copy uboot to CONFIG_SYS_TEXT_BASE address*/
relocate_run_at_stage_1:
adr r0, _start
ldr r1, _TEXT_BASE /*if in ram, no copy*/
cmp r0, r1
beq call_board_init_f
ldr r2, _end_ofs /*copy all uboot data, so, use _end_ofs(=_end-_start)*/
add r2, r0, r2
copy_from_flash_to_TEXT_BASE:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_from_flash_to_TEXT_BASE
/*copy uboot to CONFIG_SYS_TEXT_BASE address*/
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
ldr pc, =board_init_f /*jump ram use command ldr*/
从Nor flash启动时,_start=0,_TEXT_BASE=0x33000000不等就开始copy,copy的大小是_end_ofs,即uboot所有内容大小。这一步copy相当于调试时load步骤。Copy完之后,设置堆栈,以绝对跳转指令跳转到board_init_f处执行,此时0x33000000地址处就有uboot代码存在了。board_init_f此时作为第二阶段代码运行。
当调试时_start和_TEXT_BASE都等于0x33000000,所以不运行此代码,直接跳转到board_init_f。
大致的过程如下图所示。
但是,我们会发现在relocate_code处又会将代码copy一遍,即第二步copy。目前是这样实现的,需要两步copy,有点多余。如果在board_init_f函数中,将addr的地址和_TEXT_BASE设置成一样,应该就不需要第二步copy了。当然这需要做一些修改。
需要说明一点的是,uboot不仅可以在SDRAM的CONFIG_SYS_TEXT_BASE地址处运行,同样也可以在SDRAM的其它地址处运行,这应该归功于start.S的下面部分代码:
#ifndef CONFIG_PRELOADER
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
这段代码实现的具体意义目前不清楚,应该是将每个函数所对应的RAM地址进行重定向,以便在SDRAM的哪个基地址处都可以正确调用基于CONFIG_SYS_TEXT_BASE地址编译出来的函数。
Nor Flash 启动
参考网址:
http://blog.csdn.net/atower_boy/article/details/6290817
http://www.cnblogs.com/heaad/archive/2010/07/17/1779829.html
关于怎么去调用函数board_init_r,可以参考:http://blog.chinaunix.net/uid-29284763-id-3969667.html
修改相关文件:
1. u-boot-2011.03boardsamsungmini2440lowlevel_init.S
2. u-boot-2011.03boardsamsungmini2440Makefile
3. u-boot-2011.03archarmcpuarm920tu-boot.lds
4. u-boot-2011.03boardsamsungmini2440config.mk
5. u-boot-2011.03archarmlibboard.c
6. u-boot-2011.03archarmcpuarm920tstart.S
7. u-boot-2011.03boardsamsungmini2440config.mk
前面的所有调试,对于uboot来说大部分都是第2阶段的代码。如果将uboot烧写到Nor flash内,第1阶段的代码也必须实现。我们知道,第1阶段的代码就是从Norflash 0地址处运行,将uboot代码copy到SDRAM中,然后转到SDRAM,后面的步骤就和之前调试时的一样了。我们还知道,在之前的仿真调试过程中,Eclipse里面加了些初始化代码,这些初始化代码做了第1阶段的一些功能,像初始化SDRAM等等,数据cache或指令cache的关闭。因此,要想在Nor flash里运行uboot,还需要实现一些功能,
编译生成的代码烧写到Nor flash的0地址处。开机,运行,ARM从0地址处开始运行,0地址处的前4kB一定要是与地址无关的代码。
在我们根据上面的网址修改后,编译会发现:
board/samsung/mini2440/libmini2440.o:In function `lowlevel_init':
d:ProgramEclipseu-boot-2011.03boardsamsungmini2440/lowlevel_init.S:145:multiple definition of `lowlevel_init'
board/samsung/mini2440/lowlevel_init.o:d:ProgramEclipseu-boot-2011.03boardsamsungmini2440/lowlevel_init.S:145:first defined here
Make:*** [u-boot] Error 1
错误报的是说lowlevel_init有多处定义,其实我们只在u-boot.lds里面加上了lowlevel_init.o,怎么就多处定义了。上网查找,根据网址http://blog.csdn.net/lihancheng/article/details/4063408和
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3749526提供的信息,对makefile做了如下修改:
针对boardsamsungmini2440Makefile的修改如下表格:
在这个文件夹下只产生lowlevel_init.o文件,不将lowlevel_init.o链接到libmini2440.o文件里。由于u-boot.lds里面包含了lowlevel_init.o,猜测上面只所以报lowlevel_init多处定义,可能是因为libmini2440.o和lowlevel_init.o里各有一份lowlevel_init。没有具体看makefile的细节。我们在链接前4kB的代码时,把该链接到前4kB的代码必须链接到前4kB,多余的空间再放些其他的代码。
其它的文件修改可以download下来与之前的比较。
编译,然后下载到Nor Flash里就可以运行了。关于下载到Nor Flash,可参考:http://blog.chinaunix.net/uid-25100840-id-349517.html。
本文的J-Flash其中CPU设置如下图:、
本部分代码下载地址:360云盘http://yunpan.360.cn/,在《Uboot相关代码》文件夹里的《u-boot-2011.03_NorFlash启动.zip》文件。
《u-boot-2011.03源码无修改.tar.bz2》是从官网下的无修改代码
上一篇:Windows下u-boot-2011.03在Mini2440移植详解(3)
下一篇:Windows下u-boot-2011.03在Mini2440移植详解(5)
推荐阅读最新更新时间:2024-11-12 12:05