摘要:由于我国的空间技术的迅速发展,航天嵌入式系统的复杂性急剧增加。在航天领域要求对嵌入式操作系统vxWorks进行剪裁工作以适应航天设计的要求,而剪裁掉文件系统的VxWorks操作系统存在地面不能对星上的事件进行有效干预的问题。文中在“龙芯”计算机平台上通过对VxWorks操作系统进行配置,设计了一种可在轨编程的方案,并针对其中的出现的修改后的函数中全局变量和调用函数的链接地址发生变化的问题提出了解决方案并完成了软件实现该功能。文中CPU采用wh1770,通过修改原被调用函数的初始代码实现对于新函数的调用,并针对全局变量以及调用函数在更新函数中链接地址发生变化设计了在轨更新接口函数和更新代码提取工具,从而实现函数的在轨更新,给出了部分设计流程图以及代码提取工具的测试结果。测试结果显示该工具实现了设计目的,在航天工程领域具备一定的利用价值。

在航天领域,由于软件设计的复杂程序越来越高,尽管软件在研制过程中已发现和解决了大量软件问题,但难免在轨飞行时仍发现少量软件存在缺陷;同时某些需要载荷根据在轨飞行应用情况调整某些算法。基于以上等方面原因越来越需要软件具有在轨更新能力。一方面可保证航天应用的可靠运行,另一方面可提高软件维修性。同时由于嵌入式操作系统为了符合航天领域的应用需要进行剪裁,本文所采用的基于“龙芯”计算机平台的vxWorks操作系统为适应航天领域的需求剪裁掉了文件系统,所以无法使用动态加载模块的方式实现函数的在轨更新,需要使用新的方法来实现在轨编程。同时更新函数中如果有函数调用则其调用的函数和全局变量的链接地址可能会发生变化,需要对函数和全局变量的调用指令做出修改。

结合这些背景,本文提出了针对“龙芯”体系结构的函数在轨更新方案以及设计了可调整调用指令的更新代码提取工具,以满足软件具有在轨更新能力的航天任务要求。

1 函数在轨更新方案简介

文中基于“龙芯”平台的VxWorks操作系统由于要符合航天系统操作系统尽量小的要求,剪裁掉了文件系统,所以不能直接使用动态加载模块的方式实现函数在轨更新,本文的在轨更新基于RAM进行,系统软件在RAM中保留了一片区域,专用来保存在轨更新注入的函数代码。龙芯计算机平台下使用“JAL指令+函数名”的方式完成函数调用,在链接时,函数名会被链接器替换为函数的地址。JAL指令在执行时,会将自身地址写入到寄存器ra中。通常JAL指令之后会跟延迟槽,因此返回地址为原函数调用指令地址+8。

若将待更新函数的前几条指令进行替换,修改为“JAL指令+新函数的地址”,这样调用该函数后,替换的JAL指令会调用新的函数。从新函数返回后,将回到原函数的代码继续执行。因此需要将原函数第三条指令修改为返回指令,返回到原函数的调用处。

由于JAL指令调用新函数时,会当前地址写入寄存器ra中,故会将原函数的返回地址(之前寄存器ra中的内容)覆盖掉,因此在JAL指令之前,须将寄存器ra中的内容保存到堆栈中。在从新函数返回后,接着将堆栈中的原函数返回地址写回到ra中,并通过返回指令回到原函数调用指令地址+8处,即回到原函数调用处的下一指令。

2 方案设计及内存分配

2.1 函数替换模块设计

本设计的结构图如图1所示,原调用方式为通过JAL指令直接跳转到被调函数然后通过jr ra返回,替换后的函数调用方式为将通过将原函数的前8条指令进行修改,替换为以下形式的指令

VxWorks Loongson Mips

从而实现对新函数的调用,图1中给出了在轨替换前后的函数调用示例,可发现函数替换对其被调用者而言是不可见的,对其被调用者无任何影响。

VxWorks Loongson Mips

2.2 在轨更新内存分配

为了保存在轨更新的函数代码,系统软件在RAM中预留了一片空间,专用来存储函数更新代码,并建立函数更新表对其进行管理,记录原函数地址、更新代码的存储地址、更新函数的长度等信息。

目前系统软件启动完成后的内存分配见图2,其中USER_RESERVED区域为用户保留区,不会被系统软件所使用。该区域的大小在BSP的config.h文件中定义。

VxWorks Loongson Mips

