3. 验证内存保护机制

任务目标

在VxWorks安全分区环境中,通过构造一次越界内存访问,验证分区内存保护机制是否能够正确拦截非法访问并触发异常处理,从而确认分区间的内存隔离有效。

实现原理

VxWorks 7 的安全分区基于MPU(内存保护单元)实现地址空间隔离。每个分区拥有独立的虚拟地址映射和访问权限。当代码尝试访问不属于当前分区的地址(如越界数组、空指针解引用或访问其他分区地址)时,MPU会触发数据访问异常(data abort)。本案例通过注册异常钩子函数,捕获该异常并输出诊断信息,以此证明保护机制生效。

完整实现代码

#include <vxWorks.h>
#include <taskLib.h>
#include <stdio.h>
#include <string.h>
#include <memPartLib.h>
#include <arch/arm/armV7Lib.h>

/* 异常钩子函数:捕获数据访问异常 */
static void memFaultHook(void *arg, EXC_INFO *pExcInfo)
{
    printf("[MEM-PROTECT] 捕获到异常! 类型=0x%x, 地址=0x%x\n",
           pExcInfo->excType, pExcInfo->excAddr);
    printf("[MEM-PROTECT] 分区内存保护已生效,非法访问被拦截\n");
}

/* 越界访问测试任务 */
static void violationTask(void)
{
    volatile unsigned char *badPtr;
    volatile unsigned char val;

    printf("[TEST] 任务开始,尝试越界访问...\n");

    /* 构造一个越界地址:指向当前任务栈底之外 */
    badPtr = (volatile unsigned char *)0x20000000;  /* 故意使用无效地址 */
    val = *badPtr;  /* 触发数据访问异常 */

    /* 若未触发异常(保护未生效),则执行到这里 */
    printf("[TEST] 警告:越界访问未被拦截!内存保护可能未生效\n");
    (void)val;
}

/* 主测试入口 */
void memProtectTest(void)
{
    int taskId;

    /* 注册异常钩子 */
    excHookAdd(memFaultHook, NULL);
    printf("[TEST] 异常钩子已注册\n");

    /* 创建并启动越界访问任务 */
    taskId = taskSpawn("tMemViol", 100, 0, 20000,
                       (FUNCPTR)violationTask, 0,0,0,0,0,0,0,0,0,0);
    if (taskId == ERROR) {
        printf("[TEST] 任务创建失败\n");
        return;
    }

    taskDelay(100);  /* 等待任务执行完成 */
    printf("[TEST] 测试流程结束\n");
}

编译与部署

  1. 在VxWorks 7工程中创建源文件 memProtectTest.c,将上述代码完整粘贴。
  2. 确保工程已启用安全分区功能(在VIP中配置 INCLUDE_SECURE_PARTITIONS)。
  3. 编译生成VxWorks镜像并下载到目标板。

运行与验证方法

  1. 在VxWorks shell中调用测试入口:
-> memProtectTest
  1. 观察串口输出,预期结果如下:
[TEST] 异常钩子已注册
[TEST] 任务开始,尝试越界访问...
[MEM-PROTECT] 捕获到异常! 类型=0x2, 地址=0x20000000
[MEM-PROTECT] 分区内存保护已生效,非法访问被拦截
[TEST] 测试流程结束

判定标准

  • 通过:串口输出包含 [MEM-PROTECT] 捕获到异常 且地址为 0x20000000,说明MPU正确拦截了越界访问。
  • 失败:输出 越界访问未被拦截,说明内存保护未生效,需检查分区配置或MPU初始化。

常见问题

  • 异常类型值:ARM架构下数据访问异常类型通常为 0x2(Data Abort),具体值取决于处理器实现。
  • 地址选择:0x20000000 为示例地址,实际应选择一个当前分区未映射的地址空间。若该地址恰好被映射,可改用 NULL 或栈边界外地址。
  • 钩子未触发:确认 excHookAdd 调用成功,且异常未被更高级别的处理函数提前捕获。