ecos ---- boot from nand

 

http://blog.chinaunix.net/u3/91016/showart_1785134.html

Boot from NAND (一)
eCos,是个新手;我也是个新手;不过我喜欢新的东西,当然是在IT世界!
前不久弄到了一块阳初的S3C2410开发板,总算可以对eCos进行感性认识了。都说接触eCos最好的入门方法就是RedBoot,自然从安装RedBoot开始了!
其实阳初的s3c2410开发板和三星的SMDK2410几乎是一致的,想当然的认为感性认识马上就可以开始,然而事实总是残酷的!配置 SMDK2410的Redboot,选择启动方式,RAM、ROM、ROMRAM,which one should i choose? 答案却是none!才发现CPU核心板上有一块空白,本应该是一块NOR Flash的地盘...一切变得复杂起来了...
问题已经出来了,如何从NAND Flash启动Redboot?google,baidu,回答了如何从NAND启动vivi,u-boot等等...;查阅了s3c2410的资料,当 CPU配置从NAND启动时,其硬件逻辑会将4K的代码从NAND中拷贝到CPU内部的SRAM中进行执行,那么也就是说在这4K代码中必须实现将所有代 码拷贝到内存(SDRAM)中的工作。
从网上可以找到实现这些拷贝工作的代码,我从vivi中找到了这一段...
首先分析了一下Redboot启动代码的调用过程,先是Redboot目录下的Vectors.S文件,如果设置启动模式为ROM或 ROMRAM的话,则在reset_vector的一开始会执行PLATFORM_SETUP1宏,这个宏的实现在hal/arm/arm9 /smdk2410/current/include/hal_platform_setup.h文件中进行了实现,其主要工作就是关闭 WatchDog、Interrupt、cache,然后设置PLL即CPU的倍频,初始化内存管理的每个Bank的访问设置,即B0~7_BWSCON 的设置(包括访问位宽、WAIT方式和UBLB等),随后进行的是mmu的初始化;如果是ROMRAM的启动方式的话,在这里就会实现将整个 Redboot代码拷贝到SDRAM的程序。
显然,从Redboot的体系结构出发,由于hal_platform_setup.h是和平台相关的实现,那么将NAND启动时的拷贝代码放 到这里则是更加合理的,因此将从vivi中抽出来的这一段代码放到了这个代码段中。一开始不是很熟悉CDL语言,因此没有想修改这一部分的脚本,就将 ROMRAM的拷贝代码用vivi中的代码替换掉了。很显然这是个错误的决定,启动没有成功。
又花了几天的功夫熟悉了CDL语言以及配置脚本的结构,在hal/arm/arm9/smdk2410/current/cdl/目录下的 hal_arm_arm9_smdk2410.cdl文件中找到了cdl_component CYG_HAL_STARTUP的设置,在"ROMRAM"的后面加上了一个"NAND"选项,对应于宏CYG_HAL_STARTUP_NAND。这样 就可以选择启动模式为NAND了!
回到hal_platform_setup.h中,就可以在其中加入NAND启动的代码:
#ifdef CYG_HAL_STARTUP_NAND
       /**************************/
       /*   My NAND BOOT CODE    */  
       /**************************/
#endif
经过这一折腾,自我感觉也还不错,总算对于Redboot的体系结构有了一些了解,对于CDL脚本的构成和语法也熟悉了一些,作为接触eCos的第一步,至少有了一些认识...
当然,事情总是没有那么顺利的,Redboot仍然是启动不了的,只有继续再往下走了...待续...
Boot from NAND (二)
先来看看从NAND读取RedBoot到SDRAM的代码:
 

