单片机
返回首页

Cortex-M3内核的μC/OSII操作系统的安全性和稳定性研

2018-04-11 来源:eefocus

    引言

    μC/OSII是基于优先级的可剥夺型内核,系统中的所有任务都有一个唯一的优先级别,它适合应用在实时性要求较强的场合;但是它不区分用户空间和系统空间,使系统的安全性变差。而移植到CortexM3内核上的μC/OSII系统一般是运行在特权级下,以至于应用程序也可以访问操作系统的变量和常量,这样使得系统的安全性与稳定性变得更差。


    根据CortexM3内核的特点,对μC/OSII操作系统的安全性和稳定性进行研究。利用CortexM3内核上选配的MPU(Memory ProtectiON Unit,存储器保护单元),对μC/OSII操作系统做适当的改进与优化。经测试,系统的安全性与稳定性得到很大的提高。

    1 开发坏境

    采用IAR5.30作为开发环境,移植μC/OSII2.86到CortexM3内核,选用配置了MPU(Memory Protection Unit,存储器保护单元)的LPC1786处理器作为硬件实验平台,对操作系统的安全性和稳定性进行改进与优化。

    2 CortexM3内核简介

    在CortexM3内核*有两个堆栈指针:主堆栈指针(MSP),是系统上电后缺省的堆栈指针,它由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用;进程堆栈指针(PSP),用于常规的应用程序代码(不处于异常服务例程中时)。

    CortexM3处理器支持线程模式和处理模式两种工作模式,有特权级与用户级两个访问等级。异常处理总是工作在处理模式,只可使用主堆栈指针。处理模式总是在特权级下运行,而线程模式可在特权和用户级下运行。系统复位时总是处于线程模式的特权方式下,并且默认使用的堆栈指针是MSP。在用户级下,对特殊功能寄存器和系统控制空间(SCS)的大部分寄存器的访问是禁止的[2]。

    经实验验证,在用户级下使用MSR、MRS指令访问特殊功能寄存器(CONTROL等),这些指令被当作NOP指令(空指令)执行,而对系统控制空间(SCS)寄存器访问会产生精确的总线访问异常。

    另外,CortexM3内核还可以选配MPU(如LPC1700系列、LM3S系列处理器),用于对存储器进行保护。设定一块内存的访问权限,对系统的安全性有很好的帮助。

    3 μC/OSII内核简介

    μC/OSII是一个可移植、可固化、可裁剪的抢占式实时多任务内核。大部分用ANSI C语言编写,只有一小部分与硬件相关的代码用汇编语言编写。至今,μC/OSII已经在40多种不同架构的微内核处理器上移植成功[4]。μC/OSII内核只提供了任务调度、任务管理、时间管理和任务间通信等基本功能,体系结构如图1所示。进行系统移植时,只需要修改OS_CPU_C.C、OS_CPU.H、OS_CPU_A.ASM这3个文件即可。

搜狗浏览器截图(3).jpg

图1 μC/OSII体系结构

4 μC/OSII操作系统移植的改进

μC/OSII*****提供的基于CortexM3内核移植的μC/OSII系统一直工作在特权级下。这样做的好处是,系统不用频繁地切换访问等级,而且开关中断很快,利于实时性的实现;但是应用程序(用户任务)也可以访问特殊功能寄存器和系统控制空间(SCS)寄存器,修改操作系统的变量,这对系统的安全性是一种威胁,如果用户任务程序跑飞,那就有可能破坏系统寄存器和变量[5]。

4.1 系统寄存器的设置

用户应用程序运行在用户级,使用PSP堆栈指针;操作系统函数运行在特权级,使用的也是PSP堆栈指针;而中断服务例程运行在处理模式的特权方式下,使用MSP堆栈指针。

特权与用户级分区

图2 特权与用户级分区

首先利用MPU把内存分为特权级访问和用户级访问两个区,如图2所示。在系统初始化时,设置MPU相关寄存器,为系统分配任务堆栈与主堆栈:任务堆栈分配在用户区,系统变量与主堆栈分配在特权区,只可特权级下访问。

4.2 系统函数的修改

用户任务工作在用户级下,操作系统函数工作在特权级下,任务可能会在执行系统函数时执行上下文切换,因此系统要记录任务切换时是处在特权级还是用户级下,以便任务再次获得处理器控制权时,切换到原先的访问等级下。在任务创建时,加入访问权限参数mode。

