博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
三,移植uboot-支持NAND启动
阅读量:6909 次
发布时间:2019-06-27

本文共 8782 字,大约阅读时间需要 29 分钟。

文档时间:2018-08-10

交叉编译器:arm-linux-gcc-4.3.2

Ubuntu版本:16.04

uboot版本:2013.10

 

1,分析为何不能从 nand 启动

将上一章编译好的 u-boot.bin 烧写到 nand flash 中,将板子设置位 nand 启动,发现串口无任何输出,说明 nand 启动未成功,查看反汇编文件 u-boot.dis

先生成 u-boot.dis:

arm-linux-objdump -D u-boot > u-boot.dis

 打开 u-boot.dis :

发现 u-boot 如果从 nand 启动,有问题,主要是因为 s3c2440 sram 太小,只有 4k,而在前 4k 地址中,调用了很多 4k 地址以外的函数,这样就会导致程序跑飞

因此,为了能够让 uboot 支持 nand 启动,需要在前 4k 就完成代码重定位和代码拷贝的工作

2,修改代码实现 nand 启动

1),参考裸机程序关于 nand 部分和代码拷贝部分,添加 nand_read_ll.c 文件

在 board/samsung/jz2440 目录下新建 nand_read_ll.c 文件,将以前裸机程序中关于 nand 部分和 代码拷贝部分的代码复制到此文件中,完成后,代码如下:

1 /**  2 * u-boot-2012.04.01_100ask/board/samsung/smdk2440/init.c  3 **/  4   5   6 /* NAND FLASH控制器 */  7 #define NFCONF (*((volatile unsigned long *)0x4E000000))  8 #define NFCONT (*((volatile unsigned long *)0x4E000004))  9 #define NFCMMD (*((volatile unsigned char *)0x4E000008)) 10 #define NFADDR (*((volatile unsigned char *)0x4E00000C)) 11 #define NFDATA (*((volatile unsigned char *)0x4E000010)) 12 #define NFSTAT (*((volatile unsigned char *)0x4E000020)) 13  14  15 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len); 16  17 static void nand_init_ll(void) 18 { 19 #define TACLS   0 20 #define TWRPH0  1 21 #define TWRPH1  0 22     /* 设置时序 */ 23     NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); 24     /* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */ 25     NFCONT = (1<<4)|(1<<1)|(1<<0);     26 } 27  28 static int isBootFromNorFlash(void) 29 { 30     volatile int *p = (volatile int *)0; 31     int val; 32  33     val = *p; 34     *p = 0x12345678; 35     if (*p == 0x12345678) 36     { 37         /* 写成功, 是nand启动 */ 38         *p = val; 39         return 0; 40     } 41     else 42     { 43         /* NOR不能像内存一样写 */ 44         return 1; 45     } 46 } 47  48 void copy_code_to_sdram(volatile unsigned int *src, volatile unsigned int *dest, unsigned int len) 49 {     50     unsigned int i = 0; 51      52     /* 如果是NOR启动 */ 53     if (isBootFromNorFlash()) 54     { 55         while (i < len) 56         { 57             *dest++ = *src++; 58             i += 4; 59         } 60     } 61     else 62     { 63         nand_init_ll(); 64         nand_read_ll((unsigned int)src, (unsigned char *)dest, len); 65     } 66 } 67  68 void clear_bss(void) 69 { 70     extern int __bss_start, _bss_end; 71     int *p = &__bss_start; 72      73     for (; p < &_bss_end; p++) 74         *p = 0; 75 } 76  77 static void nand_select(void) 78 { 79     NFCONT &= ~(1<<1);     80 } 81  82 static void nand_deselect(void) 83 { 84     NFCONT |= (1<<1);     85 } 86  87 static void nand_cmd(unsigned char cmd) 88 { 89     volatile int i; 90     NFCMMD = cmd; 91     for (i = 0; i < 10; i++); 92 } 93  94 static void nand_addr_byte(unsigned char addr) 95 { 96     volatile int i; 97      98     NFADDR = addr; 99     for (i = 0; i < 10; i++);    100 }101 102 static void nand_wait_ready(void)103 {104     while (!(NFSTAT & 1));105 }106 107 static unsigned char nand_r_data(void)108 {109     return NFDATA;110 }111 112 void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)113 {114     int i = 0;115     unsigned int page = addr/2048;116     unsigned int col = addr&(2048-1);117         118     /* 1. 选中 */119     nand_select();120 121     while (i < len)122     {123         /* 2. 发出读命令00h */124         nand_cmd(0x00);125 126         /* 3. 发出地址(分5步发出) */127         nand_addr_byte(col&0xff);128         nand_addr_byte((col>>8)&0xff);129 130         nand_addr_byte(page&0xff);131         nand_addr_byte((page>>8)&0xff);132         nand_addr_byte((page>>16)&0xff);133 134         /* 4. 发出读命令30h */135         nand_cmd(0x30);136 137         /* 5. 判断状态 */138         nand_wait_ready();139 140         /* 6. 读数据 */141         for (; (col < 2048) && (i < len); col++)142         {143             buf[i++] = nand_r_data();144         }145         if(i==len)146             break;147         148         col = 0;149         page++;150     }151 152     /* 7. 取消选中 */        153     nand_deselect();154 }

