• 81查看
  • 0回复

[Autosar] Autosar Memory Protection Aurix Tc3xx MMU

[复制链接]

该用户从未签到

发表于 23-4-2024 20:00:30 | 显示全部楼层 |阅读模式

汽车零部件采购、销售通信录       填写你的培训需求,我们帮你找      招募汽车专业培训老师


内存保护           
          1. 内存保护子系统           
                    1.1 trap 系统           
                    1.2 IO 特权等级           
                    1.3 内存保护           
          2. Range Base内存保护           
                    2.1 保护范围 protection ranges           
                    2.2 权限访问           
                    2.3 Protection Set           
          3. 内存保护使用           
                    3.1 定义数据范围           
                    3.2 定义代码执行的地址范围           
                    3.3 为数据设置读权限           
                    3.4 为数据设置写权限           
                    3.5 为地址设置执行权限           
                    3.6 Active Protection set           
                    3.7 激活内存保护           
          4. Autosar Os ECU-Partition & Os-Application           
                    4.1 总体设计           
                    4.2 Os 配置           
                    4.3 代码生成           
          5 MPU 测试代码分析           
                    5.1 Protection Ranges           
                    5.2 Protection Sets           
                    5.3 测试代码           
                              5.3.1 任务           
                              5.3.2 初始化           
                              5.3.3 测试case           
                              5.3.4 hook

内存保护

针对Tc3 系列芯片,由专门的memory protection system. 这里面可以进行开发读写保护,执行保护等内存保护相关功能。   

1. 内存保护子系统

使用内存保护,会涉及到下面一些相关的模块,系统。

1.1 trap 系统

当数据访问到了与其权限不匹配的地址,会产生trap, 当指令执行到了与其不匹配的地址,也会产生相对应的trap. 针对trap 可以查询手册,一共有很多个trap.

与内存保护相关的trap大概由如下一些。

[img=560.010009765625,154.32000732421875]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsx8SAOVibxHRvu2l3lufgibibV1ibUJu2hnOJYm7sdWLEXcVibb2oDonia0ndw/640?wx_fmt=png[/img]

在autosar os 中,os 会对一些trap进行处理。这里给出trap的结构体类型。我们可以根据陷入trap的具体信息查手册,找到相对应的原因。

typedef struct {               
  uint8 Class; /* Trap class: 0 - 7 */               
  uint8 TIN; /* Trap TIN value */               
  uint32 ReturnAddress; /* A11 value for the trap */               
} OsTrapInfoType;

               

1.2 IO 特权等级

针对IO 由三个模式。

•User-0 mode

无法操作外设,寄存器,IO 等权限。

•User-1 mode

默认可以为User-1 模式,比较有效率,可以访问普通的外设寄存器的读写等操作。

•Supervisor mode   

需要操作系统寄存器,或者是外部的设备读写等,可能需要设置一些Supervisor模式。

               

配置Mcal的时候一定遇到过上面这些模式。CPU的PSW 寄存器中就有IO 的位置。如下

typedef struct _Ifx_CPU_PSW_Bits               
{               
    Ifx_Strict_32Bit CDC:7;           /**< \brief [6:0] Call Depth Counter - CDC (rwh) */               
    Ifx_Strict_32Bit CDE:1;           /**< \brief [7:7] Call Depth Count Enable - CDE (rwh) */               
    Ifx_Strict_32Bit GW:1;            /**< \brief [8:8] Global Address Register Write Permission - GW (rwh) */               
    Ifx_Strict_32Bit IS:1;            /**< \brief [9:9] Interrupt Stack Control - IS (rwh) */               
    Ifx_Strict_32Bit IO:2;            /**< \brief [11:10] Access Privilege Level Control (I/O Privilege) - IO (rwh) */               
    Ifx_Strict_32Bit PRS:2;           /**< \brief [13:12] Protection Register Set - PRS (rwh) */               
    Ifx_Strict_32Bit S:1;             /**< \brief [14:14] Safe Task Identifier - S (rwh) */               
    Ifx_Strict_32Bit PRS2:1;          /**< \brief [15:15] Protection Register Set MSB - PRS2 (rwh) */               
    Ifx_Strict_32Bit reserved_16:8;    /**< \brief [23:16] \internal Reserved */               
    Ifx_Strict_32Bit USB:8;           /**< \brief [31:24] User Status Bits - USB (rw) */               
} Ifx_CPU_PSW_Bits;

