MPU内存保护单元:基于TC35保护实例代码(有注解)

文章目录

  • 前言
  • 一、基于TC375实现的MPU保护机制
    • 1.1、定义数据保护范围函数
    • 1.2、定义代码保护范围函数
    • 1.3、使能数据读取权限
    • 1.4、使能数据写入权限
    • 1.5、使能指定保护范围内执行代码
    • 1.6、激活指定保护集
    • 1.7、使能MPU保护
    • 1.8、应用执行示例代码


前言

MPU内存保护单元,通过前面两章的介绍,大家对MPU的保护机制、策略、应用一定有了相应的了解,本章将会以英飞凌TC375单片机为例,向大家展示MPU保护在裸机上的使用实例,下面就跟着一起来了解代码上关于MPU是如何处理的方式。本章内容需结合关于TC375的数据手册学习,里面包含了关于MPU的关键寄存器的介绍。

相关文章:
1、《MPU内存保护单元:功能及其行业内的重要地位介绍》
2、《MPU内存保护单元:保护策略》
3、《MPU内存保护单元:基于TC35保护实例代码(有注解)》

一、基于TC375实现的MPU保护机制

1.1、定义数据保护范围函数

/* __mtcr 是一个内联汇编指令,用于将一个值写入特定的控制寄存器。在这里,它用于设置CPU的数据保护寄存器。 */
/*
__mtcr(CPU_DPR0_L, lowerBoundAddress);
__mtcr:内联汇编指令,用于将一个值写入控制寄存器。
CPU_DPR0_L:CPU数据保护范围0的下半部分寄存器的地址。这个寄存器用于设置数据保护范围0的下限地址。
lowerBoundAddress:要设置的下限地址。这个值是通过函数参数传入的。
数据保护范围:数据保护范围用于限制对特定内存区域的访问。在这个例子中,CPU_DPR0_L 和 CPU_DPR0_U 分别用于设置数据保护范围0的下限和上限地址。
地址粒度:数据保护范围的地址粒度为8字节。因此,传入的 lowerBoundAddress 的低3位将被忽略。
访问控制:设置数据保护范围后,只有在这个范围内的地址才能被访问。如果尝试访问范围外的地址,将会触发一个异常。
*通过设置 CPU_DPR0_L 寄存器,定义了数据保护范围0的下限地址。这是内存保护单元(MPU)功能的一部分,用于限制对特定内存区域的访问,从而提高系统的安全性和稳定性
*/

