Cortex-M v7 内存保护单元 (MPU) 很难使用,但它是 Cortex-M3、-M4 和 -M7 处理器可用的硬件内存保护的主要手段。这些处理器广泛用于中小型嵌入式系统。因此,学习有效地使用 Cortex-M v7 MPU 以实现现代嵌入式系统所需的可靠性、安全性和安全性非常重要。
以前的博客介绍了 MPU和术语、MPU 多任务处理和定义 MPU 区域。在第一篇博客中,定义了特权任务 ( ptasks) 和非特权任务 ( utasks)。前者以特权线程模式运行,后者以非特权线程模式运行[2]。任务的模式umode由其任务控制回(TCB)中的标志确定,并在实时操作系统(RTOS)调度程序调度时生效。umode可以在创建任务后随时设置标志pmode。
ptasks可以直接调用系统服务,但是utasks不能。有两个原因:
保护 RTOS 及其数据免受utasks. 这可能是未知谱系的软件 (SOUP),或者它可能容易受到恶意软件的攻击(例如,TCP/IP 堆栈)。
限制此软件可以使用的 RTOS 服务。不希望utasks能够执行可能损害正常系统操作的操作,例如断电或删除任务。
本博客讨论了实现上述保护的机制。应该注意的是,MPU 安全性的主要目标是将尽可能多的应用程序代码放入utasks.
utask MPA 地区
每个任务都有自己的内存保护数组 (MPA),它是从 MPA 模板初始化的。一个utask(例如ut2a)的典型 MPA 模板如下:
该模板在创建任务后加载到任务的 MPA 中,然后在分派该任务时加载到 MPU 中。MPA[0]任务堆栈的区域是在任务首次启动时定义并放入的。因此,上面utask可以访问它自己的堆栈、它自己的代码和数据区域、公共代码和数据区域,而没有其他任何东西。区域 5、6 和 7 被禁用或特权。因此,这utask被阻止直接访问系统服务和数据。后者适用于 all utasks,尽管它们的模板可能不同。
umode 服务
utasks必须使用软件中断 (SWI) 应用程序编程接口 (API) 来访问系统服务,并且他们永远无法直接访问系统数据。此外,只有不受限制的系统服务才能被utasks. 这些障碍有助于保护操作系统 (OS) 免受不受信任的代码的影响。
SWI API 是通过 Cortex-M SVC 指令“ SVC n”实现的,其中n指定要执行的系统服务。
对于 smx RTOS 内核,头文件 ,xapi.h包含所有 smx 服务的原型函数。在开头包含此文件pcode允许它访问其中任何一个。对于ucode,xapiu.h被定义。它由 。 中允许的系统服务的映射宏组成umode。例如:
这个宏覆盖了函数原型,xapi.h因此对于应用程序模块的其余部分,它不是直接调用系统服务,而是调用一个 shell 函数:
该外壳函数用于调用n == ID系统服务的 SVC 指令。NI(Not Inline) 是一个由编译器阻止函数内联的宏。请注意,shell 函数具有相同的名称,只是它的前缀smxu_不是smx_. 贝壳位于该ucom_code区域中,因此它们可以通过utasks.
应用程序模块可以以pcode开头ucode,也可以完全是pcode或ucode。无论哪种方式,ucode都以:
在那之后不能直接调用任何系统服务。以上所有内容都是在编译时完成的,因此变成了硬编码,因此可以抵抗恶意软件和错误,特别是如果代码位于 ROM 中。
混合pcode/ucode模块很方便,因为系统的功能部分通常会有一个根任务,它是一个ptask为该部分创建、初始化和启动所有其他任务的任务,其中大部分可能是utasks. 因此,所有相关的任务都可以放在一起。内在的想法是系统部分的某些任务可能是执行关键任务功能的精心构建的任务。这些任务可能是ptasks。系统部分的其他任务可能正在执行非关键功能,例如收集要发送到云的统计信息。这些将是utasks.
有些任务可能会随着项目的发展而开始存在ptasks并被迁移到。utasks通常更容易在其中调试代码pmode然后将其移至umode. 此外,任务可以启动ptasks并执行pcode,设置自己的umode标志,然后重新启动自己utasks并执行ucode。
另一个有趣的特性是xapiu.h可以部署多个文件并由不同的utasks. 这允许不同级别的信任。因此,与可信度较低的任务相比,可信度更高的任务可以访问更多的 RTOS 服务。这允许收紧 SOUP 或高度易受攻击的任务的绞索。但是,这仅在编译时有效。为了防止恶意软件,还需要有对应于不同xapiu.h文件的不同跳转表(参见下面的图 5)以及为每个任务选择跳转表的机制。
utask服务调用机制
如上所述,软件中断 API 的基本概念非常简单。但是当调用的系统服务可能导致任务切换时,事情就变得更加复杂了——尤其是对于 Cortex-M 架构,它要求 RTOS 调度程序驻留在PendSV_Handler. 同样复杂的是,处理程序以特权模式运行并使用系统堆栈 (SS)[3] 而不是当前的任务堆栈 TS。
如下图所示,SVC_Handler()由 SVC 指令调用并以处理程序模式运行:
开始运行时,由于处理器堆叠SVC_Handler(),系统服务参数处于 TS 中。处理程序将参数 0 到 3 移动到thru中,并将第 5 个参数(如果有)移动到系统堆栈的顶部,SS(这是系统服务期望找到这些参数的地方)。然后通过跳转表调用系统服务(SSR),使用传递给它的索引(ID)(见上文)。r0r3SVC_Handler()ssrt[]n
系统服务正常执行并返回SVC_Handler(),将系统服务返回值从r0TS 移动到正确位置。处理器执行的处理程序返回操作将TS 中所有堆叠的寄存器取消堆叠,因此返回值以r0.
如果系统服务导致任务调度程序需要运行 ( sched 》 0) 或中断导致链接服务例程 (LSR) 调度程序需要运行 ( lqctr 》 0),PendSV_Handler() 则将被挂起。在这种情况下,处理器尾链 [4] 从SVC_Handler()到PendSV_Handler(由图中的虚线所示),而不是返回到utask.
在这种情况下,控制不会返回到utask尚未调用的点,而是返回到在PendSV_Handler()。 这可能会导致当前任务被挂起,而另一个任务被恢复运行(如图右侧所示)。抢占任务可以是 autask或 a ptask。最终,挂起的utask将被恢复、取消堆栈,并从调用点继续运行,前提是它没有被抢占任务停止或删除。(注意:以上所有操作都是在特权模式下完成的,因此可以防止受到感染的恶意软件的侵害ucode。)
ptask服务调用机制
相比之下,下图显示了从ptask.
请注意,这更简单(更快):SVC_Handler()不涉及。ptask直接调用系统服务,如果设置sched,PendSV_Handler()则挂起。从那里开始,操作与 a 的操作相同utask。
交叉操作
无论系统服务是从utasks还是调用,系统服务的操作都是一样的ptasks。例如,autask可以测试一个信号量并在它上面挂起。Aptask可以发出信号量并且utask将恢复。或相反亦然。Aptask可能具有比 a 更高或更低的优先级utask,调度程序将根据其优先级调度它(特权在这里没有优先级!)。不同的是,ptask执行受信任的代码 ( pcode) 并且通常可以完全访问内存、外围设备和系统服务,而utask执行非特权代码 ( ucode) 并且只能访问 MPU 允许的内容。此外,MPU 只能通过 更改pcode。
以免担心ptasks不受约束的代理,请注意,即使启用了后台区域,也可以阻止通过 MPU 访问区域。因此,对一个任务进行读/写 (RW) 的区域可能对另一个任务是只读 (RO) 并且从不对两者执行 (XN)。另一方面,ptasks确实可以直接访问所有 smx 服务。随着系统安全性的加强,应考虑限制ptasks以及utasks.
审核编辑:郭婷
-
处理器
+关注
关注
68文章
19136浏览量
228958 -
嵌入式
+关注
关注
5064文章
18996浏览量
302608 -
API
+关注
关注
2文章
1481浏览量
61776
发布评论请先 登录
相关推荐
评论