在配置Mcal的时候,也会有这样的配置项。比如ADC的配置为 user-1

#define ADC_MCAL_USER1  (1U)

               

1.3 内存保护

提供允许访问的内存区域,与区域方式。具体什么意思呢? 就是分为以下两种。

•Range Based

这是一种开销比较小的方式,不需要内存虚拟的方式,提供了一段地址,给这一段地址设置了权限。这里的地址是真实的,直接访问的。

•Page Based

这是比较传统的方式,基于虚拟地址,这样需要MMU 的支持。虚拟地址,对虚拟出来的页 进行权限限制。

                    

2. Range Base内存保护

针对range base的内存保护,是不需要虚拟内存的,操作的是真实的地址。将从下面三个方面进行介绍。

2.1 保护范围 protection ranges

对于保护范围,是一段连续的地址。在这段连续的地址上,进行权限的设置。

起始地址 << 保护区域 << 终止地址。

针对数据的访问,读写权限的操作。地址的最小颗粒度是8个bit。 也就是uint8 的大小。

对于指令的访问,因为是个指针,32位单片机走的是32个bit的地址。所以这里是 uint32的颗粒度。

所以在设置的时候,我们需要保证其实地址小于终止地址,并且满足相对应的颗粒度即可。

那么如果地址中间怎么办呢?就是说如果允许访问,与不允许访问连接在一起了呢? 如下图。

[img=560.010009765625,93.20001220703125]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxeteKib7aIABGE4FFkkLGEgFB5JfQOlcM9SZjuiaW4pKjFzzXP7Sp6W6g/640?wx_fmt=png[/img]

为了确保在所有TriCore实现中的确定性行为,应该在每个内存保护区域之间留下至少是最大内存访问大小的两倍的区域(减去一个字节)作为缓冲区。一些实现可能需要更小的缓冲区间距。

               

2.2 权限访问

针对上面定义的保护范围,可以设置一些不同的访问权限。分为如下

•读权限

•写权限   

•指令操作权限

简写如下

[img=560.010009765625,86.02999877929688]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxBSsdicic2aUch5JoV8iaC0WxTCw2NfyqPt7duUOHR7rHUSXjZLA4MK22g/640?wx_fmt=png[/img]

               

2.3 Protection Set

为了全部地址使用访问权限的完整操作叫做Protection Set

每一个操作(Protection Set) 包含如下

•选择代码保护范围

•选择数据保护范围

•为每一个范围定义访问权限

•使能指令执行保护范围

•使能数据读取保护范围

•使能数据写入保护范围

每个TriCore实现的提供的内存保护集的数量是有限制的,限制为最少两个,最多八个。

               

3. 内存保护使用

•定义数据,执行,保护的地址范围

•在已经定义了的protection set 里面定义 访问的权限。读,写,执行

•active protection set

•使能内存保护

下面我们具体说一下。   

3.1 定义数据范围

数据范围是由高地址与低地址组成。也就是下面两个寄存器来设置。

DPRx_U (x=0-31)

[img=560.010009765625,267.3800048828125]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxzajrrK2BY8WKYrDibHFFzCxszvQsHyO7NM7hPbOuiaAIMbfcv9riax3aQ/640?wx_fmt=png[/img]

               

DPRx_L (x=0-31)

[img=560.010009765625,239.8900146484375]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxqvhynlZAHH6SdKnXJsDDGjQN85lVianKaibzmXOjTXD6rKddySIPphUQ/640?wx_fmt=png[/img]

               

在这里面x表示的是可以操作的数量。也就是set-x。 实际的寄存器看了,这个可能不是0-31 而是有限制的。

所以根据上面的寄存器,我们可以写一个函数来设置 数据范围。   

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

               

__isync() 这个是编译器的指令。表示上面的指令都需要被完全执行完。

[img=560.010009765625,114.75997924804688]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxeOegjELXW6VhJfneGpJankNg2NebQMgoJmOicSI3FjkS4Pn2FDJtfZQ/640?wx_fmt=png[/img]

另外两个指令也一起说了。

往core寄存器写入,与从core寄存器读出数据。

[img=560.010009765625,66.46002197265625]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxP6Sb2lBC1aNvtzjiadudvz7GZLyaBRILQOoHIj5wOmKuuiccY6T4oueA/640?wx_fmt=png[/img]

               

