RTOS:任务MPU配置(含解析)


前言

操作系统,在入行嵌入式j接触它之前,感觉那是多么高深、神圣的技术,感觉它是高不可攀的。曾经也幻想过它有多么的复杂,在裸机编程时无数次想去应用这个技术,但无奈,无人指引,以致于每每都会望而却步。如今,也在多种OS的基础上做过各行各业的软件开发,所以想在闲暇之时,将使用过的OS内核软件逐行阅读,以提升自我编程能力、去了解更多软件编程思想。写此专栏文章的目的也仅仅是为了让这个过程留痕。

本文所有代码源于RTOS-Keenel

一、任务MPU配置

上源码
void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
                                const struct xMEMORY_REGION * const xRegions,
                                StackType_t * pxBottomOfStack,
                                configSTACK_DEPTH_TYPE uxStackDepth )
{
    uint32_t ulRegionStartAddress, ulRegionEndAddress, ulRegionNumber;
    int32_t lIndex = 0;

    #if defined( __ARMCC_VERSION )

        /* Declaration when these variable are defined in code instead of being
            * exported from linker scripts. */
        extern uint32_t * __privileged_sram_start__;
        extern uint32_t * __privileged_sram_end__;
    #else
        /* Declaration when these variable are exported from linker scripts. */
        extern uint32_t __privileged_sram_start__[];
        extern uint32_t __privileged_sram_end__[];
    #endif /* defined( __ARMCC_VERSION ) */

    /* Setup MAIR0. */
    xMPUSettings->ulMAIR0 = ( ( portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE << portMPU_MAIR_ATTR0_POS ) & portMPU_MAIR_ATTR0_MASK );
    xMPUSettings->ulMAIR0 |= ( ( portMPU_DEVICE_MEMORY_nGnRE << portMPU_MAIR_ATTR1_POS ) & portMPU_MAIR_ATTR1_MASK );

    /* This function is called automatically when the task is created - in
        * which case the stack region parameters will be valid.  At all other
        * times the stack parameters will not be valid and it is assumed that
        * the stack region has already been configured. */
    if( uxStackDepth > 0 )
    {
        ulRegionStartAddress = ( uint32_t ) pxBottomOfStack;
        ulRegionEndAddress = ( uint32_t ) pxBottomOfStack + ( uxStackDepth * ( configSTACK_DEPTH_TYPE ) sizeof( StackType_t ) ) - 1;

        /* If the stack is within the privileged SRAM, do not protect it
            * using a separate MPU region. This is needed because privileged
            * SRAM is already protected using an MPU region and ARMv8-M does
            * not allow overlapping MPU regions. */
        if( ( ulRegionStartAddress >= ( uint32_t ) __privileged_sram_start__ ) &&
            ( ulRegionEndAddress <= ( uint32_t ) __privileged_sram_end__ ) )
        {
            xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = 0;
            xMPUSettings->xRegionsSettings[ 0 ].ulRLAR = 0;
        }
        else
        {
            /* Define the region that allows access to the stack. */
            ulRegionStartAddress &= portMPU_RBAR_ADDRESS_MASK;
            ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK;

            xMPUSettings->xRegionsSettings[ 0 ].ulRBAR = ( ulRegionStartAddress ) |
                                                            ( portMPU_REGION_NON_SHAREABLE ) |
                                                            ( portMPU_REGION_READ_WRITE ) |
                                                            ( portMPU_REGION_EXECUTE_NEVER );

            xMPUSettings->xRegionsSettings[ 0 ].ulRLAR = ( ulRegionEndAddress ) |
                                                            ( portMPU_RLAR_ATTR_INDEX0 ) |
                                                            ( portMPU_RLAR_REGION_ENABLE );
        }
    }

    /* User supplied configurable regions. */
    for( ulRegionNumber = 1; ulRegionNumber <= portNUM_CONFIGURABLE_REGIONS; ulRegionNumber++ )
    {
        /* If xRegions is NULL i.e. the task has not specified any MPU
            * region, the else part ensures that all the configurable MPU
            * regions are invalidated. */
        if( ( xRegions != NULL ) && ( xRegions[ lIndex ].ulLengthInBytes > 0UL ) )
        {
            /* Translate the generic region definition contained in xRegions
                * into the ARMv8 specific MPU settings that are then stored in
                * xMPUSettings. */
            ulRegionStartAddress = ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) & portMPU_RBAR_ADDRESS_MASK;
            ulRegionEndAddress = ( uint32_t ) xRegions[ lIndex ].pvBaseAddress + xRegions[ lIndex ].ulLengthInBytes - 1;
            ulRegionEndAddress &= portMPU_RLAR_ADDRESS_MASK;

            /* Start address. */
            xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRBAR = ( ulRegionStartAddress ) |
                                                                        ( portMPU_REGION_NON_SHAREABLE );

            /* RO/RW. */
            if( ( xRegions[ lIndex ].ulParameters & tskMPU_REGION_READ_ONLY ) != 0 )
            {
                xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRBAR |= ( portMPU_REGION_READ_ONLY );
            }
            else
            {
                xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRBAR |= ( portMPU_REGION_READ_WRITE );
            }

            /* XN. */
            if( ( xRegions[ lIndex ].ulParameters & tskMPU_REGION_EXECUTE_NEVER ) != 0 )
            {
                xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRBAR |= ( portMPU_REGION_EXECUTE_NEVER );
            }

            /* End Address. */
            xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRLAR = ( ulRegionEndAddress ) |
                                                                        ( portMPU_RLAR_REGION_ENABLE );

            /* PXN. */
            #if ( portARMV8M_MINOR_VERSION >= 1 )
            {
                if( ( xRegions[ lIndex ].ulParameters & tskMPU_REGION_PRIVILEGED_EXECUTE_NEVER ) != 0 )
                {
                    xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRLAR |= ( portMPU_RLAR_PRIVILEGED_EXECUTE_NEVER );
                }
            }
            #endif /* portARMV8M_MINOR_VERSION >= 1 */

            /* Normal memory/ Device memory. */
            if( ( xRegions[ lIndex ].ulParameters & tskMPU_REGION_DEVICE_MEMORY ) != 0 )
            {
                /* Attr1 in MAIR0 is configured as device memory. */
                xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRLAR |= portMPU_RLAR_ATTR_INDEX1;
            }
            else
            {
                /* Attr0 in MAIR0 is configured as normal memory. */
                xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRLAR |= portMPU_RLAR_ATTR_INDEX0;
            }
        }
        else
        {
            /* Invalidate the region. */
            xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRBAR = 0UL;
            xMPUSettings->xRegionsSettings[ ulRegionNumber ].ulRLAR = 0UL;
        }

        lIndex++;
    }
}

