Chinaunix首页 | 论坛 | 博客
  • 博客访问: 46255
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-06 15:00
文章分类

全部博文(15)

文章存档

2013年(15)

我的朋友

分类: 嵌入式

2013-10-15 15:13:34

对于个人用户来说MQX的用户模式似乎显得有些多余,花费不少资源,故意找一些东西限制住自己看起来真的是没有什么必要。但从freescale官方来说,完善系统的权限机制还是相当有必要的,针对多人协作开发的项目来说,搞底层的人搞底层,搞应用的搞应用,靠着系统调用作为衔接,分工明确,责任分明。在这点上,就像linux这类成熟的通用操作系统平台了。

所谓用户模式,就是设计了特权级和用户级两个权限标志,用户级被一些定义好的条条框框限制住,防止越权访问。不过实现这个机制的前提要用硬件支持,牛逼一点的就用MMU,搞出一套地址映射机制,把这个实际的地址空间全部对用户屏蔽,然后在这之上细分各种权限。不过K60没有这么高端的MMU,只有一个功能简单了许多的MPU,以此来实现权限机制。

先说一下K60的MPU机制。所谓MPU(Memory Protection Unit),就是规定了某一个主设备运行在不同的权限下对某一个地址范围内从设备的操作设置。在K60上,权限只有两个分别是Privileged和Unprivileged,而操作也只有三种:读(r)、写(w)和执行(x)。主设备指的是能够主动发起读、写或是执行请求的设备,而从设备是相应主设备请求的设备。在K60上有多个主设备,也有多个从设备,它们是由总线矩阵的形式连接起来的。


K60上主要有上述M0~M5六个主设备,而MPU最多允许8个设置主设备的权限,看来这个是够用的。这里还要说明的是在x86架构下的MMU的主设备只有CPU一个,虽然我们的电脑也有网卡、usb等设备,但这些设备并不受MMU的控制。既然不受MMU控制,那这些设备会不会与CPU同时对某一块相同的地址同时发起操作请求呢?答案但是“不”,因为这些设备都是插在PCI上面的(usb设备的控制器是PCI设备)。bios会把PCI枚举总线设备获取的地址映射告诉CPU,在建立MMU机制的时候会根据这些外设的地址来完成相应的映射。如果这些外设对某一块地址发出操作请求,CPU就会从PCI上获取对应的信息,一旦允许外设操作,CPU就会在外设访问这段地址空间期间,禁用对其的访问。

回到我们的K60,它的MPU干的事情就是,规定M0~M5这个6个主设备从0XAAAAAAAA到0xBBBBBBBB范围内的地址空间,两个权限Privileged、Unprivileged是否允许进行读、写或执行操作的能力(其实K60只有M0~M4才具备执行能力)。

 

MQX的用户模式就是任务运行在Unprivileged权限下,任务FLAGS有一个TASK_USER_MODE属性,一旦在MQX_template_list里设置某一个任务为MQX_USER_TASK时,在创建该任务的时候就会把任务的FLAGS置为TASK_USER_MODE。但切换到该任务的时候,在dispatchS中


点击(此处)折叠或打开

  1. ASM_LABEL(switch_task)
  2.                 /* update kernel structures */
  3.                 str r1, [r0, #KD_CURRENT_READY_Q] /* store addr for active que */
  4.                 str r2, [r0, #KD_ACTIVE_PTR] /* active task descriptor */

  5.                 ldrh r3, [r2, #TD_TASK_SR]
  6.                 strh r3, [r0, #KD_ACTIVE_SR] /* restore priority mask for enabled interrupt for active task */

  7. #if MQX_ENABLE_USER_MODE || (MQXCFG_ENABLE_FP && PSP_HAS_FPU)
  8.                 ldr r1, [r2, #TD_FLAGS]
  9. #endif

  10. ....

  11. #if MQX_ENABLE_USER_MODE
  12.                 tst r1, #TASK_USER_MODE /* r1 still contain TD_FLAGS, check for user mode task */
  13.                 ite eq
  14.                 moveq r0, #0 /* privilege mode */
  15.                 movne r0, #1 /* user mode */
  16.                 msr CONTROL, r0
  17. #endif

可以看出,一旦任务的FLAGS有TASK_USER_MODE,就会把当前的CONTROL权限设置为Unprivileged,当用户堆栈弹出运行在任务里的时候,就变成用户权限了。

 

在之前的博文“从异常到任务”里我提过,MQX的任务切换主要是通过PendSV异常来完成的,但置为PendSv异常的操作确实同SVC异常来完成的。MQX之所以不直接使用置为PendSV异常,而是通过置为SVC异常,在SVC异常中置为PendSv异常这样绕圈子的方式来完成任务切换的原因在于:在Unprivileged的权限下是无法触发PendSV。换而言之,用户态的任务是无法通过PendSV来切换的任务的,但SVC异常则无此限制。虽然用户模式是MQX的一个可选功能,但MQX采用了统一的函数接口,虽然降低了效率,但增加了代码的通用性。


阅读(1787) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~