计算机系统应用  2020, Vol. 29 Issue (8): 217-223   PDF    
GEC架构下RTOS对外接口函数重映射机制
刘长勇1,2,3, 王宜怀2, 孙亚军2     
1. 武夷学院 数学与计算机学院, 武夷山 354300;
2. 苏州大学 计算机科学与技术学院, 苏州 215006;
3. 认知计算与智能信息处理福建省高校重点实验室, 武夷山 354300
摘要:实时操作系统(RTOS)是嵌入式人工智能与物联网终端中重要工具, 不同的机构开发的RTOS其实时性、调度规则、任务间通信机制等稍有差异, 但基本要素相同. 基于通用嵌入式计算机(GEC)架构研究了RTOS在BIOS驻留方法及对外接口函数重映射机制, 以NXP的KL36芯片为例给出了mbedOS在BIOS中的驻留实现, 并给出对外接口函数重映射实例. 实践表明RTOS驻留在BIOS中, 不仅缩短了编译链接时间, 同时通过对外接口函数的重映射, 简化了对RTOS调度机制的理解, 降低了编程难度, 为有效地实现不同RTOS下应用程序的可移植性提供了技术基础.
关键词: 实时操作系统    通用嵌入式计算机    对外接口函数重映射    BIOS    KL36    
RTOS External Interface Function Remapping Mechanism under GEC Architecture
LIU Chang-Yong1,2,3, WANG Yi-Huai2, SUN Ya-Jun2     
1. Department of Mathematics and Computer Science, Wuyi University, Wuyishan 354300, China;
2. School of Computer Science and Technology, Soochow University, Suzhou 215006, China;
3. Key Laboratory of Cognitive Computing and Intelligent Information Processing of Fujian Education Institutions, Wuyishan 354300, China
Foundation item: National Natural Science Foundation of China (61672369); Natural Science Foundation of Fujian Province (2017J01651)
Abstract: Real-Time Operating System (RTOS) is an important tool in embedded artificial intelligence and IoT terminals. RTOS developed by different institutions has slight differences in real-time properties, scheduling rules, and communication mechanisms between tasks, but the basic elements are the same. This work is based on the general embedded computer(GEC) architectures, studies the RTOS resident method in BIOS and the remapping mechanism of external interface function. Taking the KL36 chip of NXP as an example, the resident implementation of mbedOS in the BIOS is given, and living example of external interface function remapping is given. Practice shows that the RTOS resides in the BIOS, which can shorten the compilation and linking time. At the same time, by remapping external interface functions, the understanding of the RTOS scheduling mechanism is simplified, the programming difficulty is reduced, and the technical basis is provided for effectively implementing the portability of applications under different RTOS.
Key words: real-time operating system     general embedded computer     external function interface remapping     BIOS     KL36    

为了提升编程颗粒度、提高可移植性, 借鉴通用计算机的概念与做法, 把基本输入输出系统(Basic Input and Output System, BIOS)与用户程序分离开来, 实现彻底的工作分工, 形成了通用嵌入式计算机(General Embedded Computer, GEC)[1]. GEC架构将嵌入式软件系统分为BIOS工程程序(简称BIOS)和USER工程程序(简称USER)两部分, BIOS先于USER固化于微控制器(Microcontroller Unit, MCU)内的非易失存储器(如Flash)中, 为实时操作系统(Real-Time Operating System, RTOS)的驻留提供了空间. 实时操作系统能提供精确的实时控制和任务管理功能, 保证系统的实时性需求[2].通过将RTOS驻留在BIOS中, 降低用户的编程难度、简化程序的串口写入以及方便用户调用, 同时也可以很好地帮助用户解决因RTOS在不同开发环境的编译困难而造成的烦恼.