权限的值定义为:

#define OS_Mode_USER 1u //用户级
#define OS_Mode_PRIVILEGE 0u //特权级
在创建任务函数与堆栈初始函数的参数中加入访问权限参数,形式如下:
INT8U OSTaskCreateExt (……,INT8U mode );
OS_STK *OSTaskStkInit (……,INT8U mode);

在堆栈初始化时,把mode最后存到堆栈当中,以便任务第一次运行时进入相应的工作模式(特权级或用户级)。统计任务和空闲任务的mode是OS_Mode_PRIVILEGE,而用户任务为OS_Mode_USER。

4.3 OS_CPU_A.ASM文件中函数的修改

在OS_CPU_A.ASM文件中,只需修改函数PendSV_Handler(PendSV服务例程),任务切换是由它来完成的。同时,设置PendSV的优先级为最低,以便快速响应中断,提高系统的实时性。PendSV服务例程的流程如图3所示。

搜狗浏览器截图(4).jpg

图3 PendSV服务例程流程

任务切换上文的程序:

SUBS R0,R0,#0x24;调整PSP指针,mode、R4~R11共36字节
MRS R1,CONTROL;获取当前任务的访问等级mode
STM R0,{R1,R4R11};压栈mode,R4~R11


LDR R1,=OSTCBCur;获取OSTCBCur?﹥OSTCBStkPtr
LDR R1,[R1]
STR R0,[R1];存储PSP值到任务控制块切换下文的程序:
……;OSPrioCur=OSPrioHighRdy;
……;OSTCBCur=OSTCBHighRdy;
……;得到新任务的PSP值,存储到R0中
LDM R0,{R1,R4R11};R1(mode),R4~R11出栈
MSR CONTROL,R1;修改CONTROL[0]
ORR LR,LR,#0x04;选择返回时使用的堆栈
ADDS R0,R0,#0x24;调整PSP值
MSR PSP,R0;R0存入PSP中


4.4 系统函数的使用

系统函数都是在特权级下执行的,在应用程序中调用系统函数前应该切换到特权级,系统函数执行完毕后再切换后用户级。调用形式如下:

ToPrivilege ();
OSFunction(Parameter1, Parameter2……);//系统函数
ToUser ();

在特权级下可以通过置位CONTROL[0]来进入用户级。用户级下是不能通过修改CONTROL[0]来回到特权级的,必须通过一个异常handler来修改CONTROL[0],才能在返回到线程模式后取得特权级。因此,从用户级到特权级的方法就是产生一个异常,再在异常例程中修改CONTROL[0]。通常的方法是使用软中断SVC。

切换到特权级的代码如下:

ToPrivilege;函数ToPrivilege ()
SVC 0
BX LR
SVC_Handler;SVC服务例程
MRS R1,CONTROL
AND R1,R1,#0xFE
MSR CONTROL,R1;回到特权级
BX LR

而从特权到用户级就简单了,只要执行切换程序就可以了,不用产生异常。切换到用户级的代码为:

ToUser;函数ToPrivilege ()
MRS R0,CONTROL
ORR R0,R0,#0x01;切换到用户级
MSR CONTROL,R0
BX LR

4.5 其他改进方法

任务在用户级+PSP下运行,而操作系统函数运行在特权级+MPS运行,中断服务例程有硬件设定在处理模式+特权级+MSP,这样系统的安全性和稳定性会更高。但是每个任务需要两个堆栈PSP、MSP。这样无疑增加了内存的使用(将近增加一倍),由于嵌入式芯片的片内RAM比较小,增加内存必然会增加成本,并且要对任务控制块做相应的修改,存储两个堆栈。任务创建时对这两个堆栈都要初始化,任务切换时判断切换的堆栈与访问权限,这些都增加了系统的开销。

结语

系统连续稳定地运行10个小时以上没出现任何问题,可见系统移植成功。利用CortexM3内核选配的MPU,对μC/OSII操作系统进行修改,只是增加了很小的系统开销,却使系统的安全性和稳定性得到了很大的提高。该方法可应用于对系统安全性与稳定性要求比较高的场合。


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • RS-485基础知识:处理空闲总线条件的两种常见方法

  • 如何调制IC555振荡器

  • 基于ICL296的大电流开关稳压器电源电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章