对BSP中RAM初始化的代码(对于基于ROM的和引导ROM的vxworks映像在romInit.s中)进行修改,使初始化时不对USER_RESERVED区域清零。在系统首次加电时由应用程序对该区域清零,而在系统复位时则不做清零处理。这样修改是为了在系统复位后,USER_RESERVED区域中保存的内容不被清除掉。如果每次复位后该区域的内容均被擦除,其中保存的在轨更新代码必须重新注入,在进行了函数在轨更新后,须时刻关注系统状态,在复位发生后立即重新注入。这样会对数据注入链路造成较大的压力。

2.3 更新区域的布局

2.2中提到在RAM中预留了用户保留区域USERRESERVED区域来建立函数更新表对函数更新进行管理,该区域内将记录原函数地址、更新代码的存储地址、更新函数的长度等信息。在更新代码注入完成且校验正确后,需检查是否有空间来存储更新代码,如果有则在函数更新表中增加一项,并确定更新代码在更新专用区域中的存放地址,然后将注入的代码从缓冲区拷贝到该地址。

为了保证可靠性,函数更新表及更新代码存储区域均采用三模处理。函数更新表在内部三模。更新代码存储区域则是将同一更新代码存储在3个区域,在执行更新替换前进行比对,防止错误。在轨更新区域内存布局如图3,ONLINEUPDATE_BEGIN定义了在轨更新区域首地址ONUNEUPDATE_LEN定义了区域长度,ONLINE_UPDATE_END则定义了区域末地址,这些常量均需要在在轨更新头文件(本文定义在onlineUpdate.h)中定义。

VxWorks Loongson Mips

3 在轨更新接口函数

为了便于应用程序使用在轨更新功能,制定并实现了在轨更新功能接口,分别实现在轨更新区域初始化,获取下一个在轨更新的函数第一条指令的存储地址,设置函数在轨更新,以及启用和禁用函数更新功能。

4 系统调试代码提取工具及调试结果

4.1 代码提取工具

若待更新的函数中调用了其它函数,或是使用了全局变量,由于重新编译链接后,函数和全局变量的链接地址均可能发生变化,从而导致更新的函数中引用的地址与当前星载计算机上正在运行的软件中地址不一致。在龙芯计算体系结构下,并不需要对全局变量进行处理,只需对函数调用指令进行处理。本文设计的代码提取工具完成更新代码的提取,并将更新代码中的函数调用指令进行调整。

1)全局变量地址变化的处理方式

Gcc—wrs—mips交叉编译器生成的数据段地址4 k字节对齐。更新后的函数体积若相对于原函数增加过大,则会造成数据段链接地址改变。由于龙芯体系结构(基于mips体系结构)中存在着全局指针寄存器即gp寄存器,使用该指针能方便的存取static和extern数据,编译器会将全局变量存放在gp中的全局指针指向的32 kB的地址范围内,这样链接地址的改变并不影响全局变量在gp中的指针指向的范围的存放地址,因此调用时并不需要对链接地址改变了的全局变量进行修改,图4,图5为测试结果,图4为全局变量gDatal的链接地址,图5为gDatal链接地址变化前后编译器通过gp寄存器调用gDatal的指令对比。

VxWorks Loongson Mips

在轨运行的软件中,gDatal的地址分别为0x80led874,而在本地编译生成的更新函数代码中,gDatal的地址为0x801ed864。而此时使用gp寄存器调用gDatal的指令并未发生变化,由此可见,通过利用gp寄存器,并不需要对改变了链接地址的全局变量改变做出修改。

2)函数链接地址的变化

在修改函数代码重新编译后,被修改函数之后的所有函数链接地址均会发生变化,由于修改了函数add,导致函数add和add之后的函数链接地址都发生了变化。add中调用了retOne函数,由于龙芯的函数调用指令JAL指令是由指令操作符和目标函数所在地址的低28位右移2位形成的指令偏移值一起构成,如图6所示,因此需对JAL指令的调整。

VxWorks Loongson Mips

通过对更新代码中的JAL指令进行解析,通过指令编码中的偏移地址与指令地址高4位计算出JAL调用的函数地址。查找新的MAP文件,得到调用的函数名。然后利用函数名查找旧的MAP文件,获取星载计算机中该函数的链接地址。然后对调用函数的链接地址对JAL指令进行调整,即完成了JAL指令的调整工作。

4.2 代码提取工具执行结果

代码执行结果如图7所示。

VxWorks Loongson Mips

5 结束语

本文设计的基于龙芯计算机平台的vxWorks函数在轨更新研究可行,设计的代码提取工具能完成任务需求。测试结果显示软件能达到了设计目的,在航天工程领域具备较好的工程利用价值。