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

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

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

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

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

評論