同时, 为了充分发挥RTOS的功能, 方便用户使用, 提高用户程序的可移植性, 通过提供对外函数接口的形式是一种比较好的做法. 对外函数接口(也称为应用程序编程接口, API)是软件库提供的一组可访问的接口, 软件库通过API向外提供服务, 开发人员通过使用API实现代码复用, 提高生产效率[3].因此, 在对外函数接口设计上, 要充分考虑其可用性[4,5]、稳定性[6]和安全性[7,8].目前, 对外函数接口的研究已取了一定的研究成果, 主要集中在API使用规约[9-11]、API推荐研究[12,13]、API文档研究[14,15]、API组合模式的应用[16]等方面, 但有关RTOS的驻留及其对外函数接口研究方面文献较少. 为此, 本文首先给出通用嵌入式计算机架构下RTOS的BIOS驻留方法, 剖析了RTOS对外函数接口设计方法, 提出了接口函数重映射机制, 最后在mbedOS下进行应用实践. 实践表明, 将RTOS驻留在BIOS中, 能有效地节省用户程序的编译时间, 同时通过对外接口函数的重映射, 能有效地提升了应用程序的可靠性性和开发效率, 易于用户调用, 也使应用程序易于复用, 为嵌入式人工智能与物联网终端程序的开发提供了技术基础.

1 RTOS的BIOS驻留方法简介

在GEC架构中, 虽然嵌入式软件系统分为BIOS和USER两部分, 但最终程序代码和各种变量数据都是放在同一个MCU的Flash和RAM中, 要将RTOS驻留在BIOS中, 实现RTOS与应用程序的物理隔离, 就必须对MCU的Flash和RAM空间进行合理的划分, 这样才能确保代码不重叠, 变量使用不越界, 从而保证RTOS能得到正常运行, 而又不影响USER的执行. 因此, 要考虑RTOS驻留的硬件载体, 即MCU的Flash和RAM空间大小的因素. 对Flash空间的划分可采用分割独享方式, 一部分给BIOS程序使用, 另一部分给USER程序使用, 两者使用的空间不重叠. 对RAM空间的划分则需要考虑MCU的RAM空间大小, 当RAM空间足够大时, 可采用分割独享方式, BIOS和USER各单独使用不重叠的空间; 当RAM空间较小时, 可采用重叠共享方式, 即BIOS使用的空间和USER使用的空间部分重叠共享, 这样可以提高RAM空间的利用率. 在实现RTOS驻留的过程中, 还需要考虑如何合理划分Flash空间, 使USER程序占用的空间尽量大; 重叠共享方式分配RAM空间时, 如何避免出现数据越界与冲突; RTOS的调度会依赖于系统服务调用, 何时将这些调用权移交给RTOS等问题.

2 RTOS对外函数接口设计方法

虽然RTOS已驻留在BIOS中, 但要发挥其作用, 还需将RTOS的功能函数设计成对外函数接口表, 然后通过映射形成对外函数映射表, 这样才能向USER提供服务. 也就是说, USER可以通过对外函数映射表实现对RTOS提供的接口函数的调用.

2.1 设计RTOS对外函数接口的必要性

在GEC架构下, 将RTOS提供的函数进行对外接口的设计, 不仅能够发挥RTOS的功能, 而且还能方便用户使用, 提高USER程序的可复用性. 因此, RTOS向用户提供接口函数是非常必要的.

(1)提高应用程序的可复用性. 由于USER是通过对外函数映射表实现对RTOS提供的对外接口函数调用的. 因此, 当在BIOS中驻留不同的RTOS时, 只要向USER提供相同功能的接口就可以, 即使这些接口的名称发生的改变, 也不会影响USER的调用, USER程序不需要修改, 提高了USER程序的可复用性.

(2)提升应用程序的稳定性和可靠性. 由于RTOS已经驻留在BIOS中, 它所提供的对外函数功能已经在BIOS中通过编译、测试和验证, 变成了一段可靠的、稳定的机器码. 因此, 在USER程序中可以放心地调用RTOS提供的对外函数, 不用担心会出现的代码错误, 从而提升了应用程序的稳定性和可靠性.

