2. 实现分区间通信的受限通道
任务目标
在VxWorks 7安全分区(Safety Profile)环境中,为分区A与分区B建立一条受限通信通道。要求:数据仅能通过显式创建的通道对象传输,禁止分区直接访问对方内存或全局变量;通道具备方向性(A→B单向),并验证跨分区数据收发的正确性。
实现方案
使用VxWorks 7的分区间通信(Inter-Partition Communication, IPC)机制——基于共享内存的SM(Shared Memory)对象与MSG_Q消息队列组合。核心思路:
- 在系统分区(System Partition)中创建共享内存区域,并绑定一个
SM_OBJ描述符; - 在分区A中通过
smOpen获取该区域的映射,写入数据; - 在分区B中通过同一
SM_OBJ读取数据,实现单向传输。
该机制由VxWorks安全内核强制隔离,分区无法绕过通道直接访问对方地址空间。
环境依赖
- VxWorks 7(Safety Profile版本,支持SM/MPU隔离)
- VxWorks Image项目包含
INCLUDE_SM和INCLUDE_MSG_Q组件 - 两个应用分区(Partition A / Partition B)已创建,且具备
SM_OBJ访问权限
关键完整代码
/* sm_ipc_common.h - 共享定义 */
#define SM_IPC_NAME "/SM_CHAN_1"
#define SM_IPC_SIZE 256
#define SM_IPC_MSGID 0x1001
typedef struct {
int valid; /* 数据有效标志 */
char payload[SM_IPC_SIZE - sizeof(int)];
} sm_ipc_data_t;
/* sm_ipc_sender.c - 分区A:发送端 */
#include <vxWorks.h>
#include <smName.h>
#include <smLib.h>
#include <string.h>
STATUS smIpcSend(const char *msg, int len)
{
SM_OBJ *smObj;
sm_ipc_data_t *data;
/* 打开已创建的共享内存对象 */
smObj = smOpen(SM_IPC_NAME);
if (smObj == NULL)
return ERROR;
/* 映射到本分区地址空间 */
data = (sm_ipc_data_t *)smMap(smObj);
if (data == NULL) {
smClose(smObj);
return ERROR;
}
/* 写入数据并置有效标志 */
if (len > (int)sizeof(data->payload))
len = sizeof(data->payload);
memcpy(data->payload, msg, len);
data->valid = 1;
smUnmap(smObj, (void *)data);
smClose(smObj);
return OK;
}
/* sm_ipc_receiver.c - 分区B:接收端 */
#include <vxWorks.h>
#include <smName.h>
#include <smLib.h>
#include <string.h>
STATUS smIpcReceive(char *buf, int bufLen, int *recvLen)
{
SM_OBJ *smObj;
sm_ipc_data_t *data;
smObj = smOpen(SM_IPC_NAME);
if (smObj == NULL)
return ERROR;
data = (sm_ipc_data_t *)smMap(smObj);
if (data == NULL) {
smClose(smObj);
return ERROR;
}
if (data->valid) {
int copyLen = strlen(data->payload) + 1;
if (copyLen > bufLen)
copyLen = bufLen;
memcpy(buf, data->payload, copyLen);
*recvLen = copyLen;
data->valid = 0; /* 消费后清除标志 */
smUnmap(smObj, (void *)data);
smClose(smObj);
return OK;
}
smUnmap(smObj, (void *)data);
smClose(smObj);
return ERROR; /* 无新数据 */
}
/* sm_ipc_setup.c - 系统分区:创建通道(仅执行一次) */
#include <vxWorks.h>
#include <smName.h>
#include <smLib.h>
STATUS smIpcSetup(void)
{
SM_OBJ *smObj;
/* 创建共享内存对象,大小含头部 */
smObj = smCreate(SM_IPC_NAME, SM_IPC_SIZE, SM_MEM_PUBLIC);
if (smObj == NULL)
return ERROR;
/* 初始化数据区 */
void *addr = smMap(smObj);
if (addr != NULL) {
memset(addr, 0, SM_IPC_SIZE);
smUnmap(smObj, addr);
}
smClose(smObj);
return OK;
}
运行与验证
- 部署:将
sm_ipc_setup.c编译到系统分区(System Partition),sm_ipc_sender.c编译到分区A,sm_ipc_receiver.c编译到分区B。 - 初始化通道:在系统分区启动脚本中调用
smIpcSetup(),创建共享内存对象。 - 发送数据:在分区A的shell中执行:
smIpcSend("Hello from A", 14) - 接收数据:在分区B的shell中执行:
char buf[64]; int len; smIpcReceive(buf, sizeof(buf), &len)
通过条件:分区B的buf内容为"Hello from A",且len值为14。若分区B尝试直接访问分区A的全局变量地址,将触发内存保护异常——这验证了通道的受限性。
常见问题
- smOpen返回NULL:确认
smIpcSetup()已在系统分区成功执行,且分区A/B的权限配置允许访问该SM对象。 - 数据竞争:当前实现使用
valid标志做简单同步,适用于单发送/单接收场景。多生产者场景需增加信号量保护。 - 通道方向性:本实现仅分区A写入、分区B读取。若需双向,需创建两个独立SM对象,分别绑定不同方向。