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");
}
编译与部署
- 在VxWorks 7工程中创建源文件
memProtectTest.c,将上述代码完整粘贴。 - 确保工程已启用安全分区功能(在VIP中配置
INCLUDE_SECURE_PARTITIONS)。 - 编译生成VxWorks镜像并下载到目标板。
运行与验证方法
- 在VxWorks shell中调用测试入口:
-> memProtectTest
- 观察串口输出,预期结果如下:
[TEST] 异常钩子已注册
[TEST] 任务开始,尝试越界访问...
[MEM-PROTECT] 捕获到异常! 类型=0x2, 地址=0x20000000
[MEM-PROTECT] 分区内存保护已生效,非法访问被拦截
[TEST] 测试流程结束
判定标准
- 通过:串口输出包含
[MEM-PROTECT] 捕获到异常且地址为0x20000000,说明MPU正确拦截了越界访问。 - 失败:输出
越界访问未被拦截,说明内存保护未生效,需检查分区配置或MPU初始化。
常见问题
- 异常类型值:ARM架构下数据访问异常类型通常为
0x2(Data Abort),具体值取决于处理器实现。 - 地址选择:
0x20000000为示例地址,实际应选择一个当前分区未映射的地址空间。若该地址恰好被映射,可改用NULL或栈边界外地址。 - 钩子未触发:确认
excHookAdd调用成功,且异常未被更高级别的处理函数提前捕获。