(3)缩短应用程序的开发时间. 由于RTOS提供了原型级的对外函数调用接口, 用户可以直接使用, 无需花大量精力深入理解RTOS的工作原理和调度机制, 不需要知道具体的实现细节, 只需关注用户程序的编写, 大大地提高了开发效率.

(4)方便应用程序调用. 由于RTOS提供的对外函数已经变成了机器码驻留于BIOS内, 用户难以调用, 通过对这些函数进行重映射, 最终向USER提供函数调用原型接口, 用户就可以像调用普通函数一样方便使用这些函数.

2.2 RTOS对外函数接口机制

要实现RTOS对外函数接口, 首先需要在BIOS中对函数进行重定义、声明、注册, 形成对外函数接口表; 其次要在USER中通过映射获取对外函数接口表的入口地址, 形成对外函数映射表, 并重定向函数名称, 最后在USER中实现对函数的调用, 其过程如图1所示.

图 1 对外函数接口的设计与实现过程示意图

(1)对外函数的二次封装

对外函数不仅可以包含RTOS的功能函数, 而且还可以包括各类构件函数, 本文主要介绍如何封装RTOS提供的对外接口函数. RTOS一般都具备线程管理、同步与通信、中断管理等基本功能, 相应的提供了线程类、事件类及操作系统启动函数等, 在这些类中提供了大量的成员函数, 都是采用C++实现的. 由于这些成员函数的执行依赖于类对象的创建及其成员变量, 而不是使用绝对地址的方式来实现对类中的某个成员函数的调用. 因此, 必须在BIOS程序中对这些函数进行重定义, 二次封装成C语言可以调用的函数形式, 这样才能实现在USER中调用它们. 对外函数的二次封装(或称重定义)主要包括函数名、函数的返回值类型、函数的参数、函数体以及为了便于理解程序而加入的功能说明和代码注释等. 其格式如下:

格式: void重定义函数名(参数表列)

{

  [相关变量声明]

  调用RTOS函数

}

例如, mbedOS的延时函数名为Thread::wait, 通过二次封装重定义为thread_wait.

(2)对外函数的声明

对外函数重定义好之后, 一般应在与之同名的.h头文件中进行声明, 函数的声明要给出函数名、函数的返回值类型、函数的参数以及函数的功能说明, 即使用者通过函数的声明就能了解函数的功能和使用方法, 而不需要查看函数的具体实现.

格式: void重定义函数名(参数表列);

(3)对外函数的注册

当对外函数定义和声明之后, 还要对函数进行注册才能形成对外函数接口表. 借鉴中断向量表的定义做法, 可以给所有的或部分的函数编号, 并将函数名(即函数的入口地址)集中在一起按编号有序地放在一个统一的区域中, 形成对外函数接口表. 在对外函数接口表中, 对外接口函数的入口地址用32位的二进制表示, 可以看作和定义成long类型的数据, 一般采用汇编语言编写一个SVC中断来注册. 对外函数接口表采用数组(如BIOS_API)存储, 其入口地址就是数组名或数组的首地址, 函数的编号与数组的下标元素的序号一一对应, 其中,0号表示对外函数的数量,1号函数对应BIOS_API[1], 2号函数对应BIOS_API[2], 依此类推, 换句话说, 可以通过数组元素来访问这些对外函数. 同时, 为了便于扩充或更新对外函数的个数, 还预留了一些缺省的函数名(如DefaultFUN).

格式: BIOS_API:   //对外函数接口表数组

.long函数个数   //0号表示函数个数

.long重定义函数名 //从1开始对函数编号

……

例如: BIOS_API:

.long 134    //共有134个对外函数

.long OS_start  //1号对外函数(启动操作系统)

……

.long thread_wait //4号对外函数(延时函数)