void define_data_protection_range(uint32 lowerBoundAddress, uint32 upperBoundAddress, uint8 range)
{
    switch(range)
    {
        case 0: /* Data Protection Range 0 */
            __mtcr(CPU_DPR0_L, lowerBoundAddress); 
            __mtcr(CPU_DPR0_U, upperBoundAddress); 
            break;
        case 1: /* Data Protection Range 1 */
            __mtcr(CPU_DPR1_L, lowerBoundAddress); 
            __mtcr(CPU_DPR1_U, upperBoundAddress); 
            break;
        case 2: /* Data Protection Range 2 */
            __mtcr(CPU_DPR2_L, lowerBoundAddress); 
            __mtcr(CPU_DPR2_U, upperBoundAddress); 
            break;
        case 3: /* Data Protection Range 3 */
            __mtcr(CPU_DPR3_L, lowerBoundAddress); 
            __mtcr(CPU_DPR3_U, upperBoundAddress); 
            break;
        case 4: /* Data Protection Range 4 */
            __mtcr(CPU_DPR4_L, lowerBoundAddress); 
            __mtcr(CPU_DPR4_U, upperBoundAddress); 
            break;
        case 5: /* Data Protection Range 5 */
            __mtcr(CPU_DPR5_L, lowerBoundAddress); 
            __mtcr(CPU_DPR5_U, upperBoundAddress); 
            break;
        case 6: /* Data Protection Range 6 */
            __mtcr(CPU_DPR6_L, lowerBoundAddress); 
            __mtcr(CPU_DPR6_U, upperBoundAddress); 
            break;
        case 7: /* Data Protection Range 7 */
            __mtcr(CPU_DPR7_L, lowerBoundAddress); 
            __mtcr(CPU_DPR7_U, upperBoundAddress); 
            break;
        case 8: /* Data Protection Range 8 */
            __mtcr(CPU_DPR8_L, lowerBoundAddress); 
            __mtcr(CPU_DPR8_U, upperBoundAddress); 
            break;
        case 9: /* Data Protection Range 9 */
            __mtcr(CPU_DPR9_L, lowerBoundAddress); 
            __mtcr(CPU_DPR9_U, upperBoundAddress); 
            break;
        case 10: /* Data Protection Range 10 */
            __mtcr(CPU_DPR10_L, lowerBoundAddress);
            __mtcr(CPU_DPR10_U, upperBoundAddress);
            break;
        case 11: /* Data Protection Range 11 */
            __mtcr(CPU_DPR11_L, lowerBoundAddress);
            __mtcr(CPU_DPR11_U, upperBoundAddress);
            break;
        case 12: /* Data Protection Range 12 */
            __mtcr(CPU_DPR12_L, lowerBoundAddress);
            __mtcr(CPU_DPR12_U, upperBoundAddress);
            break;
        case 13: /* Data Protection Range 13 */
            __mtcr(CPU_DPR13_L, lowerBoundAddress);
            __mtcr(CPU_DPR13_U, upperBoundAddress);
            break;
        case 14: /* Data Protection Range 14 */
            __mtcr(CPU_DPR14_L, lowerBoundAddress);
            __mtcr(CPU_DPR14_U, upperBoundAddress);
            break;
        case 15: /* Data Protection Range 15 */
            __mtcr(CPU_DPR15_L, lowerBoundAddress);
            __mtcr(CPU_DPR15_U, upperBoundAddress);
            break;
        case 16: /* Data Protection Range 15 */
            __mtcr(CPU_DPR16_L, lowerBoundAddress);
            __mtcr(CPU_DPR16_U, upperBoundAddress);
            break;
        case 17: /* Data Protection Range 15 */
            __mtcr(CPU_DPR17_L, lowerBoundAddress);
            __mtcr(CPU_DPR17_U, upperBoundAddress);
            break;
    }

#if !defined(__TASKING__)
    __isync();    /* 确保上面的指令均已执行完毕 */  
#endif
}

1.2、定义代码保护范围函数

/*
__mtcr(CPU_CPR0_L, lowerBoundAddress);
__mtcr:内联汇编指令,用于将一个值写入控制寄存器。
CPU_CPR0_L:CPU代码保护范围0的下半部分寄存器的地址。这个寄存器用于设置代码保护范围0的下限地址。
lowerBoundAddress:要设置的下限地址。这个值是通过函数参数传入的。
代码保护范围:代码保护范围用于限制对特定代码区域的执行。在这个例子中,CPU_CPR0_L 和 CPU_CPR0_U 分别用于设置代码保护范围0的下限和上限地址。
地址粒度:代码保护范围的地址粒度为8字节。因此,传入的 lowerBoundAddress 的低3位将被忽略。
访问控制:设置代码保护范围后,只有在这个范围内的代码才能被执行。如果尝试执行范围外的代码,将会触发一个异常。
*通过设置 CPU_CPR0_L 寄存器,定义了代码保护范围0的下限地址。这是内存保护单元(MPU)功能的一部分,用于限制对特定代码区域的执行,从而提高系统的安全性和稳定性。
*/
void define_code_protection_range(uint32 lowerBoundAddress, uint32 upperBoundAddress, uint8 range)
{
    switch(range)
    {
        case 0: /* Code Protection Range 0 */
            __mtcr(CPU_CPR0_L, lowerBoundAddress);
            __mtcr(CPU_CPR0_U, upperBoundAddress);
            break;
        case 1: /* Code Protection Range 1 */
            __mtcr(CPU_CPR1_L, lowerBoundAddress);
            __mtcr(CPU_CPR1_U, upperBoundAddress);
            break;
        case 2: /* Code Protection Range 2 */
            __mtcr(CPU_CPR2_L, lowerBoundAddress);
            __mtcr(CPU_CPR2_U, upperBoundAddress);
            break;
        case 3: /* Code Protection Range 3 */
            __mtcr(CPU_CPR3_L, lowerBoundAddress);
            __mtcr(CPU_CPR3_U, upperBoundAddress);
            break;
        case 4: /* Code Protection Range 4 */
            __mtcr(CPU_CPR4_L, lowerBoundAddress);
            __mtcr(CPU_CPR4_U, upperBoundAddress);
            break;
        case 5: /* Code Protection Range 5 */
            __mtcr(CPU_CPR5_L, lowerBoundAddress);
            __mtcr(CPU_CPR5_U, upperBoundAddress);
            break;
        case 6: /* Code Protection Range 6 */
            __mtcr(CPU_CPR6_L, lowerBoundAddress);
            __mtcr(CPU_CPR6_U, upperBoundAddress);
            break;
        case 7: /* Code Protection Range 7 */
            __mtcr(CPU_CPR7_L, lowerBoundAddress);
            __mtcr(CPU_CPR7_U, upperBoundAddress);
            break;
        case 8: /* Code Protection Range 7 */
            __mtcr(CPU_CPR8_L, lowerBoundAddress);
            __mtcr(CPU_CPR8_U, upperBoundAddress);
            break;
        case 9: /* Code Protection Range 7 */
            __mtcr(CPU_CPR9_L, lowerBoundAddress);
            __mtcr(CPU_CPR9_U, upperBoundAddress);
            break;
    }

#if !defined(__TASKING__)
    __isync();    /* 确保上面的指令均已执行完毕 */  
#endif
}

