ARM Cortex-M 架構(gòu)于 2004 年推出,是目前市場(chǎng)上最流行的 32 位架構(gòu),被大多數(shù)(如果不是所有)主要 MCU 制造商采用。Cortex-M 從一開始就設(shè)計(jì)為對(duì) RTOS 內(nèi)核友好:專用的 RTOS 滴答計(jì)時(shí)器、上下文切換處理程序、用 C 編寫的中斷服務(wù)例程、尾鏈、簡(jiǎn)單的臨界區(qū)管理等等。許多 Cortex-M MCU 實(shí)施都輔以浮點(diǎn)單元 (FPU)、DSP 擴(kuò)展、高度通用的調(diào)試端口和內(nèi)存保護(hù)單元 (MPU)。
在這個(gè)四部分系列的第 2 部分中,讓我們看看如何使用 Cortex-M MPU 來(lái)提高嵌入式設(shè)備的安全性。在此處閱讀其他三個(gè)部分:第 1部分、第 3部分和第 4 部分。
ARM Cortex-M
2004 年,Arm 推出了基于精簡(jiǎn)指令集計(jì)算機(jī) (RISC) 架構(gòu)的新系列 CPU 內(nèi)核,稱為 Cortex-M(M 代表微控制器)。第一個(gè) Cortex-M 被稱為 Cortex-M3,該系列已經(jīng)發(fā)展到包括許多衍生內(nèi)核:Cortex-M0/M0+、Cortex-M4、高性能 Cortex-M7,以及最近推出的 Cortex-M23 和M33 采用 TrustZone 安全技術(shù)。
Cortex-M 處理器系列的程序員模型(見圖 1)高度一致。例如,R0 到 R15、PSR、CONTROL 和 PRIMASK 可用于所有 Cortex-M 處理器。兩個(gè)特殊寄存器 - FAULTMASK 和 BASEPRI - 僅在 Cortex-M3、Cortex-M4、Cortex-M7 和 Cortex-M33 上可用,浮點(diǎn)寄存器組和浮點(diǎn)狀態(tài)和控制寄存器 (FPSCR) 在可選浮點(diǎn)內(nèi)的 Cortex-M4、Cortex-M7 和 Cortex-M33。一些 Cortex-M 實(shí)現(xiàn)還配備了內(nèi)存保護(hù)單元 (MPU)。
【圖1 | 基于 Armv7-M 的 CPU 寄存器模型。]
在上下文切換期間,RTOS 會(huì)保存和恢復(fù) CPU 寄存器和 FPU 寄存器(假設(shè)處理器配備了一個(gè))。因?yàn)?MPU 配置是從表格中獲取的,所以我們只需要在任務(wù)切換時(shí)加載 MPU 寄存器。換句話說(shuō),不需要為被切換的任務(wù)保存MPU配置。詳細(xì)信息將在下一節(jié)中描述。
Cortex-M 特權(quán)級(jí)別
上電時(shí),Cortex-M 以特權(quán)模式啟動(dòng),使其能夠訪問 CPU 的所有功能。它可以訪問任何內(nèi)存或 I/O 位置,啟用/禁用中斷,設(shè)置嵌套向量中斷控制器 (NVIC),以及配置 FPU 和 MPU,等等。
為了保證系統(tǒng)的安全和可靠,特權(quán)模式代碼必須保留給經(jīng)過(guò)充分測(cè)試且已知可信的代碼。由于大多數(shù) RTOS 都經(jīng)過(guò)了徹底的測(cè)試,因此 RTOS 通常被認(rèn)為是受信任的,而大多數(shù)應(yīng)用程序代碼則不是。這種做法很少有例外。例如,通常假定 ISR 是受信任的,因此也可以在特權(quán)模式下運(yùn)行,只要這些 ISR 不被濫用并盡可能短。這是大多數(shù) RTOS 供應(yīng)商的典型建議。
可以使應(yīng)用程序代碼以非特權(quán)模式在 Cortex-M 上運(yùn)行,從而限制代碼可以執(zhí)行的操作。具體來(lái)說(shuō),非特權(quán)模式會(huì)阻止代碼禁用中斷、更改嵌套向量中斷控制器 (NVIC) 的設(shè)置、將模式改回特權(quán)模式以及更改 MPU 設(shè)置以及其他一些事情。這是一個(gè)理想的特性,因?yàn)槲覀儾幌M皇苄湃蔚拇a賦予自己特權(quán),從而改變系統(tǒng)設(shè)計(jì)者實(shí)施的保護(hù)。
由于 CPU 總是以特權(quán)模式啟動(dòng),因此需要從一開始就創(chuàng)建任務(wù)以在非特權(quán)模式下運(yùn)行,或者在啟動(dòng)后不久切換到非特權(quán)模式(通過(guò)調(diào)用 API)。一旦進(jìn)入非特權(quán)模式,CPU 只能在服務(wù)中斷或異常時(shí)切換回特權(quán)模式。
SVC 處理程序
由于非特權(quán)代碼無(wú)法通過(guò) CPU 或 NVIC 禁用中斷,因此應(yīng)用程序代碼被迫使用 RTOS 服務(wù)來(lái)訪問共享資源。因?yàn)?RTOS 服務(wù)需要在特權(quán)模式下運(yùn)行(在關(guān)鍵部分禁用中斷),非特權(quán)任務(wù)必須通過(guò) Cortex-M 上稱為 SuperVisor Call (SVC) 的特殊機(jī)制才能切換回特權(quán)模式。SVC 的行為類似于中斷,但由一條名為 SVC 的 CPU 指令調(diào)用。這也稱為軟件中斷。
在 Cortex-M 上,SVC 指令使用一個(gè) 8 位參數(shù)來(lái)指定調(diào)用者想要執(zhí)行的 256 個(gè)可能的 RTOS 函數(shù)(或服務(wù))中的哪一個(gè)。系統(tǒng)設(shè)計(jì)者決定哪些 RTOS 服務(wù)應(yīng)該對(duì)非特權(quán)代碼可用。例如,您可能不希望允許非特權(quán)任務(wù)終止另一個(gè)任務(wù)(或它本身)。此外,這些服務(wù)都不允許禁用中斷,因?yàn)檫@會(huì)破壞在非特權(quán)模式下運(yùn)行代碼的原因之一。一旦被調(diào)用,SVC 指令將引導(dǎo)至稱為 SVC 處理程序的異常處理程序。
這個(gè)過(guò)程如圖 2 所示。 (1) 一些非特權(quán)代碼執(zhí)行 SVC #5 以等待互斥體。(2) SVC指令強(qiáng)制SVC異常處理程序執(zhí)行。該行為與生成中斷時(shí)相同。SVC 處理程序提取參數(shù)(即值 5)并使用該參數(shù)將 (3) 索引到 SVC 跳轉(zhuǎn)表中。(4) 執(zhí)行所需的 RTOS 服務(wù)(特權(quán)模式),完成后,RTOS 返回到非特權(quán)代碼。
SVC 處理程序是 RTOS 的一部分,因此您不必?fù)?dān)心實(shí)現(xiàn)它。事實(shí)上,無(wú)論您的任務(wù)是在特權(quán)模式還是非特權(quán)模式下運(yùn)行,您的應(yīng)用程序代碼都會(huì)調(diào)用相同的 RTOS API。
通過(guò) SVC 處理程序需要付出代價(jià):額外的代碼和 CPU 周期。在 Cortex-M3 上,SVC 處理程序添加了大約 1 KB 的代碼并執(zhí)行 75 到 125 條 CPU 指令來(lái)執(zhí)行。因此,與從特權(quán)模式調(diào)用相同的 RTOS 服務(wù)相比,由非特權(quán)模式調(diào)用的任何 RTOS 服務(wù)都需要更多的處理時(shí)間。
【圖2 | 限制來(lái)自非特權(quán)代碼的 CPU、NVIC 和 MPU 訪問。]
在非特權(quán)模式下運(yùn)行代碼還可以防止用戶代碼禁用中斷,從而減少鎖定系統(tǒng)的機(jī)會(huì)。當(dāng)然,如果用戶代碼進(jìn)入無(wú)限循環(huán),鎖定仍然可能發(fā)生,尤其是在高優(yōu)先級(jí)任務(wù)或 ISR 中發(fā)生這種情況時(shí)。但是,在這種情況下,可以通過(guò)使用看門狗來(lái)恢復(fù)鎖定。
附帶說(shuō)明一下,如果非特權(quán)任務(wù)嘗試通過(guò) NVIC 禁用中斷,Cortex-M 會(huì)生成故障(總線故障)。您的應(yīng)用程序代碼需要考慮到這一點(diǎn)。
在非特權(quán)模式下運(yùn)行仍然不會(huì)阻止應(yīng)用程序代碼訪問任何內(nèi)存位置和外圍設(shè)備或阻止代碼在 RAM 之外執(zhí)行。這就是 MPU 的用武之地。
Armv7-M 架構(gòu)中的 Cortex-M MPU
Cortex-M(假設(shè)為 Armv7-M)上的 MPU 是一種設(shè)備,它允許進(jìn)程訪問多達(dá)八 (8) 或十六 (16) 個(gè)內(nèi)存或外圍區(qū)域(取決于 MCU 實(shí)現(xiàn))。每個(gè)區(qū)域的位置和大小是可配置的。每個(gè)區(qū)域的大小必須是 2 的冪的倍數(shù),但不能小于 32 字節(jié)。此外,區(qū)域的基地址必須與區(qū)域大小的整數(shù)倍值對(duì)齊。因此,如果該區(qū)域?yàn)?8K 字節(jié),則該區(qū)域必須在 8K 邊界上對(duì)齊。由于 MPU 中可用的區(qū)域相對(duì)較少,因此區(qū)域通常用于限制對(duì) RAM 和外圍設(shè)備的訪問,而不是太多代碼。但是,必須使用至少一個(gè)區(qū)域來(lái)提供對(duì)代碼空間的訪問。
組織內(nèi)存的一種方便方法是將進(jìn)程所需的 RAM 分組到一個(gè)連續(xù)的塊中,如圖 3 所示。每個(gè)進(jìn)程都將以類似的方式設(shè)置。進(jìn)程 A 的擴(kuò)展視圖顯示它由四個(gè)任務(wù)組成,每個(gè)任務(wù)都有自己的堆棧。進(jìn)程 A 還管理一個(gè)外圍設(shè)備??瞻状砜赡苡捎?MPU 的對(duì)齊限制而未使用的內(nèi)存或 I/O 空間。
【圖3 | 按進(jìn)程對(duì)區(qū)域進(jìn)行分組。]
F3(1) 需要一個(gè) MPU 區(qū)域來(lái)提供對(duì)代碼空間的訪問。該區(qū)域可以設(shè)置為只允許訪問與進(jìn)程關(guān)聯(lián)的代碼,但是當(dāng)一個(gè)進(jìn)程與其他進(jìn)程共享代碼(即庫(kù))時(shí),有時(shí)可能會(huì)出現(xiàn)問題。
F3(2) 需要一個(gè) MPU 區(qū)域來(lái)允許進(jìn)程內(nèi)的所有任務(wù)訪問分配給進(jìn)程的外圍設(shè)備。例如,如果進(jìn)程 A 管理一個(gè)以太網(wǎng)控制器,則該區(qū)域必須允許訪問與該設(shè)備關(guān)聯(lián)的所有寄存器。
F3(3) MPU 區(qū)域用于訪問分配給進(jìn)程的所有 RAM。這里假設(shè)進(jìn)程全局變量和進(jìn)程堆由進(jìn)程內(nèi)的所有任務(wù)共享。附帶說(shuō)明一下,不可能使用所有進(jìn)程都可以使用的全局堆,因?yàn)槟鸁o(wú)法設(shè)置 MPU 表來(lái)將一個(gè)進(jìn)程的動(dòng)態(tài)分配內(nèi)存與另一個(gè)進(jìn)程的動(dòng)態(tài)分配內(nèi)存分開。
F3(4) MPU 區(qū)域用于 RedZone 堆棧檢查。事實(shí)上,我們只需要一個(gè)區(qū)域來(lái)覆蓋一個(gè)進(jìn)程中的所有任務(wù)堆棧,因?yàn)槲覀冎恍枰谏舷挛那袚Q期間移動(dòng) RedZone。然而,這意味著每個(gè)任務(wù)將需要一個(gè)稍微不同的 MPU 進(jìn)程表。話雖如此,這在很大程度上取決于 RTOS 在上下文切換期間如何管理 MPU。例如,RTOS 可能決定只加載 MPU 進(jìn)程表中的前七個(gè)區(qū)域,并使用堆棧的基地址加載最后一個(gè)區(qū)域以設(shè)置 RedZone。大多數(shù)時(shí)候,RTOS 將任務(wù)堆棧的基地址存儲(chǔ)在任務(wù)的控制塊 (TCB) 中。使用這種方案,一個(gè)進(jìn)程中的所有任務(wù)可以共享完全相同的進(jìn)程表,同時(shí)為任務(wù)堆棧正確設(shè)置 RedZone。
F3(5) 這表示由于 Cortex-M 的 MPU 要求所有區(qū)域的大小必須是 2 的二進(jìn)制冪而導(dǎo)致的未使用 RAM。因此,如果進(jìn)程 A 需要 7 KB 或 RAM,則由于進(jìn)程 A 需要 8 K,因此會(huì)丟失 1K。您可能只想增加某些堆棧的大小,而不是浪費(fèi)該空間在進(jìn)程中減少堆棧溢出的機(jī)會(huì)。但是,這樣做的缺點(diǎn)是,如果您需要向進(jìn)程添加功能,那么您可能不記得可以回收多少內(nèi)存。事實(shí)上,從安全關(guān)鍵的角度來(lái)看,如果您使用內(nèi)存配置來(lái)限定您的系統(tǒng),那么您可能無(wú)法收回它。因此,最好分配進(jìn)程所需的堆棧并忍受浪費(fèi)的空間。
從程序員的角度來(lái)看,Cortex-M MPU 是一個(gè)相當(dāng)簡(jiǎn)單的設(shè)備,它由 19 個(gè) 32 位寄存器組成,如圖 4 所示。您會(huì)注意到,該模型與圖 1 中的模型不同,因?yàn)橐恍┘拇嫫鲗?shí)際上是存儲(chǔ)的,因此可以間接尋址,但在內(nèi)部,它們就是這樣出現(xiàn)的。
【圖4 | Cortex-M MPU 寄存器。]
TYPE寄存器用于決定MPU支持的MPU區(qū)域數(shù)量,該寄存器的DREGION字段會(huì)一直讀為0、8或16。CTRL寄存器用于配置MPU的某些方面,但實(shí)際上,該寄存器用于啟用或禁用 MPU。事實(shí)上,在更改任何或所有區(qū)域的配置之前,應(yīng)禁用 MPU。RNR編號(hào)允許您尋址特定的 MPU 區(qū)域。
參考圖 4,您會(huì)注意到 RBAR 的低五位具有固定值。當(dāng)設(shè)置為 1 時(shí),“V 位”表示低 4 位用于指定區(qū)域編號(hào)。RBAR 的高位用于指定區(qū)域的基地址?;刂繁仨氃谂c區(qū)域大小匹配的邊界上對(duì)齊;例如,1 KB 區(qū)域必須在 1 KB 邊界上對(duì)齊。
在大多數(shù)情況下,為給定區(qū)域設(shè)置屬性非常簡(jiǎn)單:
RASR.XN 當(dāng)區(qū)域覆蓋 RAM 并且您不希望在該區(qū)域之外執(zhí)行代碼時(shí),強(qiáng)烈建議您將此位設(shè)置為 1。這將捕獲來(lái)自黑客的代碼注入攻擊。
RASR.AP: 如果該區(qū)域覆蓋了 RAM 區(qū)域,那么您將這些位設(shè)置為“011”,如果該區(qū)域覆蓋 ROM,則將該字段設(shè)置為“110”。
RASR.TEX SCB 圖 4 顯示了基于內(nèi)存區(qū)域所在位置的這些位的典型值。
RASR.SRD 此字段允許您將區(qū)域細(xì)分為八個(gè)相等的部分。此功能可以大大減少內(nèi)存浪費(fèi)。例如,一個(gè) 16 KB 的區(qū)域有八個(gè) 2 KB 的子區(qū)域,因此如果一個(gè)進(jìn)程只需要 5 KB(3 個(gè)子區(qū)域),那么您可以禁用其中的五個(gè)子區(qū)域并將它們分配給不同的進(jìn)程。
RASR.SIZE 這個(gè)字段設(shè)置起來(lái)有點(diǎn)復(fù)雜,因?yàn)樗枰恍┤斯じ深A(yù),并專門查看鏈接器映射文件以確定兩個(gè)大小屬性的編碼二進(jìn)制冪。
RASR.EN 該位啟用 (1) 或禁用 (0) 區(qū)域。如果您不需要所有八個(gè)區(qū)域,則必須禁用該區(qū)域,以免無(wú)意中啟用來(lái)自不同進(jìn)程的區(qū)域。
清單 1 顯示了加載所有八個(gè) MPU 區(qū)域的優(yōu)化函數(shù)的匯編語(yǔ)言代碼。我將此作為一個(gè)示例,說(shuō)明我們可以如何有效地更改 MPU 配置,但這不是您必須擔(dān)心的事情。確定管理 MPU 的最佳方式確實(shí)是 RTOS 的責(zé)任。但是,您需要遵循 RTOS 指南,了解如何為每個(gè)任務(wù)設(shè)置 MPU 進(jìn)程表。對(duì)于這個(gè)特定的實(shí)現(xiàn),您需要?jiǎng)?chuàng)建一個(gè) MPU 進(jìn)程表來(lái)分配所有八個(gè)區(qū)域,即使使用的區(qū)域更少。該函數(shù)的原型是:
void OS_MPU_ProcessSet (ARM_MPU_Region_t *p_process);
p_process 是指向包含八對(duì) RBAR 和 RASR 值的 MPU 進(jìn)程表的指針。ARM_MPU_Region_t 是 ARM 的 Cortex 微控制器軟件接口標(biāo)準(zhǔn) (CMSIS) 3定義的數(shù)據(jù)類型,聲明如下:
typedef struct
{
uint32_t RBAR; // Region base address
uint32_t RASR; // Region attributes (type, region size, enable, etc.)
} ARM_MPU_Region_t;
因此,對(duì)于每個(gè)任務(wù),您需要聲明一個(gè)包含八個(gè)條目的 ARM_MPU_Region_t 數(shù)組,如下所示:
請(qǐng)注意,最后一個(gè)條目包含任務(wù)堆棧的基地址,并且還假定 RedZone 大小為 32 字節(jié)。
[清單 1 | 配置所有 8 個(gè) MPU 區(qū)域。]
概括
Cortex-M 中的 MPU 是一個(gè)相當(dāng)簡(jiǎn)單的設(shè)備。RTOS 負(fù)責(zé)在每次上下文切換時(shí)配置 MPU。但是,為應(yīng)用程序設(shè)置 MPU 進(jìn)程表是應(yīng)用程序開發(fā)人員的責(zé)任。如果 RTOS 為每個(gè)任務(wù)設(shè)置了 RedZone,則一個(gè)進(jìn)程中的任務(wù)可以共享同一個(gè) MPU 進(jìn)程表。
要讓應(yīng)用程序在 MPU 上運(yùn)行,仍然需要注意一些事項(xiàng)。具體來(lái)說(shuō),如何按進(jìn)程對(duì) RAM 進(jìn)行分組?一個(gè)進(jìn)程如何與另一個(gè)進(jìn)程通信?如果任務(wù)訪問其分配的內(nèi)存空間之外的內(nèi)存或外圍設(shè)備會(huì)發(fā)生什么?除了任務(wù)棧,內(nèi)核對(duì)象是否應(yīng)該分配在進(jìn)程內(nèi)存空間中?我們將在第 3 部分解決這些問題。
審核編輯:郭婷
-
寄存器
+關(guān)注
關(guān)注
31文章
5434瀏覽量
124474 -
RAM
+關(guān)注
關(guān)注
8文章
1392瀏覽量
117519 -
MPU
+關(guān)注
關(guān)注
0文章
415瀏覽量
49916
發(fā)布評(píng)論請(qǐng)先 登錄
嵌入式開發(fā)入門指南:從零開始學(xué)習(xí)嵌入式
RZ/V2N中檔嵌入式AI MPU 數(shù)據(jù)手冊(cè)和產(chǎn)品介紹

高可靠性嵌入式主板設(shè)計(jì)

如何提高嵌入式代碼質(zhì)量?
MPU在嵌入式系統(tǒng)中的應(yīng)用
如何使用Ozone分析Cortex-M異常

嵌入式超火的方向有哪些?
什么是嵌入式操作系統(tǒng)?
【「嵌入式Hypervisor:架構(gòu)、原理與應(yīng)用」閱讀體驗(yàn)】+全文學(xué)習(xí)心得
【「嵌入式Hypervisor:架構(gòu)、原理與應(yīng)用」閱讀體驗(yàn)】+第7-8章學(xué)習(xí)心得
ARM MCU嵌入式開發(fā) | 基于國(guó)產(chǎn)GD32F10x芯片+嵌入的開始
FPGA賦能嵌入式設(shè)備,筑牢安全防線
瑞薩電子基于Arm Cortex-A55和雙Cortex-M33 MPU的SOM方案 加速物聯(lián)網(wǎng)設(shè)計(jì)

嵌入式系統(tǒng)中工業(yè)4.0網(wǎng)絡(luò)安全

評(píng)論