.long DefaultFUN //预留缺省函数

3 接口函数重映射机制

当RTOS提供的对外函数经过重定义、声明、注册, 形成对外函数接口表后, USER程序还需进一步通过重映射机制形成对外函数映射表, 才能最后在USER中实现对函数的调用.

3.1 对外函数接口表的映射

当RTOS的对外函数接口表形成之后, 此时RTOS提供的函数已经变成了一段机器码, 必须先将BIOS的对外函数接口表映射成USER的对外函数映射表, 获得存放对外函数接口表的数组首地址, 这样USER程序才能使用它. 为了与BIOS_API数组的元素一一对应, USER程序的对外函数映射表也采用数组(如USER_API), 用它来存放对外函数接口表的地址. 这样, 当USER使用USER_API时就相当于使用BIOS_API, 也就是说, USER通过USER_API就可以访问BIOS提供的对外函数.

在USER中, 采用SVC中断的方式来实现对外函数接口表的映射. 因此, 在BIOS中先要将SVC中断重定向为用户的SVC_IRQ, 接着在USER中调用svc1_init函数触发BIOS中的SVC_IRQ中断, 然后由SVC_IRQ中断触发实际的SVC封装函数SVC_HandlerS, 最后在这个汇编程序SVC_HandlerS中实现将BIOS提供的对外函数接口表的入口地址映射到对外函数映射表中, 汇编函数SVC_HandlerS实现流程如图2所示.

3.2 对外函数的重定向

当对外函数映射表形成之后, 此时USER就可以通过USER_API数组访问函数, 如USER_API[1]访问的是1号对外函数. 但采用USER_API[i]这种形式对具体要访问的对外函数的类型、函数名、参数以及功能等不够清晰明了. 因此, 类似中断向量重定向的做法, 也可以重定向对外函数, 重新给USER_API[i]取另外一个用户熟悉的函数名, 这个函数名可以与对外函数名同名, 也可以是不同名的, 这样就可以为用户提供函数原型级接口, 易于用户记住和使用,图3描述了从RTOS的原型函数到最终实现用户实际调用函数的映射关系. 函数重定向宏定义的一般形式如下:

图 2 汇编函数SVC_HandlerS实现流程

图 3 对外函数映射关系示意图

#define 函数重定向名 ((对外函数声明指针表达形式) (全局数组[对外函数编号]))

例如:

#define delay ((void (*)(uint_32 millisec)) (USER_API[4]))

3.3 对外函数的调用

当对外函数重定向之后, 就可以利用重定向后的名字来调用函数. 例如, 当USER调用delay函数时, 实际上是指向了USER_API[4], 而USER_API[4]对应BIOS_API[4], BIOS_API[4]存放的是thread_wait函数的入口地址, 而thread_wait函数实际上就是Thread::wait函数. 因此, 可以认为USER通过调用delay函数达到调用Thread::wait函数的目的.

4 mbedOS下的应用实践

2014年ARM公司推出了mbedOS, 它是一种专为物联网 (IoT) 中的“物体”设计的开源嵌入式实时操作系统[17].本文选用mbedOS进行应用实践, 测试工程在Kinetis Design Studio 3.0.0 IDE集成开发环境和金葫芦AHL-A系列Cortex-M0+内核的KL36微控制器[18](即AHL-AN100VL型号开发板)上进行. KL36片内Flash大小为64 KB, 一般用来存放中断向量、程序代码、常数等; 片内RAM为静态随机存储器SRAM, 大小为8 KB, 一般用来存储全局变量、静态变量、临时变量(堆栈空间)等.

4.1 mbedOS提供的对外接口函数

