u-boot2010.03 移植篇(二)-----修改start.S,支持nand启动

2024-02-26 02:58

本文主要是介绍u-boot2010.03 移植篇(二)-----修改start.S,支持nand启动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面开始 移植篇(二)-----修改start.S,支持nand启动
----------------------------------------------------------
使用环境
PC:     ubuntu 11.04
kernel: 2.6.32-28-generic
corss:  arm-linux-gcc 4.3.2
arm:    s3c6410
uboot:  uboot-2010-03
----------------------------------------------------------

一切版权均有作者所有,欢迎转载,请指明出处,如何修改请与本人联系,谢谢


uboot的第一阶段,其实做的事情也是比较多的,,但是一般来说,重点就是配置各种硬件环境,来保证第二阶段能正常启动.
而该部分根据不同的硬件也是不同的..像我的,s3c6410有2片dram,和一片nand..所以我为了保证我的代码能正常执行,
我必须得把代码搬移到内存里面去.不然代码在nand中也没法执行...但是为什么代码在nand中不能执行呢?其中一个比较
重要的原因就是nand并不是挂在CPU总线上面的,而是采用专门的硬件处理单元来控制的...nand控制器.
在你不添加任何代码的情况下,是不能控制外围的nand芯片的...但是怎么办.cpu内根本没有代码,怎么才能读取nand中的
代码到内存中去呢?没错-----s3c6410在启动的时候会帮我们以nand的最基本的时序.搬移nand中的前8K代码,到stepping
这样就可以执行了.而uboot的代码远比这个大..以至于我们得紧靠这部分代码,来完成剩下的代码部分的搬移....

今天的重点就是这个了.主要是来完成nand中剩余部分的uboot搬移到ram中,以便uboot能正常启动起来....好了.直接开始..

首先,你得有smdk6410_config 编译目标,不然怎么开始.....此处省略N字...请看我的移植篇第一篇...

下面开始.打开start.S (cpu/arm1176/start.S)和smdk6410.h (include/configs/smdk6410.h)
我们得一边参看头文件中的配置,一边修改代码,来达到我们的目的..
start.S 中,最开始就是一段啥?异常向量表,此处忽略,请参考分析篇中对start.S的分析

前面一部分是MMU啥的...直接招待after_copy:这个标签
什么?之前没有任何copy的东西???怎么有after_copy一说呢?
没错..所以我们得把copy代码添加在这里..从nand中把数据搬移出来,放到这之前完成,这样才对得起这个after_copy的标签
说干就干,这里我是调用的C代码,你也可以用汇编来完成的,只要功能一样就行了

这里我们得向我们的配置头文件内添加一个宏,就是 #define CONFIG_NAND_BOOT
接着,我们要去添加我们要调用的copy_from_nand

[cpp] plain copy
  1. *   
  2.  * copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)   
  3.  * r0: size to be compared   
  4.  * Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size   
  5.  *///   
  6. .globl copy_from_nand   
  7.     
  8. copy_from_nand:   
  9.     mov r10, lr                     /* save return address */  
  10.       
  11.     mov r9, r0   
  12.     /* get ready to call C functions */    
  13.     ldr sp, _TEXT_PHY_BASE          /* setup temp stack pointer */  
  14.     sub sp, sp, #12   
  15.     mov fp, #0                      /* no previous frame, so fp=0 */  
  16.     mov r9, #0x1000   
  17.     bl  copy_uboot_to_ram           /* 此函数需要添加,稍后说明。 */  
  18. 3:  tst r0, #0x0                      
  19.     bne copy_failed                 /* 判断返回值是否失败 */  
  20.     ldr r0, =0x0c000000             /* 判断内容是否一致 */  
  21.     ldr r1, _TEXT_PHY_BASE   
  22. 1:  ldr r3, [r0], #4   
  23.     ldr r4, [r1], #4   
  24.     teq r3, r4   
  25.     bne compare_failed              /* not matched */  
  26.     subs r9, r9, #4   
  27.     bne 1b   
  28. 4:  mov lr, r10                     /* all is OK */  
  29.     mov pc, lr   
  30.       
  31. copy_failed:   
  32.     nop                             /* copy from nand failed */  
  33.     b copy_failed   
  34.       
  35. compare_failed:   
  36.     nop                             /* compare failed */  
  37.     b compare_failed  

