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;
}

运行与验证

  1. 部署:将sm_ipc_setup.c编译到系统分区(System Partition),sm_ipc_sender.c编译到分区A,sm_ipc_receiver.c编译到分区B。
  2. 初始化通道:在系统分区启动脚本中调用smIpcSetup(),创建共享内存对象。
  3. 发送数据:在分区A的shell中执行:
    smIpcSend("Hello from A", 14)
  4. 接收数据:在分区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对象,分别绑定不同方向。