使用KL36微控制器作为mbedOS驻留的硬件载体, 考虑其Flash和RAM空间大小的因素, 在mbedOS驻留于BIOS时, 对Flash空间采用分割独享方式划分. 对RAM空间可采用分割独享和重叠共享方式划分, 如图4所示, 在分割独享方式中BIOS和USER各占一半的RAM空间; 本文采用重叠共享方式, BIOS占全部RAM空间, USER占一半以上的RAM空间, 这样可以最大程度地提高RAM空间的利用率. 根据前面介绍的RTOS对外函数接口设计方法和重映射机制, 可以将mbedOS提供的启动、线程、延时、事件、消息队列、信号量和互斥量等函数进行重定义、声明、注册、映射、重定向, 最后提供给用户程序调用. mbedOS提供的对外函数原型名称、对外函数二次封装名称以及重定向函数名称之间的映射关系如表1所示, 仅列举了本测试工程中使用到的对外接口函数.

图 4 RAM空间划分示意图

表 1 部分对外函数重定向一览表

4.2 功能性测试

测试工程的功能是创建两个任务, 实现每2秒红灯闪烁一次, 蓝灯任务每1秒切换亮暗一次, 绿灯任务当收到蓝灯任务的信号(17)时, 切换绿灯亮暗. 当芯片上电之后, 首先启动BIOS, 接着转到USER的启动, 在USER的启动过程中通过映射对外函数接口表形成对外函数映射表, 并重定向对外函数. 然后启动mbedOS, 并创建和启动蓝灯任务和绿灯任务, 最后在一个无限循环中使红灯每2 s闪烁一次, 同时对蓝灯任务和绿灯任务进行调度. 蓝灯任务主要完成每秒闪烁一次, 并设置信号; 绿灯任务主要是等待信号, 当收到信号后闪烁一次. 测试工程的执行流程如图5所示.

在测试工程中主要调用的对外函数有: 操作系统启动函数OsStart、任务创建函数create、任务启动函数start、延时函数delay、信号设置函数signal_set和信号等待函数signal_wait等, 其功能性测试结果如图6所示, 从中可以看出能精准调用这些对外函数, 程序的功能得到准确的实现, 说明对外函数接口设计正确.

4.3 编译时间测试

编译时间的测试是在联想笔记本电脑K49上进行, 其CPU型号为Intel Core i7-3520M, 主频2.9 GHz, 内存8 GB, 采用64位的Windows 7操作系统. 测试工程针对KL36 (采用Kinetis Design Studio 3.0.0 IDE编译环境)、S32K144 (采用S32 Design Studio for ARM v1.3编译环境)和MSP432 (采用Code Composer Studio 6.2.0编译环境)微控制器分别对mbedOS是否驻留BIOS的USER程序进行编译时间测试, 测试结果如表2所示. 从表2中可以看出, 将mbedOS驻留在BIOS中, USER程序可以节约2~3倍的编译时间, 从而提高了用户程序的开发效率.

图 5 测试工程执行流程

图 6 功能性测试结果

表 2 驻留与非驻留时USER程序编译时间

5 结论与展望

