[Raw-OS] MPU内存保护模块

jorya_txj   2013-9-8 10:44 楼主
对于C语言等静态语言编程的时候最隐晦的出错问题是数组溢出。数组溢出问题通常是动态执行程序的时候出现的问题,表现出来的错误形式千变万化。对于debug带来很大的难度,随着代码量的增大,寻找出这样一个错误一定程度上伴随着运气成分,运气差点的话需要花大量的时间去锁定错误,跟踪错误,进而去解决。



下图是通用型操作系统的系统设计模式:

mpu.png

内存保护单元的主要功能是实现用户模式和内核模式的数据代码隔离,传统的操作系统还会完全隔离用户模式下的进程代码数据,但是进程切换的时候会带来很大的时间和空间的开销,其效率很低下。



实时操作系统的任务栈溢出是永远的痛,目前任何一种软件检查栈的方式都不能100%检查出来栈的溢出。任务栈溢出本质上也是属于数组溢出形式之一。

对于某些高度安全的领域,执行在用户态的任务,由于不可控制的硬件和软件问题,突发的错误的的去访问内核态的代码以及变量,在某些情况下很可能会出安全事故。比如一个马达驱动是在内核层,但是应用层由于某种原因失控去操作内核层,如果这个时候不去禁止的话,很可能会造成重大事故。



综上所述,对于debug以及安全,均需要一套机制去保护用户态的任务的栈空间以及全局变量。目前主流操作系统,比如linux 和windows 都是利用mmu 的保护模式去保证用户态的进程之间的数据独立,以及禁止用户态的线程。但是线程之间如果有数组溢出问题的话,还是解决不了,因为线程之间的数据还是共享的。还有mmu因为涉及到页表交换,地址映射等软件和硬件操作,无论性能和实时性上都会打折扣。Arm9的cpu打开mmu会速度增加的原因是cache必须依赖mmu,只有mmu打开了cache是能才有用,但是mips cpu 的设计是这两块都是独立的。

对于mpu来说所有的物理地址等于虚拟地址,硬件不会做虚地址翻译成实地址的事情,而且任务切换交换的不是页表,而是几个硬件寄存器,在时间上完全是可以预测的,对于性能和实时性不会有任何损害。



对于目前实现MPU的实时系统,寥寥无几,而且都是闭源的。比如uC/TimeSpaceOS, 以及uC/OS-MPU,不但闭源而且从没有公布源码。Threadx也有类似的MPU保护模块,但是threadx源码是全部闭源的。目前只有freertos 开源出来了MPU保护模块,但是代码较复杂,而且功能模块的实用性还是需要在实践中去衡量的。



raw os以简洁的代码实现了整个MPU保护模块,而且秉承着开源到底的作风,放出了整块源码。raw os 秉承着一切皆可以仿真的作风,利用keil mdk 成功的仿真出来整个raw os + MPU的系统功能。下面描述raw os的mpu保护模块功能:



1 任务分可以创建为用户态任务或者内核态任务。

2 用户态的任务不能访问内核态的指令以及数据。

3 用户态的各个任务之间的数据都是隔开的,相互之间不允许访问。比如用户态的栈空间之间都是隔开的,只要一越界,立马被MPU侦测到。

4 用户态的任务除了能访问各自的栈外,还能访问各自定义的3个region, 就是说可以自定义3块memory 供用户态的任务去访问。3个region在任务创建的时候指定,但是在运行阶段也可以动态改变这3个region的定义。

5内核态的任务也适用于第4条。

6 3个用户自定义的region 可以各自设置为只读,或者读写,或者不可访问模式。

7 用户态的任务之间不允许共享内存,数据可以通过内部的操作系统api, 比如queue等去通讯。用户态之间的任务可以通过任务创建的时候的3个region设置去共享内存,但是这个是不推荐的。

8 raw os的内核api可以全部放在flash 的一个region 中,设置为只能内核态的任务才能去访问。假如用户态的任务调用rawos 的api, 会马上切换模式为内核态然后调用内核态的raw os api。

9 raw os 的内核数据可以放在一个region 中,设置为只有内核态的任务才能访问。

10系统级别的寄存器只能在内核模式访问,比如control寄存器,外设的寄存器,可以在用户态和内核态访问,但是也可以设置为只能内核态访问外设寄存器,看用户的需求。

raw os的mpu保护模块功能一定程度上参考了freertos 的mpu 模块的设计方法,感谢freertos的mpu的作者。freertos的mpu模块地址如下:
感兴趣的可以进一步了解它的实现原理等。




关于mpu模块的寄存器功能请参考arm官网的文档,已经有很详细的描述,这里不再描述。模块下载地址为: http://www.raw-os.org/module.html


官网已经放出mpu模块的demo,在shell_task.c里面创建了两个任务,其中创建了一个用户态的任务。读者感兴趣的可以利用keil mdk仿真自己去设置一些参数,以及调试一些代码,用来验证上述理论。



以上所述的方法是内核态和用户态代码是在同一个bin文件里面,但是更好的设计方法是用户态和内核态的采用两个bin文件,彻底隔离开来。mpu内存保护模块在rtos中的运用还刚刚开始,相信未来会更进一步的成熟应用。


[ 本帖最后由 jorya_txj 于 2013-9-8 10:46 编辑 ]

回复评论 (2)

看看了啊
点赞  2013-9-9 17:30
raw os 官网:www.raw-os.org
点赞  2013-10-9 09:51
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复