在 board/samsung/jz2440/Makefile 中增加对 nand_read_ll.c 文件的编译支持(红色部分为修改代码):

COBJS    := jz2440.oCOBJS    += nand_read_ll.oSOBJS    := lowlevel_init.o

 

 2),修改 include/configs/jz2440.h 文件

查找 CONFIG_SYS_TEXT_BASE 将其值改为:

#define CONFIG_SYS_TEXT_BASE    0x33f00000

 

 0x33f00000是 uboot 重定位之后的地址,从0x33f00000到0x34000000,给uboot预留了1M的存储空间

3),修改 arch/arm/lib/crt0.S 文件

从之前的 arch/arm/cpu/arm920t/start.S 文件知道,程序最后会跳到 _main 处,如下所示:

而 _main 的入口在 crt0.S 中,调用 C 函数也是在 crt0.S 中,因此我们需要修改 crt0.S 文件,修改代码如下(红色为修改部分,蓝色部分为删除代码):

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)    ldr    sp, =(CONFIG_SPL_STACK)#else    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)#endif    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */    sub    sp, #GD_SIZE    /* allocate one GD above SP */    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */    mov    r9, sp        /* GD is above SP */

 

__TEXT_BASE:   .word CONFIG_SYS_TEXT_BASE     mov r0,#0                   //r0对应第一个参数:源地址    ldr r1,__TEXT_BASE          //_TEXT_BASE : 0x33f00000:目的地址    ldr r2,__bss_start         // __bss_start - _start   (有效代码大小)    sub r2, r2, r1    bl copy_code_to_sdram     //该函数首先会初始化nand控制器,然后复制代码到SDRAM连接地址dest上    bl clear_bss              //清除bss段        ldr pc,    =call_board_init_f        //绝对跳转,跳到SDRAM中执行call_board_init_f:    mov    r0, #0    bl board_init_f    ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */    bic sp, sp, #7    /* 8-byte alignment for ABI compliance */    ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */    sub r9, r9, #GD_SIZE        /* new GD is below bd */    ldr    r1, __TEXT_BASE            /* dest_addr */    //第二个参数目的地址    /* call board_init_r */    bl board_init_r                /* 进入第二阶段 */    #if ! defined(CONFIG_SPL_BUILD)/* * Set up intermediate environment (new sp and gd) and call * relocate_code(addr_moni). Trick here is that we'll return * 'here' but relocated. */    ldr    sp, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp */    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */    ldr    r9, [r9, #GD_BD]        /* r9 = gd->bd */    sub    r9, r9, #GD_SIZE        /* new GD is below bd */    adr    lr, here    ldr    r0, [r9, #GD_RELOC_OFF]        /* r0 = gd->reloc_off */    add    lr, lr, r0    ldr    r0, [r9, #GD_RELOCADDR]        /* r0 = gd->relocaddr */    b    relocate_codehere:/* Set up final (full) environment */    bl    c_runtime_cpu_setup    /* we still call old routine here */    ldr    r0, =__bss_start    /* this is auto-relocated! */    ldr    r1, =__bss_end        /* this is auto-relocated! */    mov    r2, #0x00000000        /* prepare zero to clear BSS */clbss_l:cmp    r0, r1            /* while not at end of BSS */    strlo    r2, [r0]        /* clear 32-bit BSS word */    addlo    r0, r0, #4        /* move to next */    blo    clbss_l    bl coloured_LED_init    bl red_led_on    /* call board_init_r(gd_t *id, ulong dest_addr) */    mov     r0, r9                  /* gd_t */    ldr    r1, [r9, #GD_RELOCADDR]    /* dest_addr */    /* call board_init_r */    ldr    pc, =board_init_r    /* this is auto-relocated! */    /* we should not return here. */#endif