为充分发挥实时操作系统的强大功能, 本文给出了RTOS在BIOS中的驻留方法, 在GEC架构下提出了RTOS对外接口函数的设计方法, 剖析了接口函数重映射机制, 为用户提供函数原型级的调用接口. 最后以NXP的KL36芯片为例, 在mbedOS进行应用实践, 测试表明对外函数接口的设计是正确的, 有效地解决了函数调用的困难, 提高用户程序的可靠性, 为RTOS的应用研究提供了基础. 后续还将进一步探索用户程序在不同RTOS上的可移植性问题, 本文涉及到的测试工程可到苏州大学嵌入式学习社区网站(网址: http://sumcu.suda.edu.cn)的“教学培训-教学资料-mbedOS”位置, 下载“SD_mbedOS_API”查看.

参考文献
[1]
王宜怀, 张建, 刘辉, 等. 窄带物联网NB-IoT应用开发共性技术. 北京: 电子工业出版社, 2019.
[2]
张美玉, 张倩颖, 孟子琪, 等. 实时嵌入式双操作系统架构研究综述. 电子学报, 2018, 46(11): 2787-2796. DOI:10.3969/j.issn.0372-2112.2018.11.029
[3]
李正, 吴敬征, 李明树. API使用的关键问题研究. 软件学报, 2018, 29(6): 1716-1738. DOI:10.13328/j.cnki.jos.005541
[4]
Tsai CC, Jain B, Abdul NA, et al. A study of modern Linux API usage and compatibility: What to support when you’re supporting. Proceedings of Eleventh European Conference on Computer Systems. London, UK. 2016. 1–16.
[5]
Atlidakis V, Andrus J, Geambasu R, et al. POSIX abstractions in modern operating systems: The old, the new, and the missing. Proceedings of the Eleventh European Conference on Computer Systems. London, UK. 2016. 19.
[6]
Bavota G, Linares-Vásquez M, Bernal-Cárdenas CE, et al. The impact of API change- and fault-proneness on the user ratings of Android apps. IEEE Transactions on Software Engineering, 2015, 41(4): 384-407. DOI:10.1109/TSE.2014.2367027
[7]
Li L, Bissyande TF, Le Traon Y, et al. Accessing inaccessible android APIs: An empirical study. Proceedings of 2016 IEEE International Conference on Software Maintenance and Evolution (ICSME). Raleigh, NC, USA. 2016. 411–422.
[8]
Nadi S, Krüger S, Mezini M, et al. Jumping through hoops: Why do Java developers struggle with cryptography APIs? Proceedings of the 38th International Conference on Software Engineering. Austin, TX, USA. 2016. 935–946.
[9]
汪昕, 陈驰, 赵逸凡, 等. 基于深度学习的API误用缺陷检测. 软件学报, 2019, 30(5): 1342-1358. DOI:10.13328/j.cnki.jos.005722
[10]
Liang B, Bian P, Zhang Y, et al. AntMiner: Mining more bugs by reducing noise interference. Proceedings of the 38th International Conference on Software Engineering. Austin, TX, USA. 2016. 333–344.
[11]
Murali V, Chaudhuri S, Jermaine C. Bayesian specification learning for finding API usage errors. Proceedings of the 2017 11th Joint Meeting on Foundations of Software Engineering. Paderborn, Germany. 2017. 151−162.
[12]
Thung F. API recommendation system for software development. Proceedings of the 31st IEEE/ACM International Conference on Automated Software Engineering (ASE). Singapore, Singapore. 2016. 896–899.
[13]
吕晨, 姜伟, 虎嵩林. 一种基于新型图模型的API推荐系统. 计算机学报, 2015, 38(11): 2172-2187.
[14]
Treude C, Robillard MP. Augmenting API documentation with insights from stack overflow. Proceedings of the 2016 IEEE/ACM 38th International Conference on Software Engineering. Austin, TX, USA. 2016. 392–403.
[15]
Zhou J, Walker RJ. API deprecation: A retrospective analysis and detection method for code examples on the Web. Proceedings of the 2016 24th ACM SIGSOFT International Symposium on Foundations of Software Engineering. Seattle, WA, USA. 2016. 266–277.
[16]
夏艳敏, 唐兵, 唐明董, 等. 利用关联规则挖掘的Web API组合模式发现. 小型微型计算机系统, 2019, 40(10): 2195-2201. DOI:10.3969/j.issn.1000-1220.2019.10.031
[17]
Bock C, Marquardt M, Martens A, et al. Smart sensors and actors with BACnetTM and mbed OS on cortex-M microcontrollers. Proceedings of the 2019 IEEE 5th World Forum on Internet of Things (WF-IoT). Limerick, Ireland. 2019. 937–942.
[18]
NXP. KL36 sub-family reference manual. https://www.nxp.com/docs/en/reference-manual/KL36P121M48SF4RM.pdf. (2013-07-03)[2019-09-25].