在这段代码里面,就是调整了下sp,为了能调用c函数 copy_uboot_to_ram,那么重点就是这个函数了..这个函数在nand_cp.c中.

<Ps:这个错误由以为网友提出,在此表示感谢....希望更多的网友能够支持.谢谢>

这个文件比较大,分析篇我会重点分析,究竟nand是如何搬移数据的.这里我们只要复制下好了...

[cpp] plain copy
  1. #include <common.h>  
  2. #ifdef CONFIG_S3C64XX  
  3. #include <asm/io.h>  
  4. #include <linux/mtd/nand.h>  
  5. #include <asm/arch/s3c6400.h>  
  6.   
  7. static int nandll_read_page(uchar * buf, ulong addr, int large_block)  
  8. {  
  9.     int i;  
  10.     int page_size = 512;  
  11.   
  12.     if (large_block == 1)  
  13.         page_size = 2048;  
  14.     if (large_block == 2)  
  15.         page_size = 4096;  
  16.   
  17.     NAND_ENABLE_CE();  
  18.   
  19.     NFCMD_REG = NAND_CMD_READ0;  
  20.   
  21.     /* Write Address */  
  22.     NFADDR_REG = 0;  
  23.   
  24.     if (large_block)  
  25.         NFADDR_REG = 0;  
  26.   
  27.     NFADDR_REG = (addr) & 0xff;  
  28.     NFADDR_REG = (addr >> 8) & 0xff;  
  29.     NFADDR_REG = (addr >> 16) & 0xff;  
  30.   
  31.     if (large_block)  
  32.         NFCMD_REG = NAND_CMD_READSTART;  
  33.   
  34.     NF_TRANSRnB();  
  35.   
  36.     /* for compatibility(2460). u32 cannot be used. by scsuh */  
  37.     for (i = 0; i < page_size; i++) {  
  38.         *buf++ = NFDATA8_REG;  
  39.     }  
  40.   
  41.     NAND_DISABLE_CE();  
  42.     return 0;  
  43. }  
  44.   
  45. static int nandll_read_blocks(ulong dst_addr, ulong size, int large_block)  
  46. {  
  47.     uchar *buf = (uchar *) dst_addr;  
  48.     int i;  
  49.     uint page_shift = 9;  
  50.   
  51.     if (large_block == 1)  
  52.         page_shift = 11;  
  53.   
  54.     /* Read pages */  
  55.     if (large_block == 2)  
  56.         page_shift = 12;  
  57.   
  58.     if (large_block == 2) {  
  59.         /* Read pages */  
  60.         for (i = 0; i < 4; i++, buf += (1 << (page_shift - 1))) {  
  61.             nandll_read_page(buf, i, large_block);  
  62.         }  
  63.         /* Read pages */  
  64.         for (i = 4; i < (0x60000 >> page_shift);i++, buf += (1 << page_shift)) {  
  65.             nandll_read_page(buf, i, large_block);  
  66.         }  
  67.     } else {  
  68.         for (i = 0; i < (0x60000 >> page_shift);i++, buf += (1 << page_shift)) {  
  69.             nandll_read_page(buf, i, large_block);  
  70.         }  
  71.     }  
  72.   
  73.     return 0;  
  74. }  
  75.   
  76. int copy_uboot_to_ram(void)  
  77. {  
  78.     int large_block = 0;  
  79.     int i;  
  80.     vu_char id;  
  81.   
  82.     NAND_ENABLE_CE();  
  83.     NFCMD_REG = NAND_CMD_READID;  
  84.     NFADDR_REG = 0x00;  
  85.   
  86.     /* wait for a while */  
  87.     for (i = 0; i < 200; i++) ;  
  88.         id = NFDATA8_REG;  
  89.     id = NFDATA8_REG;  
  90.   
  91.     if (id > 0x80)  
  92.         large_block = 1;  
  93.     if (id == 0xd5)  
  94.         large_block = 2;  
  95.   
  96.     /* read NAND Block. 
  97.      * 128KB ->240KB because of U-Boot size increase. by scsuh 
  98.      * So, read 0x3c000 bytes not 0x20000(128KB). 
  99.      */  
  100.     return nandll_read_blocks(CONFIG_SYS_PHY_UBOOT_BASE, 0x60000,large_block);  
  101. }  
  102.   
  103. #endif  