#ifdef CYG_HAL_STARTUP_NAND
                // reset NAND
                mov      r1, #NAND_CTL_BASE
                ldr     r2, = 0xf830          // initial value
                str      r2, [ r1, #oNFCONF]
                ldr     r2, [ r1, #oNFCONF]
                bic     r2, r2, #0x800       // enable chip
                str      r2, [ r1, #oNFCONF]
                mov      r2, #0xff            // RESET command
                strb    r2, [ r1, #oNFCMD]
                mov      r3, #0               // wait
1:               add      r3, r3, #0x1
                cmp      r3, #0xa
                blt     1b
2:               ldr     r2, [ r1, #oNFSTAT]        // wait ready
                tst     r2, #0x1
                beq     2b
                ldr     r2, [ r1, #oNFCONF]
                orr     r2, r2, #0x800           // disable chip
                str      r2, [ r1, #oNFCONF]
                    
                // copy redboot to RAM                            
                // Set up a stack [ for calling C code]
                ldr     r1, = __startup_stack
                ldr     r2, = LEO2410_SDRAM_PHYS_BASE
                orr     sp, r1, r2
        
                ldr     r2, = __rom_data_end
                ldr     r0, = __exception_handlers                
                sub      r2, r2, r0
                ldr     r0, = __exception_handlers
                ldr     r1, = LEO2410_SDRAM_PHYS_BASE
                orr     r0, r0, r1
                mov      r1, # 0x0                
                bl       nand_read_ll        
                teq     r0, #0x0
                beq     ok_nand_read            
1:               b       1b        // infinite loop
            
ok_nand_read:         
                // verify            
                mov      r0, #0
                ldr     r1, = __exception_handlers
                ldr     r2, = LEO2410_SDRAM_PHYS_BASE
                orr     r1, r1, r2
                mov      r2, #0x400      // 4 bytes * 1024 = 4K- bytes
go_next:
                ldr     r3, [ r0] , #4
                ldr     r4, [ r1] , #4
                teq     r3, r4
                bne     notmatch
                subs    r2, r2, #4
                beq     done_nand_read    
                bne     go_next
notmatch:
1:               b       1b        
done_nand_read:     
                // jump to ram
                ldr     r1, = on_the_ram
                ldr     r2, = LEO2410_SDRAM_PHYS_BASE
                add      pc, r1, r2
                nop
                nop
1:               b       1b         // infinite loop
on_the_ram:         
#endif /* CYG_HAL_STARTUP_NAND * /

这一段代码其实并不复杂,主要做了三个方面的事情。第一:初始化S3C2410的NAND控制器,以便用于读取NAND中的RedBoot代码;第 二:初始化C函数调用堆栈地址,设置好NAND读取函数的入口参数并调用该函数;第三:将读取到SDRAM的RedBoot代码段的前4k和位于SRAM 中的代码进行比较,确定读取过程是正确的,然后将PC跳转到SDRAM的相应位置进行执行!

仔细分析了代码,实在没有看到什么地方有问题。比较了s3c2410的文档,NAND控制器的设置也没有错误,SDRAM地址和NAND地址参数的 设置也没有错(其中LEO2410_SDRAM_PHY_BASE的值为0x30000000,这是因为SDRAM是使用的BANK6、7)。但是为什么 会无法启动呢?(另外,在这里出现的LEO2410_SDRAM_PHY_BASE,实际上对应于SMDK2410模板应该是 SMDK2410_SDRAM_PHY_BASE,只是我在移植时新建了一个叫leo2410的模板,从而改的新名字,呵呵)

没有办法,只好step in了。一开始还真不知道该怎么来调试,是不是需要去弄个ICE来,那可要投资一大笔了...。突然想起不是有JTAG线吗,摸索了一下直接使用 AxD+H-JTAG就可以完成调试了,呵呵!在网上找了一下,对于阳初的开发板,H-JTAG的设置为:

 TMS Pin4  D2
 TCK Pin2  D0
 TDI Pin3  D1
 TDO Pin11 Busy
 nTRST NO TAP RST
 nSRST NO SYS RST
连上开发板,直接将PC的值设置为0,就可以单步调试了。跟踪到bl nand_read_ll,单步执行就发现程序跑掉了,全是乱指令。问题就在这里,但是为什么会这样呢?其实非常简单,突然间想起了现在的执行过程是在SRAM中进行的,而SRAM只拷贝了4K的代码,而非常不幸的是nand_read_ll函数并没有在这4k代码中。
这太让人头痛了,如何让nand_read_ll进入到前4k代码呢?想过直接将nand_read_ll 函数写成汇编的宏放进hal_platform_setup.h中,不过把这段代码写成汇编也比较麻烦,而且不是很符合这样的结构。没有办法,只好研究一 下RedBoot的编译过程,查看Makefile了。eCos的目录结构也比较繁杂,而且每个模块下几乎都有一个Makefile,一层层的看太费力 了,所以比较方便的办法是直接对configurtool中打印出来的Make信息进行分析。
根据分析结果,RedBoot的链接顺序是:Vectors.o、extras.o、 libtarget.a...等,Vectors.o是直接由Vectors.S编译来的,而extras.o是最靠前的目标文件,它是由 libextras.a生成的。显然,将nand_read_ll放到extras.o库中是最合理和可靠的。研究了libextras.a的编译顺序, 发现合并是放到最前面的是ConfigureTool中选项RedBoot for ARM Option下面的配置项所对应的c文件,如redboot_linux_exec.c文件。于是就想到将nand_read_ll函数的实现所在的c文 件(nand_read.c)设置到该选项下面,这样应该就可以保证其位置处于4k代码之内了!说干就干,在hal/arm/arch/current /cdl/hal_arm.cdl中加入以下脚本:
 

cdl_option CYGPKG_REDBOOT_NAND_READ {
    display      "Provide the nand flash device read command"
    flavor       bool
    calculated   { CYG_HAL_STARTUP = = "NAND" ? 1: 0}
    description  "
                 This option contains the code which impliment the command for nand flash reading. It is useful to boot redboot from nand device. The option is enabled/disabled from RedBoots CDL."

    compile - library= libextras. a nand_read. c
    }

这一段脚本直接加到cdl_component CYGPKG_REDBOOT_ARM_OPTIONS脚本的里面,放到cdl_component CYGPKG_REDBOOT_ARM_LINUX_EXEC之前,就可以让编译链接时nand_read. c被编译到extras.o的最前面。

弄好之后,重新编译,下载...重启...太爽了,接上串口,终于看到了RedBoot的启动信息,以及 RedBoot>的提示符,至此,终于实现了从NAND启动RedBoot的任务,终于迎来了对RedBoot的第一次感性认识。接下来的工作,就 是一步一步的加入各个器件的驱动以及用RedBoot启动eCos或者linux了。

 

Boot from NAND 的一点补充
在说到调用nand_read_ll函数的时候,有一些曲折情况也没有说明,呵呵。当时对于参数的设置也是有过一些反复的,特别是对于拷贝的长 度参数r2的设置。最开始的时候是将这一段代码放到hal_mmu_init的后面进行的,那样传递的参数就应该是虚地址而不是物理地址。而且由于同样的 情况hal_mmu_init函数也没有在前4k代码段里面(如果在我就直接将nand_read_ll放到hal_mmu_init所在的文件了,呵 呵)。所以这样是一直没有调通的。
因此后来将nand_read_ll放到了hal_mmu_init的前面,这样就可以直接使用物理地址了。nand_read_ll的三个参 数分别为:r0,NAND内部的起始地址,当然是0了;r1,SDRAM的起始地址,则应该是SDRAM的物理地址,在代码段里就是 LEO2410_SDRAM_PHYS_BASE;第三个r2就是拷贝的长度,这一段需要知道RedBoot的实际长度,一开始不知道是怎么算的,就直接 给了个定长,当然也可以工作,但是总觉得别扭。不过参考一下ROMRAM启动方式下的代码就知道了,用__rom_data_end减去 __exception_handlers就得到了RedBoot的长度。这里面__exception_handlers就是RedBoot的起始段地 址,当然就是0了;而__rom_data_end则是最后一个段的结束地址,反映了RedBoot的最后一个字节的位置,这样就解决了参数设置的问题。 将RedBoot启动时显示的已使用内存的长度和编译得到的RedBoot.bin的长度进行比较就可以发现是相等的。
另外,在vivi的代码段里面,最后在设置pc的值以跳转到SDRAM中执行时,并没有
 

ldr         r2, = LEO2410_SDRAM_PHYS_BASE
add         pc, r1, r2

这两句,而是直接将on_the_ram标志的地址给了pc,但是在我们现在这中情况下是无法工作的,因为并没有启动mmu,所以必须将SDRAM的物理基址加上,才能跳转到正确的地方。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值