1 引言
SEU(Single Event Upset)是由带电粒子投射到集成电路器件的敏感区域引起的,通常会导致处理器内部寄存器内容改变或内存位翻转(bitflips),带来的后果可能是计算结果错误,程序执行序列错误,甚至是系统的崩溃。国外的许多研究机构都开展了抗SEU计算机系统的研究,提出了许多解决措施,如基于系统级冗余的方法,采用抗辐照的计算机组件方法,以及基于软件的容错方法(比如N个版本软件,基于算法的容错,代码跳转检测),这些方法各有优缺点。系统级冗余和抗辐照组件尽管可以保证可靠性,但带来成本地急剧提高和系统规模的增加。软件容错技术主要应用在内存容错,对处理器本身的寄存器和运算器等的错误并没有提供很好的解决方法,同时软件的容错技术会引起性能下降和软件程序规模增长。
半导体技术的发展,特别是FPGA技术的迅猛发展,为我们提供了设计计算机系统更灵活的手段和平台。目前FPGA的规模已经达到几百万门,甚至有抗辐照的FPGA器件。选用基于FPGA的片上系统(SOC)方案来实现容错的嵌入式系统,具有重要的意义和广阔的应用前景。这种方案有以下几个优点:采用FPGA其集成度高,计算机系统设计简单,可靠性高,体积重量小;具有较高的扩展性,很容易实现定制的硬件容错逻辑,并且具有重新配置的功能;可以使用已有的IP核,缩短了开发周期。
本文提出了一种基于FPGA的容错嵌入式系统设计方法,并给出了Xilinx FPGA的实现方案。本系统主要考虑SEU对计算机系统的影响,通过多CPU核的设计方法,使得在单个功能单元失效的情况下系统的可靠性依然得以保证,并通过软件错误检测和恢复机制,使系统的额外负载和容错功能达到了一个较好的平衡。
2 多处理器内核的FPGA内部设计
由于采用了基于FPGA的设计方式,在定制系统的逻辑功能上具有了极大的灵活性和可扩展性。在FPGA内部系统设计中,本系统采用CPU IP软核的三模冗余,达到传统的板级三模冗余效果。图1是采用Xilinx Vertex II FPGA实现的容错计算机系统框图。
Xilinx的Vertex II支持MicroBlaze处理器软核,并支持IBM CoreConnect片上互连总线。在FPGA内部集成了3个MicroBlaze处理器软核,通过一个Voter逻辑单元进行表决,实现了处理器的三模冗余。MicroBlaze处理器采用RISC架构和哈佛结构,32位地址总线,独立的指令和数据缓存,并且有独立的数据和指令总线连接到IBM的OPB(On-chip Peripheral Bus)总线,这样它能很容易和其它外设IP核一起完成整体功能。如图1所示,三个MicroBlaze通过Voter连接到OPB总线上,所有其它设备的控制逻辑通过OPB接口挂接在OPB总线上,MicroBlaze通过OPB总线访问内存、ROM、FLASH以及串口等设备。
三个MicroBlaze的数据总线和指令总线在接入OPB总线之前都经过了Voter进行比较。如果发现比较结果不一致,那么某个CPU所在的逻辑单元可能发生SEU错误。Voter判断哪个CPU的数据或地址与其它的两个不同,这时Voter自动屏蔽出错的CPU发出来的地址和数据。此时整个系统由一个三模冗余转化成一个双机比较,同时向没有发生错误的CPU发出一个异常处理中断,CPU响应中断,并且调用异常处理程序,记录下此时CPU的各种状态,在软件层面把出错的CPU屏蔽出去。假如其中又有一个CPU受到SEU的影响发生了错误,那么Voter判断出错误,FPGA进行全局重新配置,回到原来的三模冗余状态。但由于SEU的发生频率较小,这样的情况会较少发生。Voter逻辑的结构设计如图2所示。
Voter模块有三个输入B1、B2、B3,代表三个MicroBlaze数据总线上的数据输入,三个输出Output表示经过比较的总线数据,Reset信号用来复位系统,Error信号表示出错状态。如果Voter的三个比较器自身发生错误,那么比较后的输出有误,可以由控制逻辑判断纠正。如果控制逻辑发生了错误,那么只能等待watchdog超时,等待外部计算机对之进行重新配置。
3 μc/OS-Ⅱ系统的容错设计和实现
FPGA内部运行μc/OS-Ⅱ操作系统,μc/OS-Ⅱ操作系统具有如下的特性:可移植性,体积小,可裁减,多任务,服务执行时间可确定性,最重要的是它具有很高的稳定性和可靠性。为了减轻不可避免的SEU现象带来的影响,必须在软件方面增强μc/OS-Ⅱ操作系统和应用程序的容错特性。
3.1 加入系统的EDAC支持
EDAC(Error Detection And Correction)是容错系统中用来避免内存中数据变化的常用方法,我们在本系统中增加了对EDAC的支持。
3.1.1 校验码的选择及其内存分配
海明码因为其高效简单的特性,在很多系统中都使用它进行差错的校验。本系统使用(12,8)的海明码,一个字节的码字对应4位的纠错位。海明码的编解码通常都是使用计算的方式来完成,但是由于本系统采用的码字较短,所以可以建立一个映射表进行简单的原码到纠错码的映射,表的大小为256,其占用的空间很小。使用查找表进行编解码时只需要访问一次内存,不需要额外执行计算指令,大大加快了编解码速度。
为了使EDAC的功能对整个系统尽可能的透明,我们采用把原始数据和校验码分离的方法,保证原始数据的完整连续性,在不需要EDAC时可以对数据进行正常的连续操作,否则访问每一个数据前都需要先除去校验码,只能按单字节操作。存放分离的校验码的方法有两种,一是在每次生成校验码时动态分配一段地址,但这需要用户自己去分配这样的一个空间,因为μc/OS-Ⅱ的空间分配必须要由用户来完成,这是一个比较明显的缺陷。本系统应用程序比较简单,占用的空间并不是很大,而且片上内存有16M,可以通过简单映射到内存高端的一半地址,每一个低端地址的数据都对应一个高端地址的校验字节。虽然这种映射方式对代码段的数据也预留了空间,但是对于数据处理起来非常方便,原始数据和相应校验码的地址之间相差一个固定的偏移,不需要多余的计算。
3.1.2 两种纠错原语操作及其封装
对于内存数据的EDAC校验,构造了两个基本的原语操作,ENCODE和DECODE。这两个操作的对象是一个内存数据,ENCODE原语对内存数据进行计算并更新校验码,而DECODE进行内存数据的检验纠错。使用这两个原语可以构造出更多的功能较强的宏。常用的是下面两种宏,分别对应对单个变量和内存段的保护和纠错。
PROTECT(var):保护变量var
VALIDATE (var):对变量var进行检验纠错
PROTECT_STACK(argc):保护参数个数为argc的堆栈空间
VALIDATE_STACK(argc):对堆栈空间进行检验纠错
3.1.3 EDAC功能的具体实现
本系统基于上面介绍的各种原语来实现EDAC容错:
1)对应用程序中比较重要的数据变量在对其赋值后利用PROTECT宏进行处理,在使用之前用VALIDATE宏校验纠错。当然,使用这种方式对用户有较高的要求,他们需要分析各种变量对程序可能造成的影响。由于本系统应用程序并不是大规模的计算程序,进行的算术运算并不是很多,可以近似地认为在变量赋值之后,对它进行一定的算术运算依然是有效的,只有在数据作为函数的调用参数时,才需要对它进行保护。
2)对应用程序运行过程中函数堆栈的保护。在程序的运行过程中,比较活跃的是函数调用时堆栈的变化。在进入函数时,用PROTECT_STACK对传入的参数进行保护,在退出函数时,用VALIDATE_STACK对传入的参数进行验证。
根据MieroBlaze的ABI可以得到在函数调用时内存布局如表1所示。
如表1所示,需要传递的函数参数是通过调用者自己的堆栈空间来分配的。这样只需要知道旧的堆栈指针就可以访问传递到本函数的所有参数的值,而旧堆栈的指针就存在于Link Register之中,PROTECT_STACK和VALIDATE_STACK就是通过这个指针来进行访问的。在函数中使用堆栈保护的函数基本形式如下:
int function(par1,par2,…)
﹛
PROTECT_STACK(argc);
…
VALIDATE STACK(argc);
﹜
3.1.4 内存刷新进程
对于内存中一些固定不变的数据,比如操作系统和应用程序的代码段和常量,可以用一个刷新进程来进行定时的更新,纠正可能存在的错误,此进程为Scrubber,可以根据需要设置需要刷新的时间间隔或是频率。Scrubber主要的功能如下:
scrub_register:登记需要刷新的区域和频率。
scrub_lock:锁定需要进行刷新的区域并且进行校验纠错。
scrub_unlock:对需要刷新的区域进行保护,并且解除锁定。
每一个进程如果需要使用Scrubber进行刷新时,通过调用scrub_register函数来进行登记,对需要刷新的区域进行操作时必须对它们进行锁定,以保证其一致性。
3.2 分离操作系统以及各个程序的地址空间
因为Micro Blaze并没有自己的MMU,而且μc/OS-Ⅱ操作系统上的应用程序并不是以单独的ELF文件加载执行,而是和操作系统静态链接,操作系统和应用程序的代码和数据段都是在一起的。这种内存的分布方式在发生错误时,不容易判断到底是那个程序发生了问题。为此我们对编译脚本进行了更改,使每个程序的各个段都分离开来,中间保留一个隔离区域,其中填充brk指令。
3.3 异常及异常处理
对于程序异常的发生,以尽可能恢复程序运行为准则。Micro Blaze能够捕捉到的中断和异常如下:(1)未定义的指令,指令的操作数部分改变;(2)内部指令和BUS错误;(3)用户中断,用于系统调用;(4)软件中断,用于单步调试;(5)看门狗中断,在程序没有响应时产生。SEU对程序执行结果的影响主要来源于内存中的程序指令和数据的改变,会直接导致以上的(1)、(3)、(5)这几种错误。
在各种中断和异常中比较特殊的是软件中断,它是通过brk或者brki指令来实现的。这两条指令在μc/OS-Ⅱ和各种应用程序中都没有使用到,利用这种特性可以用来判断是否有错误的程序跳转。对于没有使用的内存空间可以用brk指令的格式来进行初始化,如果程序进入这段区域,就会触发软件中断,此时可以判断SEU错误的发生,对之进行相应的处理。每当一个异常发生时,异常处理程序的主要任务是记录下异常发生的时间以及地址,以便随后的统计分析,并且尽可能的恢复程序的运行。异常地恢复主要针对以下两种情况进行处理
1)发生了未定义的指令,这种情况是由于指令的操作码发生了变化,Micro Blaze会记录下异常发生的地址即该指令的地址,通过和ROM中该程序地址的代码进行比较可以把出错的代码更新成原始值。(2)软件中断异常,这是由执行了brk指令引起的,即程序发生了错误的跳转,进入了隔离区域。通过对指令集的分析发现,该例外发生时必然是一条跳转指令,其跳转的地址出现了错误,跳转的地址可能是立即数,或者存放在寄存器中。立即数错误发生在不可改变的代码段,前面的EDAC措施已经降低了它发生的概率,那么出现较多的将是寄存器中的跳转地址错误。可以构造一个简单的RollBack功能,因为已经保证了函数调用的各个参数的正确性,如果此函数没有使用全局的数据,那么可以在异常发生时那个函数的入口重新开始程序的执行。
4 容错性能测试和分析
4.1 测试环境
实验的测试环境由目标机和主机构成,目标机是运行在FPGA上的μc/OS-Ⅱ系统,主机是Linux系统。我们通过一个故障注入进程向内存中的地址随机注入错误位,模拟SEU的效果。由于μc/OS-Ⅱ的进程调度都是在中断处理程序中进行,此进程的优先级设置成最高,保证其能按一定的频率运行,并根据传入参数控制注入的bitfilps浓度。为了提高随机数的可靠性并且避免多余的计算,我们没有采用μc/OS-Ⅱ系统产生随机数的方法,而是由主机Linux系统产生随机数,在模拟进程开始执行时,通过串口与主机上运行的监控进程进行通信,获得随机数,用于bitfilps的生成。最后的各种测试数据同样通过串口发送回主机,主机监控进程对之进行记录分析。
4.2 测试结果
由于FGPA下载文件的格式资料较少,不容易通过对其注入bitflip来模拟某个CPU出现工作异常,我们通过仿真工具,对Voter逻辑进行模拟,结果表明Voter逻辑设计正确,能够正确处理CPU出现各种异常的情况,并且产生相应的错误信号。在加入了操作系统和应用程序的容错特性后,最后生成的程序大小比原始程序有所增加(不包括填充的brk代码),如表2所示。
从表2分析可知,程序的大小比原始程序增加了51%,这个比例相比一些软件冗余方式,如变量的复制、代码跳转检测,还是比较低的。表3为系统运行时所有容错特性开启前后的一次测试结果。
测试时间为120 rain,两种Bitflips的注入速率为1000和6000。#1表示在没有容错的情况下发生异常的次数,#2表示在有容错的情况下发生异常的次数,#3表示在进行了异常的处理后程序依然不能正确运行的次数。从相应的比较中可以看出,相比在容错特性开启前,各种系统异常的次数都有很大降低。在异常处理阶段,对未定义指令的效果最好,因为可以直接和原来的指令进行比较,而其它两种异常采用的纠错措施起到的作用并不是很明显。综合以上的结果可以看出,在采用了多种容错手段后,虽然不能够完全避免SEU对内存中操作系统和应用程序的运行带来的影响,但是在一定程度上提高了整个系统的健壮性。
5 结束语
在本系统中,通过采用FPGA设计把通常使用的板级硬件冗余方式融合到FPGA芯片内部。这样不仅达到了冗余纠错效果,而且减小了开发成本;同时,基于FPGA良好的可定制性,项目的开发周期大大缩短,系统的调试变得更加便捷。在加入了对μc/OS-Ⅱ嵌入式操作系统的容错功能后,系统的健壮性得到了一定的改善,系统的额外开销相比其它的一些软件容错手段,如变量复制、代码跳转检测等方法要小。利用FPGA进行系统设计,更容易让硬件和软件有机的结合,实现优势互补。这是在使用FPGA进行容错嵌入式系统开发的一个有益尝试,相信在今后的项目中基于FPGA的应用系统会更加的普遍和成熟。
文章评论(0条评论)
登录后参与讨论