前期准备:
1.uboot下载地址 ftp://ftp.denx.de/pub/u-boot/
2.参照物开发板的选择
我们开发板使用的CPU是S5PV210,所以要找uboot中针对S5PV210或者S5PC110进行移植的作为参考。根据规律,我们应该参考include/configs/s5p_goni.h,对应的board在uboot/board/samsung/goni这个目录。
3.删除无关文件和文件夹,其实不删除也可以,但是删除更好。
4.建立SI工程并预解析
(1)参照物开发板为:55p_goni make s5p_goni_config
(2)配置对应的cpu、board文件夹分别为:
cpu: u-boot-2013.10\arch\arm\cpu\armv7
board: u-boot-2013.10\board\samsung\goni
开始移植
1.添加交叉编译工具链
在主Makefile 中CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
2.配置,编译,测试
(1)编译过程:
make distclean
make s5p_goni_config
make
(2)结果:得到u-boot.bin即可
3.推荐linux下脚本烧入
移植原来的版本的uboot中的sd_fusing文件夹到官方uboot版本中,使用这个文件夹中的sd_fusing.sh脚本来进行烧录
4.烧入后,串口现象;
(1)串口接串口2,串口有输出。但是这个串口输出不是uboot输出的,而是内部iROM中的BL0运行时输出的。
(2)输出错误信息分析:
第一个SD checksum Error:是第一顺序启动设备SD0(iNand)启动时校验和失败打印 出来的;
第二个SD checksum Error:是第二顺序启动设备SD2(外部SD卡)启动时校验和失败 打印出来的;
剩下的是串口启动和usb启动的东西,可以不管。
总结:从两个SD checksum Error,可以看出:外部SD卡校验和失败了。
分析:SD卡烧录出错了,导致SD卡校验和会失败。发现是mkbl1程序和start.S中前16个字节校验和的处理上面不匹配造成的,解决方法是在start.S最前面加上16个字节的占位。
5.上述问题的解决方法:
参考之前的start.S发现有16字节占位。直接复制粘贴到本版本的start.S的相应位置。
\u-boot-2013.10\arch\arm\cpu\armv7\start.S
重新编译烧录运行,发现结果只显示一个SD checksum Error。这一个就是内部SD0通道的inand启动校验和失败打印出来的。剩下的没有了说明外部SD卡校验和成功了,只是SD卡上的uboot是错误的,没有串口输出内容,所以没有输出了。
3.继续分析start.S
(1)#define CONFIG_SYS_TEXT_BASE 0x34800000 可以看出我们的uboot的连接地址是在0x34800000位置
(2)cpu_init_cp15这个函数功能是设置MMU、cache等。这个版本的uboot中未使用虚拟地址,因此MMU在这里直接关掉。
(3)cpu_init_crit,这个函数里只有一句跳转指令,短跳转到lowlevel_init函数。
Lowleve_init 分析:
lowlevel_init函数在board/samsung/goni目录下,主要作用是时钟设置、串口设置、复位状态判断···这个函数是S5PC100和S5PC110两个CPU共用的。
经过浏览,发现lowlevel_init函数中做的有意义的事情有:关看门狗、调用uart_asm_init来初始化串口、并没有做时钟初始化(下面有时钟初始化的函数,但是实际没调用。如果uboot中没有初始化时钟,那么时钟就是iROM中初始化的那种配置)
7.添加开发板制锁和串口打印字符"O"
(1)我们为了调试uboot的第一阶段,就要看到现象。为了看到现象,我们向lowlevel_init函数中添加2个代码,一个是开发板制锁,在watchdog后
// 我们添加的开发板供电制锁的代码
ldr r0, =0xE010E81C
ldr r1, =0x301
str r1, [r0]
一个是串口打印"O"在串口初始化最后
// 串口2输出字符'O'
ldr r1, =0x4f4f4f4f
ldr r2, =0xE2900820
str r1, [r2] @'O'
(2)这两段代码可以直接从ARM裸机全集课程中的代码中来。其实也可以从三星移植版本的uboot中来,但是因为三星移植版本中用到了很多寄存器定义,涉及到头文件的, 所以移植过来不方便。
(3)实践添加。
实践结果及分析
(1)实验结果是:没看到开发板制锁,串口也没有输出任何东西。实验失败。
(2)结论:因为开发板制锁没有成功,所以我们判定,在开发板制锁代码运行之前uboot 就已经挂掉了。下面就是去跟踪代码运行,然后判定问题点再去解决
8.添加LED点亮代码跟踪程序运行
(1)在基础代码阶段,串口还没有运行,串口调试工具还无法使用时,使用LED点亮的方式来调试程序就是一个有力的手段。
(2)有些情况下可以用Jlink等调试工具来调试这种基础代码。
(3)从程序的基本运行路径端出发,隔一段给他添加一个LED点亮代码,然后运行时根据现象来观察,判定哪里执行了哪里没执行。从而去定位问题。
(4)从以前的裸机代码中组织出一个标准的LED点亮然后延时一段的一个标准代码段:
ldr r0, =0x11111111
ldr r1, =0xE0200240
str r0, [r1]
ldr r0, =((1<<3) | (0<<4) | (1<<5)) // 1是灭,0是亮
ldr r1, =0xE0200244
str r0, [r1]
ldr r2, =9000000 //延时函数
ldr r3, =0x0
delay_loop:
sub r2, r2, #1
cmp r2, r3
bne delay_loop
(5)之前做实验时发现一个现象:我们的uboot运行时按住电源开关时所有4颗LED都是亮的。所以我们做实验时给LED点亮是看不到现象的,所以我们的代码关键是要熄灭某些LED来判断。
(6)我们将熄灭LED的函数在start.S中隔一段的关键部位放上1个,然后运行时通过观察LED的点亮熄灭状态,就知道程序运行到哪里了。
(7)经过判断我们发现:start.S中工作一切正常,但是函数一旦放到lowlevel_init.S中就完全不工作了。通过分析得出结论:b lowlevel_init这句代码出了问题。
9.解决问题
(1)问题分析:跳转代码出了问题。分析问题出在代码的连接上。
(2)三星S5PV210要求BL1大小为8KB,因此uboot第一阶段代码必须在整个uboot镜像的前8KB内,否则跳转不到。
(3)对比三星移植版本的uboot的u-boot.lds和官方版本uboot的连接脚本u-boot.lds(注意这两个版本的uboot的连接脚本的位置是不同的),就发现lowlevel_init.S的代码段没有被放在前面。
(4)在u-boot.lds中start.o后面添加board/samsung/goni/lowlevel_init.o (.text*),这个就保证了lowlevel_init函数被连接到前面8kb中去。
(5)报错,lowlevel_init重复定义了。
修改board/samsung/goni/Makefile解决编译问题
(1)问题分析:为什么会重复定义。因为lowlevel_init这个函数被连接时连接了2次。一次是board/samsung/goni这个目录下生成libgoni.o时连接了1次,第2次是连接脚本最终在连接生成u-boot时又连接了一次,所以重复定义了。
(2)这个错误如何解决?思路是在libgoni.o中不要让他连接进lowlevel_init,让他只在最终连接u-boot时用1次,就可以避免重复定义。
(3)参考当前版本的uboot的start.S文件的处理技巧,解决了这个问题。
实践验证。
结果是开发板制锁和串口输出'O'都成功了
DDR初始化
分析下一步移植路线
(1)cpu_init_crit函数成功初始化串口、时钟后,转入_main函数,函数在arch/arm/lib/crt0.S文件中。
(2)在crt0.S中首先设置栈,将sp指向DDR中的栈地址;然后调用board_init_f函数进行板级初始化。函数在arch/arm/lib/board.c中。
(3)在这个版本的uboot中,把以前uboot的第二阶段start_armboot函数分成了2部分:board_init_f和board_init_r。所以在这里就和以前版本的uboot接轨上了,推测board_init_f中肯定是做了板级初始化,board_init_r中进入了uboot的命令行。
(4)分析到这里,在uboot2013.10版本中思路已经很清晰了:uboot的第二阶段就在crt0.
(5)分析到这里,下一步工作方向就确定了。我们要先在cpu_init_crit函数中添加DDR初始化,然后在start.S中bl _main之前添加uboot的重定位,然后将bl _main改成ldr pc, __main(__main: .word _main)长跳转。然后在crt0.S中board_init_f后删除那些重定位代码,至此uboot的第二阶段就应该能启动起来了。后续的移植就是第二阶段了。
该版本没有DDR初始化代码需要从三星官方移植
动手移植
(1)添加cpu_init.S文件到uboot2013.10中。注意,这里的代码必须保证在前8kb内,所以必须和lowlevel_init.S文件一样的链接处理。主要是在board/samsung/goni/Makefile中和arch/arm/cpu/u-boot.lds文件中做修改添加。
(2)Lds:
Makefile中:
(2)添加头文件s5pc110.h到include目录下。
(3)对cpu_init.S文件代码进行修整,把一些无用的代码去掉,把一些相关的条件编译人工处理一下。
(4)在SourceInsigt工程中添加入这两个文件。然后重新解析一遍。然后对新添加的代码进行分析修整,把里面一些明显的宏定义缺失给补上。
(5)DDR配置参数,从三星版本的smdkv210single.h中复制到s5p_goni.h中。
在lowleve_init.S中,调用mem_ctrl_asm_init 然后在后面打印“K”
(6)s5pc110.h中进行修整。
(7)结果:看到了"OK"标志,说明DDR添加实验成功
DDR初始化:1复制三星的cpu_init.S到和lowleve_init.S在同一文件下,并进行修改删除,再makefile中作为依赖添加上;再在链接脚本u-boot.lds中链接到前面。2将所需要的配置宏定义从本来的.h文件中复制到本版本的配置头文件.h中。3将cpu_init.S所需要的板级宏定义的头文件s5pc110.h复制到相对位置一样的文件夹中,并进行修改删除。4在lowleve_init.S中,调用mem_ctrl_asm_init 然后在后面打印“K”
重定位
在bl cpu_init_crit(b lowlevel_init @ go setup pll,mux,memory里面只有这一句)也可以说在b lowlevle后开始重定位相关代码。
/重定位开始
/* get ready to call C functions设置栈 */
ldr sp, _TEXT_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.检查需不需要重定位
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */
若相等则不需要重定位直接跳到after_copy
/* If BL1 was copied from SD/MMC CH2 *判断通道2 sd卡启动*/
ldr r0, =0xD0037488
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
mmcsd_boot:
bl movi_bl2_copy /*跳转重定位函数copy,在movi.c
after_copy:
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
/*请bss段,注意链接地址,需要移植修改*/
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
//bl _main 第一阶段和第二阶段的过度,分析得_mian函数为uboot第二阶段,做长跳转
ldr pc, __main
__main:
.word _main
需要移植movi_bl2_cop函数,
将 所在的文件movi.c复制到\u-boot-2013.10\board\samsung\goni,和lowleve.S同样的操作在Makefike和u-boot.lds中,删除不需要的函数,再确保宏定义可用,在s5p_goni配置头文件中添加修改。
复制所需要的头文件到相应位置movi.h
后续:将_main(在crt0.S)中的有关重定位的代码删掉
编译中出现问题解决
(1)movi.h中宏定义出错,最后在s5p_goni.h中添加了CONFIG_EVT1这个宏解决了
(2)连接错误:u-boot contains relocations other thanR_ARM_RELATIVE
在uboot下用grep "R_ARM_RELATIVE" -nR *搜索,发现Makefile中有一个检查重定位的规则,屏蔽掉这个规则后编译连接成功。
结果验证及下阶段展望
(1)看到了uboot启动打印出来的一系列信息,但是uboot没有进入命令行。
(2)这说明uboot中的DDR初始化和重定位功能都已经完美实现,后面就是第二阶段的继续移植了。