U-Boot从NAND Flash启动的实现
扫描二维码
随时随地手机看文章
摘要:U-Boot不能从NAND Flash启动给应用带来些不便,因此修改U-Boot使其支持从NAND Flash启动。分析了U-Boot启动流程的两个阶段及实现从NAND Flash启动的原理和思路,并根据NAND Flash的物理结构和存储特点,增加U-Boot对NAND Flash的操作支持,从而完成把存储在NAND Flash上的U-Boot代码复制到SDRAM中执行,实现从NAND Flash的启动。修改过后的U-Boot可以直接从NAND Flash启动,给应用带来便利。
关键词:U-Boot;NAND Flash;Boofloader;S3C2440;移植
Bootloader引导装载程序是系统上电后运行的第一段程序,其作用是完成基本的硬件初始化工作,所以引导装载程序跟硬件有着紧密的联系。因此必须根据开发板的硬件配置对引导装载程序进行修改才可以使其运行起来。随着嵌入式系统的复杂化,大容量数据存储的NAND Flash的应用会越来越广泛,同时U-Boot是功能最丰富的Bootloader,但遗憾的是U-Boot不支持从NAND Flash启动。所以如果能实现U-Boot从NAND Flash启动的话将会给应用带来很大的方便。本文讨论修改U-Boot使其支持从NAND Flash启动.采用基于S3C2440的开发板。
1 U-Boot简介及流程分析
U-Boot,全称universal boot loader,是遵循GPL条款的开放源代码项目。可以引导多种操作系统,支持多种架构的CPU。它支持如下操作系统:Linux、NetBSD、VxWorks等,支持如下架构的CPU:PowerPC、MIPS、X86、ARM、NIOS、XSeale等,同时支持NFS挂载,是一个功能丰富的BootLoader。它的整个程序框架清晰,易于移植,许多设计人员将自己的移植代码上传到网站(http://sourceforge.net/project-s/u-boot/) 上,更新速度很快。目前的版本是1.1.6,本论文正是采用此版本进行说明,U-Boot的目录结构参见U-Boot源代码。
要进行U-Boot的修改移植必须了解U-Boot的程序运行流程,这是必要的一步。U-Boot属于两阶段的BootLoader,其启动流程如图l所示。第一阶段的文件为cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S,用ARM汇编语言编写,前者是平台相关的,后者是开发板相关的。第一阶段主要是关于基本硬件的初始化,包括关闭MMU、CACHE、设置PLL时钟比例、关闭看门狗;初始化SDRAM,为复制第二阶段代码做准备,最后复制第二阶段代码到SDRAM中,然后跳到SDRAM中运行第二阶段。第二阶段代码都是用C语言编写的,功能更加复杂。主要是进一步初始化硬件设备、检测内存映射、复制内核镜像和根文件系统到SDRAM以及设置启动参数从而启动内核。[!--empirenews.page--]
2 支持NAND启动的代码修改
2.1 添加NAND Hash的初始化函数
U-Boot中关于NAND Hash的初始化流程如下:在上电后最先运行的汇编程序cpu\arm920t\start.S中调用start_armboot函数,而star-t_armboot该函数则调用了一系列的关于设备的初始化函数。这一系列的函数中包含一个名为nand_init的函数,nand_init就是完成NAND Ha-sh的初始化工作。
在1.1.6版本的U-Boot的include\linux\mtd\nand.h中定义了nand_chip结构体,该结构体中定义了关于NAND Hash操作的所有函数,包括读、写、ECC校验等,而这些函数在U-Boot中都有完整编写,只是有些个别函数需要根据自己的要求重新编写。而实现NAND Flash初始化的nand_init函数主要任务就是完成这些需要重新编写的函数和用这些函数连同U-Boot中其他默认函数来初始化nand_chip结构体。NAND-_init中的board_nand_init函数在U-Boot中并未实现,显然需要重新编写的函数就在其内添加。
先在cpu\arm920t\s3c24x0中添加nand.c文件,然后在该文件中实现所需要的初始化函数。一般只需要重新编写nand_ehip结构体中相对应的hweontrol、dev_ready和select_chip函数。这些函数的构建可参照linux内核2.6版本里的drivers\mtd\nand\s3e2410.e文件来进行编写,如内核文件中的s3c2440_nand_hwcontrol,s3c2440_nand_devready,s3c2410nand_select_chip函数,然后将其赋值给nand_chip结构体中对应的函数。
2.2 实现NAND启动
由于NAND的自身特点,对NAND Flash的操作不能像对NOR Flash那样方便地直接对地址进行操作,而是通过读写NAND Flash控制器的寄存器来完成。三星公司的S3C2440自带NAND Flash控制器,寄存器的地址是从nGCS4的地址开始。S3C2440处理器有NOR和NAND两种启动模式,当选择从NAND模式启动时,S3C2440会把NAND Hash的前4K数据搬运到内部称为Steppingstone的硬件中,同时把Steppingstone映射到地址0X00处,从而启动,启动完成后处理器会把Steppingstone释放掉以作为他用。U-Boot的一般大小都上100 K,远大于4 K,所以实现从NAND启动的原理就是让前4K代码完成基本初始化,重要的是把NAND Flash中的U-Boot代码复制到SDRAM中,从而跳到SDRAM中去执行。分析可知,S3C2440的该特点为U-Boot从NAND Flash启动提供了可能。本文讨论的实现思路就是依据此原理。
源代码中有/board/smdk2410/U-boot/lds,该文件是U-Boot代码的链接脚本,有如下代码:
可以看到Text段也就是程序代码段,被编译链接到OX00地址处,同时start.S编译后的目标文件start.O被放到text段的第一个文件处,所以start.S就是程序上电运行的第一段代码,而/cpu/arm920t/start.S这个汇编文件正是U-Boot的程序代码入口。因此代码修改和添加主要在start.S中完成,以此来保证NAND启动代码可以在最终程序编译链接所生成的文件的前4K内。
NAND Flash读写操作比较复杂,汇编实现较为麻烦,没有C语言简单容易,因此用C语言实现对NAND的操作复制工作,最后在start.S中调用编写的C程序即可。[!--empirenews.page--]
在/board/smdk2410/中添加boot_init.c文件,在其中实现nand_reset(nand重置函数)、wait_idle(等待即查询设备是否读写就位)、nand_select_chip(片选使能)、nand_dleselect_chip(取消片选)、write_cmd(写命令)、write_addr(写地址)、read_data(读数据)、nand_init(nand控制器初始化)这些子函数和copy2ram函数,同时在copy2ram中依据NAND Flash的读写操作特点来调用这些子函数。具体操作流程如图2所示。
对NAND Flash中的代码复制操作函数已经完成,接下来只要在start.S中调用copy2ram函数就完成工作。汇编文件start.S中,reloca-te、copy_loop段代码为U-Boot中原先的复制代码过程,去掉这2段代码,添加自己的代码。由于编写的是C代码,所以在start.S中调用cop-y2ram函数前必须先设定好指针、堆栈,另外copy2ram要用到的参数是通过r0、r1、r2寄存器传递的。
在stack_setup设置堆栈代码后面添加如下代码:
上面第一段代码主要是检测程序是否已经在内存中运行,如果已经在内存中,显然代码就无需复制,程序就会跳过复制阶段往后执行,第二段是设定参数,把参数放入相应寄存器,最后调用copy2ram函数。
自此关于NAND启动的主要代码修改和添加已经完成,但还有很重要的一处需要修改,关于环境参数的存放问题。环境参数紧随着U-Boot在NAND Flash中存放,在其之后是内核镜像文件。在U-Boot的第二阶段中有个名为env.relocate的函数,它会把环境参数复制到RAM中,而环境参数中需要向Linux内核传递的参数会在内核启动前重新构建成标记列表,同时把该标记列表放在跟内核约定好的地址处。因此必须指明环境参数的存放位置,否则无法复制到内存,从而需要传递到内核的参数也就无法完成传递。修改如下:在/include/configs/smdk241-0.h中添加:
第一行指定环境变量在NAND Flash中,后面2行分别指定其在NAND Flash中的大小和偏移量。关于NAND启动的部分全部完成。
3 U-Boot其他部分修改
由于所开发的开发板是基于S3C2440的,U-Boot中没有S3C2440的配置文件,只能仍用SMDK2410模板来进行修改。主要修改有两处:1)在/include/s3c24xO.h中添加S3C2440_NAND结构体;2)由于S3C2410和S3C2440的时钟寄存器有些不一样,所以需要修改时钟获得函数,在/cpu/arm920t/s3c24xO/speed.c修改。特别要注意的是机器ID的问题,在/include/asm-arm/mach-types.h中定义了各个开发板的ID号,必须要保证所定义的开发板的ID号跟内核一致,否则内核无法启动。
4 结束语
针对U-Boot不支持从NAND启动的缺点,对其进行修改。添加了关于NAND Flash的操作函数和支持从NAND启动的函数。本文详细阐述了U-Boot从NAND肩动的原理和修改过程。修改过后的U-Boot可以直接从NAND Flash启动,这样就可以摒弃传统依赖NOR Flash启动的硬件设计,使用只依赖NAND Flash作为存储器的硬件设计,从而简化电路,给应用带来极大方便。