文章目录
- 1.去掉 "-pie"选项
- 2.修改之前的init.c
- 3.修改start.s重定位部分
- 4.修改链接脚本
- 5.报错修改
- 6.重新修改链接地址
移植Uboot其他文章链接:
S3C2440移植uboot之编译烧写uboot
S3C2440移植uboot之新建单板_时钟_SDRAM_串口
S3C2440移植uboot之启动过程概述
S3C2440移植uboot之支持NAND启动
S3C2440移植uboot之支持NORFLASH
S3C2440移植uboot之支持NANDFLASH操作
S3C2440移植uboot之支持DM9000
S3C2440移植uboot之裁剪和修改默认参数
S3C2440移植uboot之支持烧写yaffs映像及制作补丁
1.去掉 "-pie"选项 参考之前uboot使用的start.S, init.c来修改uboot代码新的uboot链接地址位于0,且在arm-linux-ld时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)",从而程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K).
所以接下来修改代码,并取消"-pie"选项.
使用grep “-pie” * -nR找到:
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie // LDFLAGS: arm-linux-ld的参数
所以屏蔽arch/arm/config.mk文件的"LDFLAGS_u-boot += -pie"这行即可
将以前写uboot里的init.c放入board/samsung/smdk2440目录, 并检查是否有同名函数名,若函数只在同文件使用,则添加static.并修改Makefile 增加对init.c的支持
vi board/samsung/smdk2440/Makefile
修改include/configs/smdk2440.h文件,将CONFIG_SYS_TEXT_BASE宏改为0x33f80000,也就是uboot重定位后的位置, 这里留了512K空间供给uboot重定位
修改完的代码如下所示
/* NAND FLASH控制器 */#define NFCONF (*((volatile unsigned long *)0x4E000000))#define NFCONT (*((volatile unsigned long *)0x4E000004))#define NFCMMD (*((volatile unsigned char *)0x4E000008))#define NFADDR (*((volatile unsigned char *)0x4E00000C))#define NFDATA (*((volatile unsigned char *)0x4E000010))#define NFSTAT (*((volatile unsigned char *)0x4E000020))/* GPIO */#define GPHCON (*(volatile unsigned long *)0x56000070)#define GPHUP (*(volatile unsigned long *)0x56000078)/* UART registers*/#define ULCON0 (*(volatile unsigned long *)0x50000000)#define UCON0 (*(volatile unsigned long *)0x50000004)#define UFCON0 (*(volatile unsigned long *)0x50000008)#define UMCON0 (*(volatile unsigned long *)0x5000000c)#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)#define UTXH0 (*(volatile unsigned char *)0x50000020)#define URXH0 (*(volatile unsigned char *)0x50000024)#define UBRDIV0 (*(volatile unsigned long *)0x50000028)#define TXD0READY (1<<2)void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);static int isBootFromNorFlash(void){volatile int *p = (volatile int *)0;int val; val = *p;*p = 0x12345678;if (*p == 0x12345678){/* 写成功, 是nand启动 */*p = val;return 0;}else{/* NOR不能像内存一样写 */return 1;}}void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len){int i = 0;/* 如果是NOR启动 */if (isBootFromNorFlash()){while (i < len){ dest[i] = src[i]; i++;}}else{//nand_init();nand_read_ll((unsigned int)src, dest, len);}}void clear_bss(void){extern int __bss_start, __bss_end__;int *p = &__bss_start;for (; p < &__bss_end__; p++)*p = 0;}void nand_init_ll(void){#define TACLS 0#define TWRPH0 1#define TWRPH1 0/* 设置时序 */ NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ NFCONT = (1<<4)|(1<<1)|(1<<0);}static void nand_select(void){ NFCONT &= ~(1<<1);}static void nand_deselect(void){ NFCONT |= (1<<1);}static void nand_cmd(unsigned char cmd){volatile int i; NFCMMD = cmd;for (i = 0; i < 10; i++);}static void nand_addr(unsigned int addr){unsigned int col = addr % 2048;unsigned int page = addr / 2048;volatile int i; NFADDR = col & 0xff;for (i = 0; i < 10; i++); NFADDR = (col >> 8) & 0xff;for (i = 0; i < 10; i++); NFADDR = page & 0xff;for (i = 0; i < 10; i++); NFADDR = (page >> 8) & 0xff;for (i = 0; i < 10; i++); NFADDR = (page >> 16) & 0xff;for (i = 0; i < 10; i++);}static void nand_wait_ready(void){while (!(NFSTAT & 1));}static unsigned char nand_data(void){return NFDATA;}void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len){int col = addr % 2048;int i = 0;/* 1. 选中 */nand_select();while (i < len){/* 2. 发出读命令00h */nand_cmd(0x00);/* 3. 发出地址(分5步发出) */nand_addr(addr);/* 4. 发出读命令30h */nand_cmd(0x30);/* 5. 判断状态 */nand_wait_ready();/* 6. 读数据 */for (; (col < 2048) && (i < len); col++){ buf[i] = nand_data(); i++; addr++;} col = 0;}/* 7. 取消选中 */nand_deselect();}3.修改start.s重定位部分
修改arch/arm/cpu/arm920t/start.S,更改重定位代码。由于nand启动时,2440未初始化之前只有前4K可读写,所以将重定位代码放在start.S的cpu_init_crit(初始化SDRAM)段后面。修改后代码如下
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit#endif ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) //等于0x30000f80 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ bl nand_init_ll mov r0, #0 //r0->src//ldr r1, =_start ldr r1,_TEXT_BASE //链接地址 _TEXT_BASE : 0x33f80000 0x34000000-0x33f80000=512k uboot 512k足以 ldr r2,_bss_start_ofs // _bss_start_ofs: __bss_start - _start (有效代码大小) bl copy_code_to_sdram bl clear_bss //清除bss段(参考自制uboot章节) ldr pc,=call_board_init_f //绝对跳转,跳到SDRAM上执行/* Set stackpointer in internal RAM to call board_init_f */call_board_init_f: ldr r0,=0x00000000 bl board_init_f
上面的_TEXT_BASE,在start.S靠前处定义:
由于它位于靠前处,保证了_TEXT_BASE存在前4k空间里,若直接使用ldr r1,=CONFIG_SYS_TEXT_BASE,编译器可能会将这个宏定义放在SDRAM上,则会出错。
重定位写在前面了,所以我们还要删除start.S后面的u-boot-2012.04.01\arch\arm\lib\board.c中的 relocate_code重定位段,清除BSS段。同时在relocate_code(addr_sp, id, addr);后面增加return (unsigned int) id;,修改函数为unsigned int board_init_f(ulong bootflag)。
同时注释掉board.c中如下的内容,固定addr的值。
删除start.s中原有的重定位代码,删除部分如下
/* * void relocate_code (addr_sp, gd, addr_moni) * * This "function" does not return, instead it continues in RAM * after relocating the monitor code. * */.globl relocate_code relocate_code: mov r4, r0 /* save addr_sp */ mov r5, r1 /* save addr of gd */ mov r6, r2 /* save addr of destination *//* Set up the stack */stack_setup: mov sp, r4 adr r0, _start cmp r0, r6 beq clear_bss /* skip relocation */ mov r1, r6 /* r1 <- scratch for copy_loop */ ldr r3, _bss_start_ofs add r2, r0, r3 /* r2 <- source end address */copy_loop: ldmia r0!, {r9-r10}/* copy from source address [r0] */ stmia r1!, {r9-r10}/* copy to target address [r1] */ cmp r0, r2 /* until source end address [r2] */ blo copy_loop#ifndef CONFIG_SPL_BUILD/* * 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#endifclear_bss:#ifndef CONFIG_SPL_BUILD ldr r0, _bss_start_ofs ldr r1, _bss_end_ofs mov r4, r6 /* reloc addr */ add r0, r0, r4 add r1, r1, r4 mov r2, #0x00000000/* clear */clbss_l:str r2, [r0]/* clear loop... */ add r0, r0, #4 cmp r0, r1 bne clbss_l bl coloured_LED_init bl red_led_on#endif
start.s增加第二阶段启动代码
call_board_init_f: ldr r0,=0x00000000 bl board_init_f /*unsigned int id 的值存在r0中,正好给board_init_r使用*/ ldr r1, =_TEXT_BASE /*调用第二阶段代码*/ bl board_init_r4.修改链接脚本
把start.S, init.c(实现重定位), lowlevel.S(实现初始化SDRAM)等文件放在最前面
rm u-boot.lds vi arch/arm/cpu/u-boot.lds
添加以下字段:
. = ALIGN(4);.text :{__image_copy_start = .;CPUDIR/start.o (.text) //CPUDIR为arch/arm/cpu/arm920t目录board/samsung/smdk2440/libsmdk2440.o (.text) *(.text)}
libsmdk2440.o是将smdk2440单板目录下的所有*.c,*S文件编译后,连接成一个库文件.
5.报错修改报错
board.c:259: error: conflicting types for 'board_init_f'/work/system/u-boot-2012.04.01/include/common.h:276: error: previous declaration of 'board_init_f' was here/work/system/u-boot-2012.04.01/config.mk:312: recipe for target 'board.o' failed
根据指示修改u-boot-2012.04.01/include/common.h 276行如下
报错
board/samsung/smdk2440/libsmdk2440.o: In function `clear_bss':/work/system/u-boot-2012.04.01/board/samsung/smdk2440/init.c:77: undefined reference to `__bss_end_' Makefile:472: recipe for target 'u-boot' failed
根据指示修改u-boot-2012.04.01/board/samsung/smdk2440/init.c:77行如下
我们指定了 CONFIG_SYS_TEXT_BASE 0x33f80000 ,所以我们的uboot不能超过512k,0x33f80000这个是不包括bss段的全局变量的。查看start.s文件。
在反汇编中搜索_bss_end_ofs,00094b40为整个代码段的大小(包括了bss段),转换为10进制609088,已经大于了512k,所以重新修改CONFIG_SYS_TEXT_BASE 0x33f00000 。预留uboot空间为0x34000000-0x33f00000=1M
然后通过旧的uboot,将新的uboot烧写到nand中
usb 1 30000000 //先下载到SDRAM上nand erase 0 0x80000 //擦除512kb,必须大于新的ubootnand write 30000000 0 0x80000 //将SDRAM上的新uboot写入nand
查看u-boot.lds
烧写后,如下图所示:
nand启动便实现完成了,上面的Flash: *** failed *** 是属于uboot第二阶段函数board_init_r()里的代码,表示不支持nor flash,不能实现读,写,擦除等命令。