1. 搭建QNX驱动开发环境

任务目标

在虚拟机中完成QNX SDP 7.0的安装,配置宿主机与QNX虚拟机之间的交叉编译链路,创建最小字符设备驱动项目并成功编译生成可加载的.so驱动文件。

环境与依赖

  • 宿主机:Ubuntu 20.04/22.04 x86_64,已安装VirtualBox 6.1+或VMware Workstation 15+
  • 虚拟机:QNX SDP 7.0(含QNX Neutrino 7.0实时操作系统),镜像文件 qnx-sdp-7.0-desktop.iso
  • 交叉编译工具链:QNX SDP自带的qcc(基于GCC的QNX交叉编译器),安装后位于 $QNX_HOST/usr/bin/qcc
  • 目标架构:x86_64(虚拟机架构),编译时使用 -Vgcc_ntox86_64 选项指定

实施步骤

1. 虚拟机安装QNX SDP

  1. 在VirtualBox中新建虚拟机,类型选择Other/Unknown(64位),分配至少4GB内存、40GB动态扩展虚拟硬盘。
  2. 挂载qnx-sdp-7.0-desktop.iso启动,按提示完成安装。安装时选择QNX Neutrino Desktop图形环境。
  3. 安装完成后进入系统,打开终端确认版本:uname -a应显示QNX与x86_64。

2. 配置网络与共享目录

  1. 虚拟机网络设为桥接模式,确保宿主机与虚拟机可互相ping通。
  2. 在宿主机创建共享目录~/qnx_share,通过VirtualBox共享文件夹或Samba挂载到虚拟机/data目录,用于传输源码与编译产物。

3. 配置交叉编译环境

在宿主机安装QNX SDP主机端工具(Host部分),安装完成后设置环境变量:

export QNX_TARGET=/opt/qnx700/target/qnx7
export QNX_HOST=/opt/qnx700/host/linux/x86_64
export PATH=$QNX_HOST/usr/bin:$PATH

验证工具链可用:

qcc -Vgcc_ntox86_64 --version

输出应显示QNX编译器版本信息,说明交叉编译工具链配置成功。

4. 创建最小驱动项目

在宿主机~/qnx_share下创建驱动项目目录minidrv,包含以下文件:

项目文件:minidrv/build.sh

#!/bin/sh
# QNX最小驱动编译脚本
export QNX_TARGET=/opt/qnx700/target/qnx7
export QNX_HOST=/opt/qnx700/host/linux/x86_64
export PATH=$QNX_HOST/usr/bin:$PATH

qcc -Vgcc_ntox86_64 -c minidrv.c -o minidrv.o
qcc -Vgcc_ntox86_64 -shared -o minidrv.so minidrv.o
echo "Build complete: minidrv.so"

驱动源码:minidrv/minidrv.c

#include <sys/types.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <stdio.h>
#include <string.h>

// 驱动名称与版本
static char *drv_name = "minidrv";
static char *drv_version = "1.0.0";

// 设备路径名
static char *dev_path = "/dev/minidrv";

// 连接处理函数
static int io_open(resmgr_context_t *ctp, io_open_t *msg, void *extra) {
    return iofunc_open_default(ctp, msg, NULL, NULL);
}

// 设备关闭处理
static int io_close(resmgr_context_t *ctp, void *reserved, void *extra) {
    return iofunc_close_default(ctp, reserved, NULL);
}

// 设备读取处理
static int io_read(resmgr_context_t *ctp, io_read_t *msg, void *extra) {
    char buf[] = "minidrv: hello from QNX driver\n";
    int len = strlen(buf);
    
    if (msg->nbytes > len) {
        msg->nbytes = len;
    }
    
    return resmgr_handler(ctp, buf, msg->nbytes);
}

int main(int argc, char **argv) {
    dispatch_t *dpp;
    resmgr_attr_t resmgr_attr;
    dispatch_context_t *ctp;
    int id;
    
    // 初始化dispatch
    dpp = dispatch_create();
    if (dpp == NULL) {
        fprintf(stderr, "Failed to create dispatch\n");
        return 1;
    }
    
    // 初始化资源管理器属性
    memset(&resmgr_attr, 0, sizeof(resmgr_attr));
    resmgr_attr.nparts = 1;
    resmgr_attr.handle = NULL;
    
    // 注册资源管理器
    id = resmgr_attach(dpp, &resmgr_attr, dev_path, 
                       _FTYPE_ANY, 0, NULL, NULL);
    if (id == -1) {
        fprintf(stderr, "Failed to attach resource manager\n");
        return 1;
    }
    
    // 创建dispatch上下文
    ctp = dispatch_context_alloc(dpp);
    if (ctp == NULL) {
        fprintf(stderr, "Failed to allocate dispatch context\n");
        return 1;
    }
    
    printf("%s v%s started, device at %s\n", 
           drv_name, drv_version, dev_path);
    
    // 主循环处理消息
    while (1) {
        if (dispatch_block(ctp) == -1) {
            fprintf(stderr, "dispatch_block failed\n");
            break;
        }
        dispatch_handler(ctp);
    }
    
    // 清理
    resmgr_detach(dpp, id, NULL);
    dispatch_context_free(ctp);
    dispatch_destroy(dpp);
    
    return 0;
}

5. 编译与部署

  1. 在宿主机执行:chmod +x build.sh && ./build.sh
  2. 编译成功后,将minidrv.so复制到虚拟机/data目录。
  3. 在虚拟机中执行:cp /data/minidrv.so /lib/modules/(或直接运行mount -T io-pkt /lib/modules/minidrv.so加载)。

验证方法

  1. 编译验证:build.sh执行无报错,生成minidrv.so文件。
  2. 加载验证:在QNX虚拟机中执行mount -T io-pkt /lib/modules/minidrv.so,无错误输出。
  3. 功能验证:执行cat /dev/minidrv,预期输出:minidrv: hello from QNX driver。
  4. 卸载验证:执行umount /dev/minidrv,确认设备节点消失。

以上步骤全部通过,即完成QNX驱动开发环境搭建与最小驱动编译验证闭环。