二、详细逻辑分析

用于存储任务内存保护单元(MPU)设置。MPU 是一种硬件功能,用于限制程序访问的内存区域,从而提高系统的安全性和稳定性。
  • xMPUSettings:用于存储任务 MPU 设置的结构体。
  • xRegions:用户提供的可配置内存区域。
  • pxBottomOfStack:任务堆栈的底部地址。
  • uxStackDepth:任务堆栈的深度。
  • 设置 MAIR0 寄存器,该寄存器用于定义内存属性。在这个例子中,MAIR0 被设置为允许缓存和缓冲的正常内存,以及不允许缓存和缓冲的设备内存。
  • 如果 uxStackDepth 大于 0,那么函数会设置任务的堆栈区域。首先,函数会计算堆栈区域的起始地址和结束地址。然后,如果堆栈区域在特权 SRAM 内,那么函数不会为堆栈区域设置单独的 MPU 区域,因为特权 SRAM 已经被保护。否则,函数会定义一个允许访问堆栈的 MPU 区域。
  • 函数会处理用户提供的可配置内存区域。对于每个可配置内存区域,函数会将其转换为 ARMv8-M 特定的 MPU 设置,并存储在 xMPUSettings 中。如果 xRegions 为 NULL,或者某个区域的长度为 0,那么函数会无效化该区域。

三、源码复杂点解读

3.1、privileged_sram_startprivileged_sram_end

表示特权SRAM的起始地址和结束地址。

3.2、xMPUSettings->ulMAIR0

设置MAIR0寄存器。该寄存器用于定义内存属性。在这个位置MAIR0被设置为允许缓存和缓冲的正常内存,以及不允许缓存和缓冲的设备内存。

3.3、uxStackDepth > 0

该条件语句中,主要是计算堆栈区域的起始地址和结束地址。然后再检查该堆栈区域是否在特权SRAM中。如果是,那么函数不会为堆栈区域设置单独的MPU区域,因为特权SRAM已经被保护。否则,函数会定义一个运行访问堆栈的MPU区域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EmbSW_Guru_Wx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值