[img=560.010009765625,112.17999267578125]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxR7zy3tbPI65v9Hg2w2LXHhUAjh8t6A4aEZE0v0p05uaxwurWODgV1g/640?wx_fmt=png[/img]

               

3.2 定义代码执行的地址范围

和上面的数据地址范围一样。只是前面提到的 最小颗粒度的问题。这个只有在具体使用的时候才会体现的到,也就是32位的问题。

CPRx_U

[img=560.010009765625,281.5799560546875]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxsx3ib3VWWCIQckaOFAJCBtIM9OaYF5LHLKnrdwDULIibnIjj8k4xrPMg/640?wx_fmt=png[/img]

               

CPRx_L

[img=560.010009765625,274.8800048828125]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxqr2YTX7ib3GianeWgtbzwXO9ID5KcX38DicK9WU54mL5FOkgK4xd5iczAQ/640?wx_fmt=png[/img]

注意一下,其实在寄存器的type就提现到了,最后4个byte是只读不写的。也就是说这里是 已经限定了 32个bit的对齐。

根据前面的寄存器我们可以得出下面的代码。

               

void define_code_protection_range(uint32 lowerBoundAddress, uint32 upperBoundAddress, uint8 range)               
{               
    switch(range)               
    {               
        case 0: /* Code Protection Range 0 */               
            __mtcr(CPU_CPR0_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 0       */               
            __mtcr(CPU_CPR0_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 0       */               
            break;               
        case 1: /* Code Protection Range 1 */               
            __mtcr(CPU_CPR1_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 1       */               
            __mtcr(CPU_CPR1_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 1       */               
            break;               
        case 2: /* Code Protection Range 2 */               
            __mtcr(CPU_CPR2_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 2       */               
            __mtcr(CPU_CPR2_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 2       */               
            break;               
        case 3: /* Code Protection Range 3 */               
            __mtcr(CPU_CPR3_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 3       */               
            __mtcr(CPU_CPR3_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 3       */               
            break;               
        case 4: /* Code Protection Range 4 */               
            __mtcr(CPU_CPR4_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 4       */               
            __mtcr(CPU_CPR4_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 4       */               
            break;               
        case 5: /* Code Protection Range 5 */               
            __mtcr(CPU_CPR5_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 5       */               
            __mtcr(CPU_CPR5_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 5       */               
            break;               
        case 6: /* Code Protection Range 6 */               
            __mtcr(CPU_CPR6_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 6       */               
            __mtcr(CPU_CPR6_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 6       */               
            break;               
        case 7: /* Code Protection Range 7 */               
            __mtcr(CPU_CPR7_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 7       */               
            __mtcr(CPU_CPR7_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 7       */               
            break;               
        case 8: /* Code Protection Range 7 */               
            __mtcr(CPU_CPR8_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 8       */               
            __mtcr(CPU_CPR8_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 8       */               
            break;               
        case 9: /* Code Protection Range 7 */               
            __mtcr(CPU_CPR9_L, lowerBoundAddress);      /* Set the lower bound of CPU Code Protection Range 9       */               
            __mtcr(CPU_CPR9_U, upperBoundAddress);      /* Set the upper bound of CPU Code Protection Range 9       */               
            break;               
    }               
    __isync();               
}

               

3.3 为数据设置读权限

根据前面的地址设置,我们可以对该段地址进行读权限的设置。寄存器如下。

[img=560.010009765625,296.52001953125]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxZqPAv0icSHzR1ib6WZcavPphqEDZhMweuLMRg8EQZNvQ42l7JF51amXQ/640?wx_fmt=png[/img]

这里能看出来n对应的是range. x 是不同的sets。 通过上面的寄存器可以写出下面的代码。

               

void enable_data_read(uint8 protectionSet, uint8 range)               
{               
    Ifx_CPU_DPRE DPRERegisterValue;               
              
    /* Get the CPU Data Protection Read Enable Register value */               
    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;               
              
    }               
              
    DPRERegisterValue.B.RE_N |= (1 << range); /* Set the bit corresponding to the given Data Protection Range */               
              
    /* Set the CPU Data Protection Read Enable Register value to enable data read access */               
    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;               
    }               
              
    __isync();               
              
}

               

3.4 为数据设置写权限

同样的,对前面配置的地址进行写权限的set. 可以看下面的寄存器

[img=560.010009765625,299.25]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxibIyFdjRNBrYgblKbm3xONow2JBxL0xKUichPeL7jibGx7YZibADDOEh1Q/640?wx_fmt=png[/img]

和前面读的解释一样,可以得出下面的代码。

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;               
    }               
              
    __isync();               
}

               

3.5 为地址设置执行权限

最后一个权限,指令访问可执行的权限。根据寄存器一样的。

[img=560.010009765625,301.29998779296875]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxXHKExvbpvZByia05uf7U8O61PkN7pxpPg3aS7GI6qaHOZv28ClicF4og/640?wx_fmt=png[/img]


可以得出下面这样的代码。range 和 protectionset 来进行设置。

               

void enable_code_execution(uint8 protectionSet, uint8 range)               
{               
    Ifx_CPU_CPXE CPXERegisterValue;               
              
    /* Get the CPU Code Protection Execute Enable Register value */               
    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;               
    }               
              
    /* Set the bit corresponding to the given Code Protection Range */               
    CPXERegisterValue.B.XE_N |= (0x1 << range);               
              
    /* Set the CPU Code Protection Execute Enable Register value to enable coded execution */               
    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;               
    }               
              
    __isync();               
              
}

               

3.6 Active Protection set

设置完成之后,就需要激活刚才三个enable的相对应的set. 这里也有对应的寄存器来进行设置。

不过这个是系统寄存器。结构体如下。

typedef struct _Ifx_CPU_PSW_Bits               
{               
    Ifx_Strict_32Bit CDC:7;           /**< \brief [6:0] Call Depth Counter - CDC (rwh) */               
    Ifx_Strict_32Bit CDE:1;           /**< \brief [7:7] Call Depth Count Enable - CDE (rwh) */               
    Ifx_Strict_32Bit GW:1;            /**< \brief [8:8] Global Address Register Write Permission - GW (rwh) */               
    Ifx_Strict_32Bit IS:1;            /**< \brief [9:9] Interrupt Stack Control - IS (rwh) */               
    Ifx_Strict_32Bit IO:2;            /**< \brief [11:10] Access Privilege Level Control (I/O Privilege) - IO (rwh) */               
    Ifx_Strict_32Bit PRS:2;           /**< \brief [13:12] Protection Register Set - PRS (rwh) */               
    Ifx_Strict_32Bit S:1;             /**< \brief [14:14] Safe Task Identifier - S (rwh) */               
    Ifx_Strict_32Bit PRS2:1;          /**< \brief [15:15] Protection Register Set MSB - PRS2 (rwh) */               
    Ifx_Strict_32Bit reserved_16:8;    /**< \brief [23:16] \internal Reserved */               
    Ifx_Strict_32Bit USB:8;           /**< \brief [31:24] User Status Bits - USB (rw) */               
} Ifx_CPU_PSW_Bits;

是PSW寄存器,需要注意的是,这个寄存器是直接操作CPU 寄存器,在这个阶段不可以进行上下文切换。PSW 如果被放在了上下文切换里面,可能会丢失。所以函数需要写成 inline的方式。

如下。

inline void set_active_protection_set(uint8 protectionSet)               
{               
    Ifx_CPU_PSW PSWRegisterValue;               
    PSWRegisterValue.U = __mfcr(CPU_PSW);               /* Get the Program Status Word (PSW) register value         */               
    PSWRegisterValue.B.PRS = protectionSet;             /* Set the PRS bitfield to enable the Protection Set        */               
    __mtcr(CPU_PSW, PSWRegisterValue.U);                /* Set the Program Status Word (PSW) register               */               
}

               

3.7 激活内存保护

前面所有的配置都完成了,我们就可以激活内存保护功能。内存保护有相对应的系统寄存器。这里操作以下即可。

SYSCON

               

[img=560.010009765625,456.6199951171875]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxHTBia9PuwxERbDFqkDPGHuE15I9sgUhzzjy1vQHAbqYyU4IroZoSIGA/640?wx_fmt=png[/img]

[img=560.010009765625,265.760009765625]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxsCbj515XT6gQ7HFtWUsDA2mQiaYC9EjAjx4DdP5NKlpxWPH6SQ2RV6w/640?wx_fmt=png[/img]

根据寄存器 代码如下

void enable_memory_protection()               
{               
    Ifx_CPU_SYSCON sysconValue;               
    sysconValue.U = __mfcr(CPU_SYSCON);                 /* Get the System Configuration Register (SYSCON) value     */               
    sysconValue.B.PROTEN = 1;                           /* Set the PROTEN bitfield to enable the Memory Protection  */               
    __mtcr(CPU_SYSCON, sysconValue.U);                  /* Set the System Configuration Register (SYSCON)           */               
              
    __isync();               
              
}

               

4. Autosar Os ECU-Partition & Os-Application

4.1 总体设计

通过上面三章的寄存器,MPU模块的介绍,我们来从autosar 的角度继续这一个章节。

首先我们设计一个系统。利用autosar os 的内存保护机制,来与上面的章节联系起来。

[img=560.010009765625,400.010009765625]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxPFgTknjrwq4lWol6CluYNjNibCY2UJRgS2y9xsOlSxmSmkra4SPHhsg/640?wx_fmt=png[/img]

               

所以这里需要针对OS 进行配置。前面我们提到了OS Scalability Class 有四种。

•SC1:这个级别包含了OSEK OS的基本功能,以及标准的计数器和轮询式调度表。OSEK OS提供了一系列特性以支持AUTOSAR,包括基于优先级的调度、处理中断的功能(其中中断的优先级高于任务)、防止错误使用OS服务的保护措施,以及StartOS和StartupHook启动接口,ShutdownOS和ShutdownHook关闭接口等。

•SC2:这个级别在SC1的基础上增加了时间保护功能。时间保护的主要目的是防止时间错误通过操作系统传播,导致其他正常运行的任务或中断错过终止时间。它主要通过执行时间保护、内部间隔时间保护和锁定时间保护来实现。

•SC3:这个级别在SC1的基础上增加了内存保护功能。这主要针对未经授权访问安全相关组件的内存保护,提高了系统的安全性。

•SC4:这个级别结合了SC1的所有功能,同时增加了SC2的时间保护和SC3的内存保护。因此,SC4是这四个级别中安全性最高的。

4.2 Os 配置

这里我们直接一步到位。Scalability Class4 不过需要注意的是, Os的status 也需要改成extended.

至于为什么呢,因为os extended 会增加一些api, 也就是高级一点的才能用到的API. 比如

FUNC(void, OS_CALLOUT_CODE) Os_Cbk_SetMemoryAccess(Os_UntrustedContextRefType ApplicationContext)

这也是接下来我们需要终点讲的函数。

至于其他还增加了什么API 这里就不一一说了。

所以从Os 配置的角度很简单。

Os

•multi-core

•OsScalabilityClass

•OsStatus

[img=560.010009765625,519.6599731445312]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsx6icch3UEjoK21k8cpu75NORMMu9HxtqVOfBqQ0DGcfHymdFGTic5ujoQ/640?wx_fmt=png[/img]

OsApplication

增加一个新的,要reference 到已有的core 和 partition. 做到与前面的图相匹配。最好里面reference 一些任务和object.这样在生成代码的时候有参照。更好的理解。

[img=560.010009765625,519.6599731445312]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxrExV9lCWdxXk1qWnibVzzahaX7eSHO6Vaay6PQ9jr8xS7BicWnJoBJGA/640?wx_fmt=png[/img]

4.3 代码生成

通过上面的配置,我们来生成代码看一下。

主要提出两个函数。下面是os 的cbk 函数

FUNC(boolean, OS_CALLOUT_CODE) Os_Cbk_GetSetProtection(boolean set)

FUNC(void, OS_CALLOUT_CODE) Os_Cbk_SetMemoryAccess(Os_UntrustedContextRefType ApplicationContext)

FUNC(ProtectionReturnType, OS_CALLOUT_CODE) ProtectionHook(StatusType FatalError)

我们来分析一下结构体,看看大概可能怎么去使用。

在回调函数Os_Cbk_SetMemoryAccess中,根据Os_ApplicationContext中的配置信息,实现具体的内存访问权限设置。其实这里可以有MPU 也可以没有MPU。没有MPU 的话,就简单的用软件来进行保护。如果有MPU. 需要在回调函数里面 把内存保护单元 MPU的硬件相关机制放到这里。

先分析一下结构体

typedef struct Os_UntrustedContextType_s {               
  ApplicationType Application;               
  CoreIdType CoreID;               
  TaskType TaskID;               
  ISRType ISRID;               
  MemoryStartAddressType Address;               
  MemorySizeType Size;               
  boolean Trusted;               
} Os_UntrustedContextType;

这里可以看出来,最小的单元是任务或者是中断。这些中断和任务如果被部署到了Non-Trusted 的Os-Application 里面。则访问其他资源的时候,可能就会受阻。跟着这个思路我们看一下应该是什么时候判断的呢。

任务,中断,调度的时候。看看代码

[img=560.010009765625,256.82000732421875]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxUldIs9KJmEJZNLW56J5qCn6sCqeaHpL0wQZEnxibomMF73zExDia4WFA/640?wx_fmt=png[/img]

               

FUNC(void, OS_CODE_CORE0_LOCAL) Os_Dispatch0(void) {               
  const Os_CoreConfiguration *os_current_core_const = &Os_const_coreconfiguration[0U];               
  ..........               
    if (0 == Os_setjmp(Os_RunningTask->dynamic->terminate_jump_buf)) {           /*lint !e545 Address of what might be an array */               
                    
      Os_RunningTask->dynamic->termination_state = OS_TERM_NIL;               
      Os_CallingContext = 2048U;               
      Os_CurrentTerminator = &(Os_RunningTask->dynamic->terminate_jump_buf); /*lint !e545 Address of what might be an array */               
      if (app->tmask != OS_TRUSTED_TMASK) { /* [$UKS 2050] */               
        Os_StackValueType sp_val;               
        sp_val = Os_GetSP();               
        Os_ApplicationContext.Address = (MemoryStartAddressType)((Os_BiggestCommonType)sp_val.sp); /*lint !e923 !e9078 : really an address */               
        Os_ApplicationContext.Size = 0U;               
        Os_ApplicationContext.TaskID = Os_RunningTask;               
        Os_ApplicationContext.ISRID  = INVALID_ISR;               
        Os_ApplicationContext.CoreID = os_current_core_const->core_id;               
        Os_ApplicationContext.Application = app->app_id;               
        Os_ApplicationContext.Trusted = (app->tmask != OS_UNTRUSTED_TMASK) ? TRUE : FALSE;               
        Os_Cbk_SetMemoryAccess(&Os_ApplicationContext); /* [$UKS 1755] */               
      }               
      OS_MTCR(0xFE2C, 0x8000U); OS_SEQ_POINT();

中间省略了一部分代码,之前写过OS调度的文章,从这里可以看出来在调度的过程。准备要 进入task的时候前面,会根据当前过来的任务,中断,判断一下 是否是trust的。如果不是 OS_TRUSTED_TMASK 则就进入了刚才前面提到的 cbk 函数。

好,到这里我们大概知道了Os 的一些操作。 下面我们来结合MPU, 看看我们需要怎么搞。

5 MPU 测试代码分析

主要的有几点

•结合前三章,实现MPU的驱动接口

•结合os的cbk 函数,实现与MPU 的关联

•Init, DeInit 等 MPU 的本身操作

•实现一些Hook函数

•等等

我们先回顾两个概念。protection ranges, protection set

5.1 Protection Ranges

Protection Ranges 是MPU用于定义哪些内存区域需要受到保护的单元。每个保护范围通常都指定了一个起始地址和一个大小,以定义一个连续的内存区域。每个保护范围还可以配置有读、写和执行权限。

1.定义范围:你需要指定每个保护范围的起始地址和大小。这决定了哪些内存地址属于这个保护范围。

2.配置权限:为每个保护范围配置适当的读、写和执行权限。这决定了哪些操作是允许的,哪些是不允许的。

3.启用范围:在配置好保护范围后,你需要启用这个范围,使其生效。

5.2 Protection Sets

Protection Sets 是用于组合多个保护范围的逻辑组。一个保护集可以包含多个保护范围,这样可以将相关的保护范围组合在一起,便于管理和配置。

1.组合范围:你可以将多个保护范围组合到一个保护集中。这通常是因为这些范围在逻辑上是相关的,或者你需要将它们作为一个整体来管理。

2.配置集属性:保护集本身也可以有一些属性或配置,比如是否启用整个保护集,或者设置一些集级别的权限或行为。

3.激活保护集:配置好保护集后,你需要激活它以使其生效。当激活后,MPU会监视所有属于该保护集的保护范围,并根据配置的权限进行访问控制。

我们来准备写一下测试代码

5.3 测试代码

5.3.1 任务

我们这里不适用os. 所以也没有任务的概念了。

5.3.2 初始化

整体思路我写了一下。用到的函数在前面面都提到了。下面重复说一下。

[img=560.010009765625,744.9000244140625]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxKF5gj0IOHaSE4AdicA81VH9JP0ib2NWhibB4tObqef45B3YwEuqZqeLkg/640?wx_fmt=png[/img]

inlint void mmu_init(void)                 
{                 
    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);                 
               
    define_code_protection_range(FIRST_ADDR, LAST_ADDR, CODE_PROTECTION_RANGE_0);                 
               
    enable_code_execution(PROTECTION_SET_1, CODE_PROTECTION_RANGE_0);                 
               
    set_active_protection_set(PROTECTION_SET_1);                 
               
    enable_memory_protection();                 
}

5.3.3 测试case

初始化,也就是固定的设置好了并且激活了保护范围。然后紧接着就进行测试代码

unsigned char main(void)                 
{                 
    volatile uint8 dummyRead;                 
    unsigned int i;                 
    mmu_init();                 
    for(i = 0; i < DUMMY_ELEMENTS_NUM; i++)                 
    {                 
        /* Make a read access to the array which is partially protected. */                 
        dummyRead = dummyData;                 
        if(i == 47) dummyRead = 0;                 
    }                 
               
    while(1)                 
    {                 
    }                 
}

这里面当运行到数据0-47的时候是没问题的。

如果范围变化的话,会进入MMU 的trap. MMU 的trap 简单的来说有读,写,访问错误等trap

主要存在于 CLASS 1 的 trap

[img=560.010009765625,206.72000122070312]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxVicK2WKoz6m9WWcicedLzvt6ibia47hn7EEMm0C4UOQxkSuAxG7jIYdqew/640?wx_fmt=png[/img]

[img=560.010009765625,180.08001708984375]https://mmbiz.qpic.cn/sz_mmbiz_png/Vgbm9ibpszia4lBRA1N15amrMGQBWOiaVsxOu13pe0fBbbBRXdKQ5lMGSEzKTjgxXove0pII7CTECibmc4ypicewBrA/640?wx_fmt=png[/img]

5.3.4 hook

在前面我们提到了生成的接口函数

FUNC(ProtectionReturnType, OS_CALLOUT_CODE) ProtectionHook(StatusType FatalError)

Protection Hook的主要作用是提供一个机制,允许在特定系统保护事件发生时执行自定义的代码。这些事件可能包括访问违规、内存保护错误等。当这些事件发生时,Protection Hook会被触发,并执行预先定义的代码,以便进行错误处理、系统恢复或其他必要的操作。

通过Protection Hook,开发人员可以更加灵活地处理系统保护相关的问题。他们可以根据实际需求,自定义Hook函数的内容,以实现对特定事件的响应和处理。这有助于提升系统的稳定性和可靠性,减少因系统保护事件导致的潜在问题。

需要注意的是,Protection Hook的实现和使用需要遵循AUTOSAR规范和标准,以确保系统的兼容性和一致性。同时,开发人员也需要对系统保护机制有深入的了解,以便正确地配置和使用Protection Hook。

这里有os的情况下, 会进入保护hook. 我们可以根据error 是什么,来针对写接下来的操作。

autosar 文件 Os.h 里面会给出这个宏定义。也就是说 发生内存保护的时候,ProtectionHook 的形参就是

#define E_OS_PROTECTION_MEMORY ((StatusType)14U)

举个例子写protectionHook.

FUNC(ProtectionReturnType, OS_CALLOUT_CODE) ProtectionHook(StatusType FatalError)                 
{                 
           ProtectionReturnType Action = PRO_IGNORE;                 
           OsTrapInfoType MemError_TrapInfo;                 
           TaskType MemError_TaskId;                 
           ISRType MemError_IsrId;                 
               
           switch (FatalError)                 
           {                 
                      case E_OS_PROTECTION_MEMORY:                 
                      xxxxxxxxxx                 
                      ......

快速发帖

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|Archiver|汽车工程师之家 ( 渝ICP备18012993号-1 )

GMT+8, 4-5-2024 05:44 , Processed in 0.440583 second(s), 27 queries .

Powered by Discuz! X3.5

© 2001-2013 Comsenz Inc.