S3C2440移植uboot之支持NAND启动

Ona ·
更新时间:2024-09-21
· 626 次阅读

文章目录1.去掉 "-pie"选项2.修改之前的init.c3.修改start.s重定位部分4.修改链接脚本5.报错修改6.重新修改链接地址
  上一节S3C2440移植uboot之新建单板_时钟_SDRAM_串口移植uboot初始化了时钟,配置了支持串口,这一节我们继续修改uboot支持NAND启动。
  参考之前uboot使用的start.S, init.c来修改uboot代码新的uboot链接地址位于0,且在arm-linux-ld时加了"-pie"选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)",从而程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K).
  所以接下来修改代码,并取消"-pie"选项. 1.去掉 "-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"这行即可
在这里插入图片描述

2.修改之前的init.c

  将以前写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((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 > 8) & 0xff; for (i = 0; i < 10; i++); NFADDR = page & 0xff; for (i = 0; i > 8) & 0xff; for (i = 0; i > 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(); }

  修改init.c中的clear_bss,修改后的代码如下

void clear_bss(void) { extern int __bss_start, __bss_end_; int *p = &__bss_start; for (; p < &__bss_end_; p++) *p = 0; } 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)。

在这里插入图片描述

  删除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 #endif clear_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_r 4.修改链接脚本

  把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行如下
在这里插入图片描述

6.重新修改链接地址

  我们指定了 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,必须大于新的uboot nand write 30000000 0 0x80000 //将SDRAM上的新uboot写入nand

  烧写后,如下图所示:
在这里插入图片描述
  nand启动便实现完成了,上面的Flash: *** failed *** 是属于uboot第二阶段函数board_init_r()里的代码,表示不支持nor flash,不能实现读,写,擦除等命令。


作者:飞猪飞飞



nand s3c2440 uboot c2

需要 登录 后方可回复, 如果你还没有账号请 注册新账号