然后修改 Makefile 把我们的 nand_cp.c添加到 uboot中去编译

最后 make下.你会发现.编译好了....编译器记得重新 make smdk6410_config下.因为我们修改了头文件,需要重新生成 .mk文件

今天的任务基本完成了,今天比较轻松,接着我们稍微修改下 smdk6410.h中的配置.
主要是改几个名字,把什么 6400的改成 6410就好了..
没错,你只要查找替换就行了...因为我们现在编译的已经是 6410了.不是 6400了...

修改完之后,有一个地方得稍微改下.
cpu/arm1176/s3c64xx/Makefile

6400改成 64XX因为,我们的配置文件里面已经没有 6400了....
这个请查看头文件中的配置定义...


继续修改此篇:

到此眼看就已经结束了...好了,make吧....啥有一个错误,天哪....

[cpp] plain copy
  1. arm-linux-gcc -E -g  -Os   -fno-common -ffixed-r8 -msoft-float  -fno-common -ffixed-r8 -msoft-float  -D__KERNEL__ -DTEXT_BASE=0   
  2. -I/media/LvApp/u-boot-2010.03/include -fno-builtin -ffreestanding -nostdinc -isystem   
  3. /usr/local/arm/4.4.1/bin/../lib/gcc/arm-none-linux-gnueabi/4.4.1/include -pipe  -DCONFIG_ARM -D__ARM__   
  4. -marm  -mabi=aapcs-linux -mno-thumb-interwork -march=armv5t -march=armv5t  -ansi -D__ASSEMBLY__   
  5. -P - </media/LvApp/u-boot-2010.03/nand_spl/board/samsung/smdk6410/u-boot.lds >/media/LvApp/u-boot-2010.03/nand_spl/u-boot.lds  
  6. cd /media/LvApp/u-boot-2010.03/nand_spl/board/samsung/smdk6410 && arm-linux-ld -Bstatic -T   
  7. /media/LvApp/u-boot-2010.03/nand_spl/u-boot.lds -Ttext 0  start.o cpu_init.o lowlevel_init.o nand_boot.o nand_ecc.o s3c64xx.o \  
  8.         -Map /media/LvApp/u-boot-2010.03/nand_spl/u-boot-spl.map \  
  9.         -o /media/LvApp/u-boot-2010.03/nand_spl/u-boot-spl  
  10. start.o: In function `copy_from_nand':  
  11. /media/LvApp/u-boot-2010.03/nand_spl/board/samsung/smdk6410/start.S:302: undefined reference to `copy_uboot_to_ram'  
  12. make[1]: *** [/media/LvApp/u-boot-2010.03/nand_spl/u-boot-spl] Error 1  
  13. make[1]: Leaving directory `/media/LvApp/u-boot-2010.03/nand_spl/board/samsung/smdk6410'  
  14. make: *** [nand_spl] Error 2  
别急别急,,,小错而已..是吧....我们仔细查看,这是一个链接错误,为嘛会链接出错了..在此看到有这一行

start.o cpu_init.o lowlevel_init.o nand_boot.o nand_ecc.o s3c64xx.o

看到这一行,内心就暗自偷笑下吧..找到问题所在了...为啥?copy_uboot_to_ram这个函数不就是在start.o中内调用的嘛...所以这里没有nand_cp.o被链接进来,铁定

链接错误的...那要怎么改..直接定位到这个错误的目录下u-boot-2010.03/nand_spl/board/samsung/smdk6410修改该目录下Makefile 添加如下所示:

[cpp] plain copy
  1. COBJS   = nand_boot.o nand_ecc.o s3c64xx.o nand_cp.o 后面得加上nand_cp.o  

接着我们得模仿后面的写法,为nand_cp.o添加目标生成方法

[cpp] plain copy
  1. # from SoC directory  
  2. $(obj)cpu_init.S:  
  3.     @rm -f $@  
  4.     @ln -s $(TOPDIR)/cpu/arm1176/s3c64xx/cpu_init.S $@  
  5.   
  6.   
  7. $(obj)nand_cp.c:  
  8.     @rm -f $@  
  9.     @ln -s $(TOPDIR)/cpu/arm1176/nand_cp.c $@  

至此,,编译应该就没有问题啦....


难不成这就行了???你下载进去试试不就知道了...

不行?运行不了?为什么呢....首先我们分析下,启动的过程...arm上电之后开始0地址指令..0地址的指令(此处假设时钟是nand启动,,这里就是讨论这个问题)是由arm自主加载的..从nand

的前8k,那么前8K的代码也就是0---0x2000 的这一段了..在start.S 这个文件,我们都知道是第一条指令的位置,那么这个文件就必须要被拷贝到0地址对应起来咯...这样才能被正常执行.

这些是不是都同意呢?不同意....咱们私下讨论.联系我...同意的,咱们继续.往下分析

既然知道了start.s为开始的地方,那么这里面也是第一部分的引导代码,而大家都知道第一部分的代码其实不全的,,,启动部分只有一下部分被arm搬移,剩余的大部分其实还在nand中..

那么既然不全,也就是跳转啊,函数调用啊...都必须在0---0x2000 的位置内才能到访问到.而且还不能是跟符号相关的跳转.因为符号跳转是根据链接地址跳转的..链接地址大家应该都知道

是被链接到一个很高的内存地址处去了...0x5e000啥的那个地址...

继续啊...不能符号跳转,就必须是相对跳转了...只要保证第一部分中所有的函数调用,符号跳转都在0---0x2000中,那就没问题,正常执行....为此,我们看一下u-boot.map这个文件.发现一个问题

[cpp] plain copy
  1. Linker script and memory map  
  2.   
  3.   
  4.                 0x00000000                . = 0x0  
  5.                 0x00000000                . = ALIGN (0x4)  
  6.   
  7.   
  8. .text           0x57e00000    0x262a4  
  9.  cpu/arm1176/start.o(.text)  
  10.  .text          0x57e00000      0x440 cpu/arm1176/start.o  
  11.                 0x57e00000                _start  
  12.                 0x57e00040                _end_vect  
  13.                 0x57e00048                _armboot_start  
  14.                 0x57e0004c                _bss_start  
  15.                 0x57e00050                _bss_end  
  16.                 0x57e0010c                copy_from_nand  
  17.  cpu/arm1176/s3c64xx/cpu_init.o(.text)  
  18.  .text          0x57e00440      0x124 cpu/arm1176/s3c64xx/cpu_init.o  
  19.                 0x57e00440                mem_ctrl_asm_init  
我们只看一小部分了....在这里我们看到_start符号地址正好是那个指定的链接地址..也就是代码的起始符号...地址很高..无所谓啦...我们看看start.S中都有哪些符号的调用吧..这里直接看这个符号吧
[cpp] plain copy
  1. .text          0x57e1c268      0x1fc board/samsung/smdk6410/libsmdk6410.a(lowlevel_init.o)  
  2.                 0x57e1c26c                lowlevel_init  
这个符号其实在strat.S中是要使用的,,那么在仔细一看这个地址挺高的,,,好像不在前8k中是吧...那么在执行的时候就找不到这个符号的代码了...

问题就是在这,,得确保第一部分需要用到的代码能被arm加载进前8k就好了....那就得需要告诉连接器,,你...就你..帮我把这个链接到前面去.别放后面...不然打你...

链接器就会帮你乖乖的链接上去了...至于链接怎么听话,那就得使用链接听得懂的话了...链接脚本....使用哪个链接脚本..自己看我前面的分析文档吧....

[cpp] plain copy
  1. cpu/arm1176/u-boot.lds  
  2. SECTIONS  
  3. {  
  4.     . = 0x00000000;  
  5.   
  6.   
  7.     . = ALIGN(4);  
  8.     .text :  
  9.     {  
  10.         cpu/arm1176/start.o (.text)  
  11.         board/samsung/smdk6410/lowlevel_init.o (.text)  
  12.         cpu/arm1176/s3c64xx/cpu_init.o (.text)  
  13.         cpu/arm1176/nand_cp.o   (.text)  
  14.         *(.text)  
  15.     }  
  16. 只列出了被修改的部分...  

还有另外一个文件
[cpp] plain copy
  1. board/samsung/smdk6410/u-boot-nand.lds  
  2. SECTIONS  
  3. {  
  4.     . = 0x00000000;  
  5.   
  6.   
  7.     . = ALIGN(4);  
  8.     .text      :  
  9.     {  
  10.       cpu/arm1176/start.o   (.text)  
  11.       cpu/arm1176/s3c64xx/cpu_init.o    (.text)  
  12.       board/samsung/smdk6410/lowlevel_init.o (.text)  
  13.           cpu/arm1176/nand_cp.o   (.text)  
  14.       *(.text)  
  15.     }  

至此...最后看一下修改之后的u-boot.map
[cpp] plain copy
  1. Linker script and memory map  
  2.   
  3.   
  4.                 0x00000000                . = 0x0  
  5.                 0x00000000                . = ALIGN (0x4)  
  6.   
  7.   
  8. .text           0x57e00000    0x262a4  
  9.  cpu/arm1176/start.o(.text)  
  10.  .text          0x57e00000      0x440 cpu/arm1176/start.o  
  11.                 0x57e00000                _start  
  12.                 0x57e00040                _end_vect  
  13.                 0x57e00048                _armboot_start  
  14.                 0x57e0004c                _bss_start  
  15.                 0x57e00050                _bss_end  
  16.                 0x57e0010c                copy_from_nand  
  17.  cpu/arm1176/s3c64xx/cpu_init.o(.text)  
  18.  .text          0x57e00440      0x124 cpu/arm1176/s3c64xx/cpu_init.o  
  19.                 0x57e00440                mem_ctrl_asm_init  
  20.  board/samsung/smdk6410/lowlevel_init.o(.text)  
  21.  .text          0x57e00564      0x1fc board/samsung/smdk6410/lowlevel_init.o  
  22.                 0x57e00568                lowlevel_init  
  23.  cpu/arm1176/nand_cp.o(.text)  
  24.  .text          0x57e00760      0x1b4 cpu/arm1176/nand_cp.o  
  25.                 0x57e00814                copy_uboot_to_ram  

好了.都到前面去了..真听话.....完了..就到这吧....


完了..今天就说这么多..特别简单..
Finish!
Thanks a lot~

这篇关于u-boot2010.03 移植篇(二)-----修改start.S,支持nand启动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/747519

相关文章

Redis在windows环境下如何启动

《Redis在windows环境下如何启动》:本文主要介绍Redis在windows环境下如何启动的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis在Windows环境下启动1.在redis的安装目录下2.输入·redis-server.exe

解决SpringBoot启动报错:Failed to load property source from location 'classpath:/application.yml'

《解决SpringBoot启动报错:Failedtoloadpropertysourcefromlocationclasspath:/application.yml问题》这篇文章主要介绍... 目录在启动SpringBoot项目时报如下错误原因可能是1.yml中语法错误2.yml文件格式是GBK总结在启动S

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

一文带你了解SpringBoot中启动参数的各种用法

《一文带你了解SpringBoot中启动参数的各种用法》在使用SpringBoot开发应用时,我们通常需要根据不同的环境或特定需求调整启动参数,那么,SpringBoot提供了哪些方式来配置这些启动参... 目录一、启动参数的常见传递方式二、通过命令行参数传递启动参数三、使用 application.pro

SpringBoot项目启动报错"找不到或无法加载主类"的解决方法

《SpringBoot项目启动报错找不到或无法加载主类的解决方法》在使用IntelliJIDEA开发基于SpringBoot框架的Java程序时,可能会出现找不到或无法加载主类com.example.... 目录一、问题描述二、排查过程三、解决方案一、问题描述在使用 IntelliJ IDEA 开发基于

Linux修改pip和conda缓存路径的几种方法

《Linux修改pip和conda缓存路径的几种方法》在Python生态中,pip和conda是两种常见的软件包管理工具,它们在安装、更新和卸载软件包时都会使用缓存来提高效率,适当地修改它们的缓存路径... 目录一、pip 和 conda 的缓存机制1. pip 的缓存机制默认缓存路径2. conda 的缓

Linux修改pip临时目录方法的详解

《Linux修改pip临时目录方法的详解》在Linux系统中,pip在安装Python包时会使用临时目录(TMPDIR),但默认的临时目录可能会受到存储空间不足或权限问题的影响,所以本文将详细介绍如何... 目录引言一、为什么要修改 pip 的临时目录?1. 解决存储空间不足的问题2. 解决权限问题3. 提