用SD卡方式进行嵌入式设备操作系统的自动升级的实现
扫描二维码
随时随地手机看文章
本文提出了一种扩展Uboot实现嵌入式设备操作系统维护与升级的方法。该方法将待升级的内核和文件系统映像放入SD卡中,当系统重启时,扩展后的Uboot会自动检测并读取SD卡中的映像文件,再烧写到嵌入式设备实现自动升级。该方法较传统的通过JTAG口、串口或者网口连接到主机,在主机上通过手动输入控制命令完成内核或者文件系统的升级方式更为便捷高效。
随着现代工业社会逐步向智能化社会的过度,嵌入式在现代经济生活中扮演着至关重要的角色。32位的高性能、低成本、低功耗的嵌入式RISC(Reduced InstructionSet Computer)微处理器——ARM(Advanced RISC Machines)已经成为应用最广泛的嵌入式微处理器。
目前,基于ARM的嵌入式系统在各个领域都有着广泛的应用,嵌入式系统的维护与升级也变的日益重要。由于新技术的不断涌现和对系统功能、性能等要求的不断提高,开发者必须能够针对系统进行升级和维护,以延长系统的使用周期,改善系统性能,增强系统适应性。
传统的嵌入式系统升级,首先通过JTAG接口将Bootloader烧写到目标板的Flash中,然后在Bootloader中,将内核映像文件和文件系统映像文件通过串口或者网络下载并烧写到Flash。若需对内核或文件系统升级,则要按照上述方法重新烧写新的映像文件,直接覆盖原来的映像文件。这类方法,一方面必须将嵌入式设备和主机通过串口线或者网线相连接;另一方面需要人工手动输入控制命令,而且通过串口或网络下载映像文件速度非常慢。
本文针对嵌入式Linux操作系统提出了一种新的升级机制,即通过将映像文件拷贝到SD卡中,由扩展后的Uboot实现系统自动升级,这个方法可以有效克服传统升级方法的局限,简化系统升级步骤,提高升级速度。
1 工作原理
一个嵌入式Linux系统从软件的角度看通常可以分为4个层次:Bootloader、Linux内核、文件系统和用户应用程序。这4个层次中,Boot loader一般是按照嵌入式系统的硬件配置定制的,是嵌入式系统加电以后运行的第一段软件代码。要对Bootloader升级只能通过人工手动完成,不过一般嵌入式系统在硬件平台没有变化的情况下是不需要对Bootloader进行升级的。用户应用程序只是运行在Linux操作系统上的一个程序,其升级方法简单,一般可以通过网络直接进行升级。Linux内核和文件系统的升级不像Bootloader那样基本不需要升级,也不像应用程序那样很容易完成升级。目前,对于Linux内核和文件系统的升级一般都是在Bootloader中实现的。
通过对Uboot的功能进行扩充,加入了系统升级的功能。例如,用户需要对嵌入式设备上的Linux内核或文件系统进行升级,只需要将新的Linux内核或文件系统映像,命名为指定的名称拷贝到SD卡中。如果此时系统处于非运行状态,只需要重新启动嵌入式设备即可进行升级
过程;如果系统处于运行状态,Linux系统会自动检测SD卡是否存在相应的升级文件,存在则自动reboot,这样也完成了系统的升级。
不论系统是否处于运行状态,真正的系统升级过程都是在Uboot中完成的。设备重启时,首先运行Uboot,在这过程中Uboot完成系统初始化之后,在引导内核之前先检查SD卡中是否有Linux内核或文件系统映像文件。若有,则读取映像文件到SDRAM当中,然后通过Uboot中的Flas h命令将内核或者文件系统映像烧写到相应的分区当中来完成升级;若无,则直接启动系统,具体流程如图1所示。
2 关键技术
2.1 Uboot工作原理
Uboot是一个由德国DENX发起的,遵循GPL条款的开源项目,支持ARM、X86、MIPS、PowerPC等处理器,可启动Linux、VxWorks、TREMS等嵌入式操作系统,其提供了丰富的配置、管理以及运行命令。
Uboot与大多数Bootloader一样都包含两种操作模式:
①启动加载(Bootloading)模式:即Uboot从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程都是自动完成的。
②下载(Downloading)模式:在这种模式下,目标机的Uboot将通过串口或网络等通信方式将内核或文件系统印象下载到RAM当中,然后再写入相应的存储设备中。这种工作模式通常在系统初次安装和更新时使用。
Uboot的实现依赖于CPU的体系结构,它分为stage1和stage2两大部分。stage1存放用汇编语言实现的依赖于CPU体系结构的代码,比如设备初始化代码等;stage2则通常用具有更好的可读性和可移植性的C语言来实现。
Uboot Stage1的主要功能有:
①硬件设备初始化;
②为Uboot重定位至RAM中,准备RAM空间;
③重定位Uboot代码到RAM中;
④设置堆栈,将BSS段清零;
⑤跳转到第二阶段的C程序入口点。
Uboot Stage2的主要功能有:
①初始化硬件设备;
②将内核和文件系统映像从Flash读到RAM中;
③设定内核启动参数和调用内核。
通过上面这两个阶段,Uboot就完成了引导内核启动的任务。
2.2 Uboot扩展升级功能
Uboot本身并不带有系统升级功能,本文在Uboot现有的功能上做扩展,使其完成系统升级的功能,将新的内核或者文件系统映像烧写到Flash的相应分区中。本文的实验对象是Samsung公司的S3C2440微处理器,该设备上有64 MB的SDARM和256 MB的NAND Flash,NAND Flash的起始地址映射到0x00000000,SDRAM的起始地址映射到0x30000000。设备上的Uboot将256 MBNAND Flash分为Bootloader、Bootloader参数、ker nel和rootfs四个区。其中,Bootloader分区是用于存放Uboot映像,它的起始地址为NAND Flash的起始地址0x00000000;Bootloader参数区是用于存放Uboot的参数;kernel区用于存放Linux内核;rootfs区用于存放文件系统,在我们的设备上使用的文件系统是Yaffs2。这4个分区的起始地址和大小如表1所列。
升级功能的扩展主要在Uboot的第二阶段完成,在Uboot完成外围硬件设备初始化之后,检测是否有SD卡插入,如果有,再检测SD卡中是否有相应的内核或者文件系统映像。如果有相应的映像文件,就进行升级工作,升级完成后再启动新的系统。系统升级核心工作可以分为两步,第一步是将相应的映像文件读取到SDRAM当中;第二步则将SDRAM中的映像写入到相应Flash分区当中,详细流程如图2所示。
2.3 具体实现
通过上面的分析可以看出,扩展一个支持SD自动升级功能的Uboot需要完成如下步骤。
(1)判断是否存在SD卡
判断SD卡是否存在,通过使用Uboot当中提供的find_mmc_devICe函数,这里只要判断该函数的返回值即可知道SD卡是否存在,实现代码如下:
(2)判断SD卡中是否有内核映像文件
如果存在,则将其烧写到Flash相应的分区当中。实现这个功能需要使用到Uboot中的run_command函数,由于kernel的映像文件一般不会超过5 MB,所以在烧写kernel的时候不需要检查映像文件的大小。检查内核映像文件是否存在也是通过执行命令的方式,如果存在,那么Env环境变量fileexist的值就是YES,并且此时的内核映像已经存在于SDRAM当中,可以直接通过命令烧写到Flash相应的分区当中。具体的代码如下:
(3)判断SD卡中是否有文件系统映像文件
如果存在,则写入到相应的Flash分区当中。本实验设备上使用的文件系统是Yaffs2,通过Uboot命令烧写Yaffs2文件系统的时候,必须要知道它的实际大小。由于升级很可能导致文件系统大小的变化,所以这里必须将读取到SDRAM当中的文件大小记录下来,这个工作在Uboot中已经完成,我们只需要通过getenv(filesize)就可以获得载入SDRAM当中的文件大小,其他的步骤和烧写内核映像是一样的。具体代码如下:
经过上面3个步骤修改的Uboot程序可支持SD卡自动升级的功能,需要注意这段代码应该放在Uboot自动加载系统之前,推荐将这些代码放在main_loop函数中。
结语
本文通过定制扩展Uboot实现了用SD卡方式进行嵌入式设备操作系统的自动升级,这种方式不但克服了传统升级方式的局限性,而且具有一定商业价值。目前,该方法经过调试,系统运行正常。显然,要通过SD卡实现系统升级,需要嵌入式设备具有SD卡接口,因此,它并不适合所有的嵌入式系统,但是这种实现机制可供借鉴。