鸿蒙轻内核M核源码分析系列十六 MPU内存保护单元 原创 精华
鸿蒙轻内核M核源码分析系列十六 MPU内存保护单元
【本文正在参与优质创作者激励】
MPU(Memory Protection Unit,内存保护单元)把内存映射为一系列内存区域,定义这些内存区域的维洲,大小,访问权限和内存熟悉信息。MPU支持对每个内存区域进行独立的属性设置,允许内存区域重, 可以导出内存属性。有关MPU的详细信息可以参考官方资料站点,比如对应Cortex-M3的文档位置为:https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit或者访问本文的附件资源部分。
在鸿蒙轻内核中,MPU用于任务栈的溢出检测。本文主要分析鸿蒙轻内核MPU模块的的源码。本文中所涉及的源码,以OpenHarmony LiteOS-M
内核为例,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。鸿蒙轻内核支持的ARM Cortex-M芯片架构都支持MPU的,代码都是一样的,以kernel\arch\arm\cortex-m4\gcc\los_mpu.c
为例进行讲解。
1、MPU枚举、结构体定义和常用宏定义
1.1 MPU枚举、结构体定义
在文件kernel\arch\include\los_mpu.h
定义MPU相关的结构体。⑴处定义MPU内存区域的访问权限,有关访问权限见下图,或者可以访问官网https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-access-permission-attributes,特别是上述页面的表格Table 4.47. AP encoding了解更多。
⑵处定义MPU的是否可执行属性枚举,⑶处定义MPU内存区域是否可以共享属性枚举,⑷定义内存区域的类型属性枚举,⑸处的结构体用于定义MPU内存区域。
1.2 MPU宏
MPU外设的一些宏定义有HAL Drivers定义,比如对于Cortex-M4,位置为Drivers\CMSIS\Core\Include\core_cm4.h
。MPU
结构体定义如下,关于MPU寄存器的详细信息可以访问https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit,查看页面上的Table 4.38. MPU registers summary,下图是MPU寄存器的官网表格截图,下文在讲解代码时会涉及MPU的各个寄存器。
另外,MPU支持8个内存区域,kernel\arch\arm\cortex-m4\gcc\los_mpu.c
文件中定义的宏如下:
2、MPU常用操作
MPU常用操作函数包含使能MPUHalMpuEnable
、失能MPUHalMpuDisable
,设置指定的内存区域属性HalMpuSetRegion
,失能指定的内存区域HalMpuDisableRegion
和获取未使用的内存区域编号HalMpuUnusedRegionGet
。
2.1 使能MPUHalMpuEnable
该函数使能MPU功能,⑴处对MPU控制寄存器MPU Control Register
进行操作,通过对寄存器相关的bit位进行赋值来使能MPU。有关该寄存器建议详细阅读https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-control-register。⑵处代码使能MemoryFault异常。接着执行的数据同步屏障__DSB()
和指令同步屏障__ISB()
,详细的可以查阅ARM的DMB,DSB,ISB等指令。
2.2 失能MPUHalMpuDisable
代码很简单,直接把MPU控制寄存器赋值为0来失能MPU功能。
2.3 失能指定的内存区域HalMpuDisableRegion
HalMpuDisableRegion
函数执行后不再对指定的内存区域进行MPU保护,⑴处校验参数合法性。⑵处没有使用的MPU内存区域无法失能。⑶处获取MPU的类型寄存器,详细可以访问https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-type-register。
⑷处表示MPU的数据内存区域(MPU data regions)数量不为空时,执行⑸处代码更新MPU内存区域编号寄存器(MPU Region Number Register
)为指定的内存区域编号,详细的信息可以参考https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-region-number-register。然后执行⑹处代码更新MPU内存区域属性和大小寄存器(MPU Region Attribute and Size Register
),详细可以参考https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-region-attribute-and-size-register。⑺处把全局变量数组中指定的区域编号设置为未使用0。
2.4 设置指定的内存区域属性HalMpuSetRegion
HalMpuSetRegion
函数设置指定的内存区域的属性。⑴处对参数进行合法性校验。⑵处如果MPU类型寄存器中表示的数据内存区域的数量为0,无法继续设置内嵌区域,直接返回LOS_NOK
。⑶处调用函数HalMpuEncodeSize
根据内存区域的实际大小值获取编码大小,该值后续会被赋值给MPU属性和大小寄存器的size位。⑷判断内存区域需要相对内存区域大小进行内存对齐,否则返回LOS_NOK
。
⑸处计算基地址寄存器的数据,有关基地址寄存器(MPU Region Base Address Register),可以访问https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/optional-memory-protection-unit/mpu-region-base-address-register了解更多。⑹处计算属性和大小寄存器的数值。⑺处如果指定的内存区域被使用,直接返回LOS_NOK
。⑻处设置MPU相关的寄存器,并标记该内存区域已使用。代码如下:
2.4.1 HalMpuEncodeSize根据内存区域实际大小获取size属性值
HalMpuEncodeSize
函数根据内存区域实际大小获取size属性值,对应的计算公式为:(Region size in bytes) = 2^(SIZE+1)
,详细信息可以访问MPU属性和大小寄存器官网资料页面的Table 4.44. Example SIZE field values。32bytes对应4,1KB对应5,…,4GB对应31。
⑴处表示内存区域大小不能大于4GB,然后判断是否相对32字节进行内存对齐。⑵处先右移2位,然后while循环,执行⑶每向右循环一位,size属性大小增加1。
2.4.2 HalMpuGetRASR根据size属性值和配置参数计算属性和大小寄存器的值
HalMpuGetRASR根据size属性值和配置参数计算属性和大小寄存器的值。⑴处根据配置的访问权限计算AP(ACCESS permission),然后计算属性和大小寄存器的值,最后执行⑶给寄存器赋值。
小结
本文带领大家一起剖析了鸿蒙轻内核的MPU模块的源代码。感谢阅读,如有任何问题、建议,都可以博客下留言给我,谢谢。
【本文正在参与优质创作者激励】
好文,收藏了
谢谢支持 匆匆忙忙分享 如果失误 多多指正