1.3、使能数据读取权限

void enable_data_read(uint8 protectionSet, uint8 range)
{
    Ifx_CPU_DPRE DPRERegisterValue;

    /* 获取CPU 数据保护读使能寄存器的值 */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_0);
            break;
        case 1: /* Protection Set 1 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_1);
            break;
        case 2: /* Protection Set 2 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_2);
            break;
        case 3: /* Protection Set 3 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_3);
            break;
        case 4: /* Protection Set 4 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_4);
            break;
        case 5: /* Protection Set 5 */
            DPRERegisterValue.U = __mfcr(CPU_DPRE_5);
            break;

    }

    /* 设定与给定数据保护范围相对应的位值-这里需要参考芯片手册 
     * RE_n 17:0 rw    Read Enable Range Select - RE[n]
     *                 00000 H Data Protection Range-n not enabled for data read
     *                 00001 H Data Protection Range-n enabled for data read       
     */
    DPRERegisterValue.B.RE_N |= (1 << range); 

    /* 使能CPU MPU读使能寄存器 */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            __mtcr(CPU_DPRE_0, DPRERegisterValue.U);
            break;
        case 1: /* Protection Set 1 */
            __mtcr(CPU_DPRE_1, DPRERegisterValue.U);
            break;
        case 2: /* Protection Set 2 */
            __mtcr(CPU_DPRE_2, DPRERegisterValue.U);
            break;
        case 3: /* Protection Set 3 */
            __mtcr(CPU_DPRE_3, DPRERegisterValue.U);
            break;
        case 4: /* Protection Set 4 */
            __mtcr(CPU_DPRE_4, DPRERegisterValue.U);
            break;
        case 5: /* Protection Set 5 */
            __mtcr(CPU_DPRE_5, DPRERegisterValue.U);
            break;
    }

#if !defined(__TASKING__)
    __isync();    /* 确保上面的指令均已执行完毕 */  
#endif
}

1.4、使能数据写入权限

void enable_data_write(uint8 protectionSet, uint8 range)
{
    Ifx_CPU_DPWE DPWERegisterValue;

    /* Get the CPU Data Protection Write Enable Register value */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_0);
            break;
        case 1: /* Protection Set 1 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_1);
            break;
        case 2: /* Protection Set 2 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_2);
            break;
        case 3: /* Protection Set 3 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_3);
            break;
        case 4: /* Protection Set 4 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_4);
            break;
        case 5: /* Protection Set 5 */
            DPWERegisterValue.U = __mfcr(CPU_DPWE_5);
            break;
    }

    /* Set the bit corresponding to the given Data Protection Range */
    DPWERegisterValue.B.WE_N |= (0x1 << range);

    /* Set the CPU Data Protection Write Enable Register value to enable data write access */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            __mtcr(CPU_DPWE_0, DPWERegisterValue.U);
            break;
        case 1: /* Protection Set 1 */
            __mtcr(CPU_DPWE_1, DPWERegisterValue.U);
            break;
        case 2: /* Protection Set 2 */
            __mtcr(CPU_DPWE_2, DPWERegisterValue.U);
            break;
        case 3: /* Protection Set 3 */
            __mtcr(CPU_DPWE_3, DPWERegisterValue.U);
            break;
        case 4: /* Protection Set 4 */
            __mtcr(CPU_DPWE_4, DPWERegisterValue.U);
            break;
        case 5: /* Protection Set 5 */
            __mtcr(CPU_DPWE_5, DPWERegisterValue.U);
            break;
    }

