1
MM32F5330 MPU簡(jiǎn)介
靈動(dòng)微電子發(fā)布了搭載安謀科技“星辰”STAR-MC1處理器的全新高性能 MM32F5 微控制器系列,該系列在內(nèi)核、總線和外設(shè)配置等多個(gè)方面進(jìn)行了創(chuàng)新,內(nèi)核上更是首次搭載了 Armv8-M 架構(gòu)的 “星辰” STAR-MC1 處理器。Armv8-M 架構(gòu)相較于 Armv7-M 架構(gòu),除了性能顯著提升以外,其中一項(xiàng)就是更加安全:Armv8-M 架構(gòu)引入了 TrustZone 技術(shù),并強(qiáng)化了內(nèi)存保護(hù)單元(MPU),讓代碼運(yùn)行在更安全的環(huán)境中。
MPU 在 4GB 地址映射中定義保護(hù)區(qū)域。Armv8-M 上的MPU 有8個(gè)region,每一個(gè)region都有起始地址,結(jié)束地址,訪問(wèn)權(quán)限和內(nèi)存屬性,每一個(gè)region都有單獨(dú)的屬性。和以往Armv7-M 的MPU有所不同,Armv8-M的MPU不支持region overlap,如果一個(gè)地址同時(shí)出現(xiàn)在兩個(gè)不同的region中,會(huì)導(dǎo)致HardFault。如果程序訪問(wèn)被MPU禁止的內(nèi)存位置,處理器就會(huì)生成一個(gè) MemManage異常。
MPU 本質(zhì)上就是為了保護(hù)某一段地址區(qū)域不被非授權(quán)狀態(tài)的程序進(jìn)行訪問(wèn)。通常嵌入式操作系統(tǒng)使用MPU進(jìn)行內(nèi)存保護(hù),內(nèi)核可以根據(jù)進(jìn)程動(dòng)態(tài)更新MPU區(qū)域設(shè)置。MPU 可以讓嵌入式系統(tǒng)更加健壯,以及保護(hù)一些加密區(qū)域。MPU 具有以下能力可以增加系統(tǒng)的健壯性:
可以阻止用戶去破壞操作系統(tǒng)需要使用的數(shù)據(jù)
可以防止一個(gè)任務(wù)去非法訪問(wèn)其他任務(wù)的數(shù)據(jù),將任務(wù)完全隔離開
可以把關(guān)鍵數(shù)據(jù)區(qū)設(shè)為只讀,從而不被破壞
檢測(cè)其他意外訪問(wèn),比如堆棧溢出,數(shù)組越界等
2
內(nèi)存類型
Armv8中將內(nèi)存分為兩種類型:Normal memory和Device memory。Normal memory適用于系統(tǒng)中的大部分內(nèi)存,而Device memory則適用于外設(shè)所使用的內(nèi)存。
Normal memory,主要指RAM,ROM,F(xiàn)LASH等,處理器以及編譯器都可以對(duì)程序做優(yōu)化,處理器還可以增加repeate,reorder,merge的操作。在強(qiáng)制訪問(wèn)順序的情況下,需要調(diào)用內(nèi)存屏障指令。
Device memory,通常都是外設(shè)對(duì)應(yīng)的內(nèi)存映射。Device類型用于可能有副作用的位置,不可緩存,不允許對(duì)標(biāo)記為Device的區(qū)域進(jìn)行推測(cè)性數(shù)據(jù)訪問(wèn)。
Device memory屬性:
1) G:Gather,多個(gè)內(nèi)存訪問(wèn)可以合并
2) R:Reordering,對(duì)內(nèi)存訪問(wèn)指令進(jìn)行重排
3) E:Early Write Ack,寫操作的Ack可提前應(yīng)答
四種Device memory:
1) Device nGnRnE,不允許gather、reorder、early
2) Device nGnRE,允許early
3) Device nGRE,允許reorder、early
4) Device GRE,允許gather、reorder、early
下表顯示了可能的MPU region屬性,包括Shareable和Cacheable屬性。
Armv8內(nèi)存類型和屬性還有很多細(xì)節(jié),對(duì)MPU region屬性配置會(huì)涉及到Cache讀寫策略的內(nèi)容,感興趣的同學(xué)可以先查閱相關(guān)資料,進(jìn)行詳細(xì)了解。本章節(jié)我們著重理解MPU的功能和作用,并進(jìn)行簡(jiǎn)單驗(yàn)證,關(guān)于Cache內(nèi)容在后續(xù)章節(jié)中再進(jìn)行說(shuō)明。
3
MPU寄存器模組
3.1 MPU主要有以下寄存器
3.2 MPU_TYPE
MPU_TYPE寄存器用來(lái)表示MPU是否存在以及它支持多少個(gè)region。
3.3 MPU_CTRL
MPU_CTRL用來(lái)使能MPU、使能backgroup map、使能NMI中MPU是否有效。
3.4 MPU_RNR
MPU_RNR用來(lái)選擇region,在訪問(wèn)MPU_RBAR和MPU_RLAR之前,必須先寫入MPU_RNR來(lái)選擇region。
3.5 MPU_RBAR
MPU_RBAR定義了region的起始地址。
3.6 MPU_RLAR
MPU_RLAR定義了region的上限地址以及region屬性選擇。
3.7 MPU_MAIR0和MPU_MAIR1
MPU_MAIR0和MPU_MAIR1提供與AttrIndex值對(duì)應(yīng)的內(nèi)存屬性編碼。
每一個(gè)region屬性MARI_ATTR占8位。
如果MAIR_ATTR[7:4]為0,那么MAIR_ATTR定義如下:
如果MAIR_ATTR[7:4]不為0,那么MAIR_ATTR定義如下:
4
MPU配置
關(guān)于MPU的配置可以參考靈動(dòng)微電子官網(wǎng)的LibSamples,具體在core_starmc1.h和mpu_armv8.h文件定義了MPU寄存器映射及接口函數(shù),下表中列出部分函數(shù):
5
MPU測(cè)試
5.1 region read/write測(cè)試
定義一個(gè)指針變量指向地址0x20006000位置,在MPU關(guān)閉時(shí),該地址可以正常進(jìn)行讀寫,通過(guò)配置MPU將0x20006000 - 0x20006FFF區(qū)域設(shè)置為region0只讀,使能MPU后再進(jìn)行寫訪問(wèn),仿真觀測(cè)運(yùn)行情況。測(cè)試代碼如下:
voidmpu_readwrite(void) { volatileuint32_t*temptr=(volatileuint32_t*)0x20006000UL; MPU_Cmd(MPU,DISABLE);//DisableMPU *temptr=0x00; printf("%x:%x ",(uint32_t)temptr,*temptr); *temptr=0xA5; printf("%x:%x ",(uint32_t)temptr,*temptr); //Enable MPU region0:0x20006000-0x20006FFF //Read-only,Executionnotpermitted,Devicememory MPU_SelectRegion(MPU,0); MPU_SetRegionBase(MPU,0x20006000UL,REGION_NON_SHAREABLE,REGION_RO_ANY,REGION_XN); MPU_SetRegionLimit(MPU,0x20006FFFUL,0,REGION_EN); MPU_SetRegionAttr(MPU,0,0); MPU_HfnmienaCmd(MPU,ENABLE); MPU_PrivdefenaCmd(MPU,ENABLE); MPU_Cmd(MPU,ENABLE); printf("Teststart: "); //AfterMPUisenabled,checkwhetherthewritepermissionisgranted. printf("%x:%x ",(uint32_t)temptr,*temptr); //Thehardfaultwillbetriggeredwhenthecodeisexecutedhere. *temptr=0x5A; printf("%x:%x ",(uint32_t)temptr,*temptr); printf("Testover! "); }
仿真查看MPU配置和代碼執(zhí)行預(yù)期一致:
串口調(diào)試助手打印情況:
打印Test start之前的數(shù)據(jù)可以進(jìn)行讀寫,使能MPU之后先打印一次數(shù)據(jù),即可讀,但是運(yùn)行到賦值語(yǔ)句*temptr = 0x5A,就進(jìn)入了HardFault,說(shuō)明該地址不可寫。
修改測(cè)試代碼設(shè)置region0為可讀寫:
MPU_SelectRegion(MPU,0); MPU_SetRegionBase(MPU,0x20006000UL,REGION_NON_SHAREABLE,REGION_RW_ANY,REGION_XN); MPU_SetRegionLimit(MPU,0x20006FFFUL,0,REGION_EN); MPU_SetRegionAttr(MPU,0,0);
仿真查看MPU配置和代碼執(zhí)行預(yù)期一致:
串口調(diào)試助手打印情況:
測(cè)試代碼得到全部執(zhí)行,使能MPU之后先打印一次數(shù)據(jù),即可讀,運(yùn)行賦值語(yǔ)句*temptr = 0x5A后,打印該地址的數(shù)據(jù)是0x5A,說(shuō)明寫正常。
綜上,MPU可以有效設(shè)置區(qū)域的讀寫權(quán)限。
5.2 region overlap測(cè)試
定義一個(gè)指針變量指向地址0x20006000位置,在MPU關(guān)閉時(shí),該地址可以正常進(jìn)行讀寫,通過(guò)配置MPU將0x20006000 - 0x20006FFF區(qū)域設(shè)置為region0可讀寫,將0x20005000 - 0x20007FFF區(qū)域設(shè)置為region1可讀寫,使能MPU后再訪問(wèn)地址0x20006000,測(cè)試代碼如下:
voidmpu_overlap(void) { volatileuint32_t*temptr=(volatileuint32_t*)0x20006000UL; MPU_Cmd(MPU,DISABLE); *temptr=0x00; printf("%x:%x ",(uint32_t)temptr,*temptr); *temptr=0xB9; printf("%x:%x ",(uint32_t)temptr,*temptr); //Configure region0:0x20006000-0x20006FFF //Read/write,Executionnotpermitted,Devicememory MPU_SelectRegion(MPU,0); MPU_SetRegionBase(MPU,0x20006000UL,REGION_NON_SHAREABLE,REGION_RW_PRIV_ONLY,REGION_XN); MPU_SetRegionLimit(MPU,0x20006FFFUL,0,REGION_EN); MPU_SetRegionAttr(MPU,0,0); //Configure region1:0x20005000-0x20007FFF //Read/write,Executionnotpermitted,Devicememory MPU_SelectRegion(MPU,1); MPU_SetRegionBase(MPU,0x20005000UL,REGION_NON_SHAREABLE,REGION_RW_PRIV_ONLY,REGION_XN); MPU_SetRegionLimit(MPU,0x20007FFFUL,1,REGION_EN); MPU_SetRegionAttr(MPU,0,1); MPU_HfnmienaCmd(MPU,ENABLE); MPU_PrivdefenaCmd(MPU,ENABLE); MPU_Cmd(MPU,ENABLE); printf("Teststart: "); //Theaddressofthe0x20006000overlapsinregion0andregion1. //Accessingtheaddresstriggersahardfault. printf("%x:%x ",(uint32_t)temptr,*temptr); printf("Testover! "); }
仿真查看MPU配置情況和代碼執(zhí)行預(yù)期一致:
串口調(diào)試助手打印情況:
打印Test start之前的數(shù)據(jù)可以進(jìn)行讀寫,使能MPU之后,因?yàn)榈刂?x20006000位于region0和region1的overlap區(qū)域,運(yùn)行打印*temptr 的語(yǔ)句,就進(jìn)入了HardFault,該位置不可訪問(wèn),說(shuō)明MPU不支持region overlap,否則對(duì)overlap區(qū)域訪問(wèn)時(shí)會(huì)觸發(fā)HardFault。
5.3 region code execute測(cè)試
將func()函數(shù)定義在指定地址0x08007800位置,在MPU關(guān)閉時(shí),程序中調(diào)用該函數(shù)可以正常執(zhí)行,通過(guò)配置MPU將0x08007800 - 0x080087FF區(qū)域設(shè)置為region0不可執(zhí)行,使能MPU后再次運(yùn)行func()函數(shù),觀察測(cè)試情況。測(cè)試代碼如下:
voidfunc(void)__attribute__((section(".ARM.__AT_0x08007800"))); voidfunc(void) { printf("Executethefunction! "); } voidmpu_xn(void) { //Injectcodeat0x08007800 typedefvoid(*test_func_t)(void); test_func_ttest_func=(test_func_t)0x08007801; test_func(); MPU_Cmd(MPU,DISABLE); //Enable MPU region0:0x08007800-0x080087FF //Read-only,Executionnotpermitted,Devicememory MPU_SelectRegion(MPU,0); MPU_SetRegionBase(MPU,0x08007800UL,REGION_NON_SHAREABLE,REGION_RO_PRIV_ONLY,REGION_XN); MPU_SetRegionLimit(MPU,0x080087FFUL,0,REGION_EN); MPU_SetRegionAttr(MPU,0,0); MPU_HfnmienaCmd(MPU,ENABLE); MPU_PrivdefenaCmd(MPU,ENABLE); MPU_Cmd(MPU,ENABLE); printf("Teststart: "); //Thetest_funcof0x08007800cannotbeexecutedafterMPUisenabled. //Thehardfaultwillbetriggeredwhenthecodeisexecutedhere. test_func(); printf("Testover! "); }
仿真查看MPU配置情況和代碼執(zhí)行預(yù)期一致:
串口調(diào)試助手打印情況:
打印Test start之前調(diào)用func()函數(shù)一次,執(zhí)行正常。使能MPU之后,再次調(diào)用func()函數(shù),就進(jìn)入了HardFault,該代碼不可執(zhí)行。
6
小結(jié)
MPU為存儲(chǔ)保護(hù)單元,它位于存儲(chǔ)器內(nèi)部的一個(gè)可編程的區(qū)域,定義了存儲(chǔ)器的屬性和訪問(wèn)權(quán)限,試圖訪問(wèn)非法或者不允許的內(nèi)存地址則會(huì)觸發(fā)HardFault異常。MPU能夠提高嵌入式系統(tǒng)的健壯性,使得系統(tǒng)更加安全。實(shí)際應(yīng)用中根據(jù)具體的項(xiàng)目需要,選擇MPU是默認(rèn)配置還是需要更改一些配置,這樣才能使應(yīng)用更加符合要求。
審核編輯:劉清
-
微控制器
+關(guān)注
關(guān)注
48文章
7651瀏覽量
152118 -
處理器
+關(guān)注
關(guān)注
68文章
19409瀏覽量
231191 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7528瀏覽量
164345 -
MPU
+關(guān)注
關(guān)注
0文章
375瀏覽量
48955
原文標(biāo)題:靈動(dòng)微課堂 (第269講)|MM32F5330內(nèi)存保護(hù)單元(MPU)
文章出處:【微信號(hào):MindMotion-MMCU,微信公眾號(hào):靈動(dòng)MM32MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論