(PS:上述修改文件中用 __TEXT_BASE 代替 CONFIG_SYS_TEXT_BASE 宏,是因为__TEXT_BASE 定义在前,而宏是在 jz2440.h 文件中定义,为了让代码编译靠前) 

!!!__TEXT_BASE  不能用start.S 中的 _TEXT_BASE 代替!!!

4),修改 arch/arm/lib/board.c 里的 board_init_f 函数(红色部分为修改代码) :

/*     * reserve memory for U-Boot code, data & bss     * round down to next 4 kB limit     */    //addr -= gd->mon_len;    addr = CONFIG_SYS_TEXT_BASE;    addr &= ~(4096 - 1);    debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
unsigned int board_init_f(ulong bootflag)
memcpy(id, (void *)gd, sizeof(gd_t));    return ((unsigned int)id);    //将id传给 board_init_r

addr 就是目的地址,因此需要修改为 0x33f00000,如果不修改,原先的栈就会被覆盖,导致代码死掉 

修改 include/common.h 中对 board_init_f 的声明(红色部分为修改代码):

/* arch/$(ARCH)/lib/board.c */unsigned int    board_init_f(ulong);

 

5),修改链接脚本 u-boot.lds(arch/arm/cpu目录下)

修改 u-boot.lds 将 nand_read_ll.c(实现代码拷贝,代码重定位) lowlevel.S(初始化ADRAM) 放在前面编译,修改如下,红色部分为修改代码:

. = ALIGN(4);    .text :    {        *(.__image_copy_start)        CPUDIR/start.o (.text*)        board/samsung/jz2440/lowlevel.o (.text*)        board/samsung/jz2440/nand_read_ll.o (.text*)        *(.text*)    }

 

修改完毕,编译,出现如下错误:

输入命令 grep "R_ARM_RELATIVE" * -nR 进行搜索,发现 Makefile 中有一个检查重定位的规则,屏蔽该规则,代码如下(红色为修改部分):

# ARM relocations should all be R_ARM_RELATIVE.checkarmreloc: $(obj)u-boot#    @if test "R_ARM_RELATIVE" != \        "`$(CROSS_COMPILE)readelf -r $< | cut -d ' ' -f 4 | grep R_ARM | sort -u`"; \        then echo "$< contains relocations other than \        R_ARM_RELATIVE"; false; fi

再次编译,成功,进行烧写(可以先把旧的u-boot.bin烧写到norflash,然后通过旧的uboot把新的uboot烧写到nand flash),得到如下界面,表示启动成功

到此,我们的代码已经支持NOR启动,NAND启动了!

 

转载于:https://www.cnblogs.com/zhyy-mango/p/9451821.html

你可能感兴趣的文章
五个免费的轻量级Linux发行版
查看>>
C# GDI+绘制矩形圆角
查看>>
C# DataTable常用操作总结 (转载)
查看>>
还原virtual函数的本质-----C++
查看>>
《GK101任意波发生器》升级固件发布(版本:1.0.2build306)
查看>>
hug and Compression Resistance
查看>>
sql server 2008分页
查看>>
lintcode:Pow(x, n)
查看>>
WebService中使用Aspose.Cells.dll
查看>>
Android菜鸟的成长笔记(28)——Google官方对Andoird 2.x提供的ActionBar支持
查看>>
【转载】装饰模式与代理模式的区别
查看>>
Persona——Web人物角色介绍
查看>>
一个三年工作经验的软件工程师的经验之谈
查看>>
Keepalived+Redis高可用部署(第二版)
查看>>
理解Linux中断 (3)【转】
查看>>
3 hql语法及自定义函数(含array、map讲解) + hive的java api
查看>>
欢迎各位技术牛人增加Swift QQ群:343549891
查看>>
Linux使用imagemagick的convert命令压缩图片、节省服务器空间
查看>>
selenium测试(Java)-- 显式等待(九)
查看>>
MySQL 5.7 mysqlpump 备份工具说明
查看>>