#if !defined(__TASKING__)
    __isync();    /* 确保上面的指令均已执行完毕 */  
#endif
}

1.5、使能指定保护范围内执行代码

/*
enable_code_execution 函数的主要作用是允许在指定的保护集和代码保护范围内执行代码。
参数:
    uint8 protectionSet:指定要配置的保护集编号。
    uint8 range:指定要启用执行权限的代码保护范围编号。
*/
void enable_code_execution(uint8 protectionSet, uint8 range)
{
    Ifx_CPU_CPXE CPXERegisterValue;

    /* 读取寄存器值 */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_0);
            break;
        case 1: /* Protection Set 1 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_1);
            break;
        case 2: /* Protection Set 2 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_2);
            break;
        case 3: /* Protection Set 3 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_3);
            break;
        case 4: /* Protection Set 4 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_4);
            break;
        case 5: /* Protection Set 5 */
            CPXERegisterValue.U = __mfcr(CPU_CPXE_5);
            break;
    }

    /* 设置执行权限 */
    CPXERegisterValue.B.XE_N |= (0x1 << range);

    /* 写入寄存器值 */
    switch(protectionSet)
    {
        case 0: /* Protection Set 0 */
            __mtcr(CPU_CPXE_0, CPXERegisterValue.U);
            break;
        case 1: /* Protection Set 1 */
            __mtcr(CPU_CPXE_1, CPXERegisterValue.U);
            break;
        case 2: /* Protection Set 2 */
            __mtcr(CPU_CPXE_2, CPXERegisterValue.U);
            break;
        case 3: /* Protection Set 3 */
            __mtcr(CPU_CPXE_3, CPXERegisterValue.U);
            break;
        case 4: /* Protection Set 4 */
            __mtcr(CPU_CPXE_4, CPXERegisterValue.U);
            break;
        case 5: /* Protection Set 5 */
            __mtcr(CPU_CPXE_5, CPXERegisterValue.U);
            break;
    }

#if !defined(__TASKING__)
    __isync();
#endif
}

1.6、激活指定保护集

/* 激活指定的保护集,使得该保护集的内存保护设置生效 */
IFX_INLINE void set_active_protection_set(uint8 protectionSet)
{
    Ifx_CPU_PSW PSWRegisterValue;
    /* PSW是程序状态字寄存器 */
    PSWRegisterValue.U = __mfcr(CPU_PSW);    /* 读取程序状态字(PSW)   */
    PSWRegisterValue.B.PRS = protectionSet;  /* 设置保护集 */
    __mtcr(CPU_PSW, PSWRegisterValue.U);     /* 写入程序状态字(PSW */
}

1.7、使能MPU保护

/* 启用处理器的内存保护功能,使得之前定义的数据和代码保护范围生效 */ 
void enable_memory_protection()
{
    Ifx_CPU_SYSCON sysconValue;
    sysconValue.U = __mfcr(CPU_SYSCON);    /* 读取系统配置寄存器(SYSCON) */
    sysconValue.B.PROTEN = 1;              /* 启用内存保护 */
    __mtcr(CPU_SYSCON, sysconValue.U);     /* 写入系统配置寄存器(SYSCON) */

#if !defined(__TASKING__)
    __isync();   /* 指令同步 */ 
#endif
}


1.8、应用执行示例代码

#define DPR_GRANULARITY             8
#define DUMMY_ELEMENTS_NUM          96 /* 数组长度. 必须是DPR_GRANULARITY的倍数 */
#define INDEX_FORTY_EIGHT           48
#define INDEX_FORTY_SEVEN           47
#define FIRST_ADDR                  0x00000000
#define LAST_ADDR                   0xFFFFFFFF


/* 定义一个数组,指定其为8字节对齐,数据保护的颗粒度为8字节,代码的为32字节 */
uint8 dummyData[DUMMY_ELEMENTS_NUM] __attribute__ ((aligned(DPR_GRANULARITY)));

/* 填充虚拟数组内容 */
volatile uint8 i;
for(i = 0; i < DUMMY_ELEMENTS_NUM; i++)
{
    dummyData[i] = i; /* 以递增的方式初始化虚拟数组内容 */
}

/* 以下是配置内存保护 */

/* 内存保护范围的规则如下:
    * 地址上下边界地址必须为8字节的倍数
    * 在使能MPU后,对地址 x 的访问必须满足以下条件:
    * lowerBoundAddress <= x < upperBoundAddress
    */
/* 定义 Range 0 数据保护: 从 0x00000000 地址向上递增直到数组dummyData索引地址 48th */
define_data_protection_range(FIRST_ADDR, (uint32)&dummyData[INDEX_FORTY_EIGHT], DATA_PROTECTION_RANGE_0);
/* 使能读保护 */
enable_data_read(PROTECTION_SET_1, DATA_PROTECTION_RANGE_0);
/* 使能写保护 */
enable_data_write(PROTECTION_SET_1, DATA_PROTECTION_RANGE_0);

/* 定义 Range 1 数据保护: 从 dummyData最后一个元素 地址向上递增直到 0xFFFFFFFF */
define_data_protection_range((uint32)&dummyData[DUMMY_ELEMENTS_NUM - 1], LAST_ADDR, DATA_PROTECTION_RANGE_1);
/* 使能读保护 */
enable_data_read(PROTECTION_SET_1, DATA_PROTECTION_RANGE_1);
/* 使能写保护 */
enable_data_write(PROTECTION_SET_1, DATA_PROTECTION_RANGE_1);

/* Define the Code Protection Range 0: from 0x00000000 to 0xFFFFFFFF (every address of the microcontroller) */
define_code_protection_range(FIRST_ADDR, LAST_ADDR, CODE_PROTECTION_RANGE_0);
/* Enable code execution on every address for Protection Set 1 */
enable_code_execution(PROTECTION_SET_1, CODE_PROTECTION_RANGE_0);

/* When a trap occurs (i.e. in case of an access violation) the active Protection Set is automatically switched to 0.
    * The following code enables the write/read access and code execution to all the memory addresses on protection set 0.
    * This ensures that the trap vector table is still executable and readable.
    */
/* Define the Code Protection Range 9: from 0x00000000 to 0xFFFFFFFF (every address of the microcontroller) */
define_code_protection_range(FIRST_ADDR, LAST_ADDR, CODE_PROTECTION_RANGE_9);
/* Define the Data Protection Range 17: from 0x00000000 to 0xFFFFFFFF (every address of the microcontroller) */
define_data_protection_range(FIRST_ADDR, LAST_ADDR, DATA_PROTECTION_RANGE_17);
/* Enable code execution for Protection Set 0 (the default Protection Set) */
enable_code_execution(PROTECTION_SET_0, CODE_PROTECTION_RANGE_9);
/* Enable read access to the Data Protection Range 17 in the Protection Set 0 */
enable_data_read(PROTECTION_SET_0, DATA_PROTECTION_RANGE_17);
/* Enable write access to the Data Protection Range 17 in the Protection Set 0 */
enable_data_write(PROTECTION_SET_0, DATA_PROTECTION_RANGE_17);

/* Activate Protection Set 1.
    * The active protection set determines the read, write, and execute permissions of the CPU.
    */
set_active_protection_set(PROTECTION_SET_1);

/* Enable the Memory Protection */
enable_memory_protection();

volatile uint8 dummyRead;

/* 循环读取数组元素 */
for(i = 0; i < DUMMY_ELEMENTS_NUM; i++)
{
    /* Make a read access to the array which is partially protected. */
    dummyRead = dummyData[i];

    /* 如果读取到数组中的第47个元素(索引为47). */
    if(i == INDEX_FORTY_SEVEN)
    {
        /* 点亮第一个LED,表示所有非保护元素都已成功读取。.*/
        switch_LED_ON(LED_FIRST_HALF);
    }
    /* 如果读取到第48个元素及之后的元素(索引大于47. */
    else if(i > INDEX_FORTY_SEVEN)
    {
        /* 点亮第二个LED */
        /* 按照MPU的配置,这部分代码应该是不可达的,因为从第48个元素开始,数组的一部分被保护起来,不应该被读取 */
        switch_LED_ON(LED_SECOND_HALF);
    }
}

你可能感兴趣的:(MPU保护,MPU内存保护单元,基于TC375的MPU实例代码,单片机MPU,MPU的裸机保护)