# QNX SMMUMAN 用户指南 概述SMMUMANSystem Memory Management Unit Manager是运行在 ARM 和 x86 板级架构上的系统内存管理单元IOMMU/SMMU管理器。它利用 DMA 隔离和内存管理功能在支持的板卡上限制 DMA 设备只能访问被授权的内存区域。命名说明平台术语ARMSMMUSystem Memory Management UnitIntel x86VT-dVirtualization Technology for Directed I/ORenesas R-CarIPMMUIntellectual Property MMU第一部分架构三层组件架构层描述Service(smmuman)系统内存管理单元管理器进程API Library(libsmmu.a)面向客户端的 API访问和管理 smmuman 服务Support libraries/drivers(smmu-*.so)硬件特定驱动如smmu-vtd.so,smmu-rcar3.so硬件要求平台要求ARMSMMU 或等效组件如 Renesas R-Car 的 IPMMUx86VT-d 支持支持的操作系统配置QNX OS 直接在硬件上运行QH host 或禁用 hypervisorQNX OS 作为 QH VM 中的 guestQNX OS for Safety 直接在硬件上运行QNX OS 作为 QHS VM 中的 guestQNX OS for Safety 作为 QHS VM 中的 guestHypervisor guest 注意VM 必须配置为向 guest 呈现底层硬件的功能等效体。设计安全状态 (DSS)当 SMMUMAN 或其任何组件遇到未知或未定义的条件时尝试进入其设计安全状态 (DSS) — 即退出 (exit)。核心职责允许设备驱动和应用程序确定 DMA 设备可访问的内存区域根据配置和/或客户端请求将 DMA 设备访问权限编程到 IOMMU/SMMU确保编程后任何未明确授权的设备无法访问内存允许客户端检索被 IOMMU/SMMU 拒绝的 DMA 设备内存访问记录管理保留内存区域启用 DMA 设备时加入禁用时移除关键警告“Until the smmuman service programs the IOMMU/SMMUs on a board with a DMA device’s memory access permissions, that device has unrestricted access to memory.”虚拟化环境附加职责管理客户物理内存与宿主机物理内存之间的地址转换和访问控制确保透传 (pass-through) 设备无法访问其映射区域之外的宿主机物理内存第二部分安装前置条件开发主机上已安装 QNX SDP 开发环境了解如何构建 QNX OS 系统了解 QNX Software Center组件清单组件用途smmuman二进制核心服务smmu-*.so架构/板级专用库如smmu-vtd.so,smmu-rcar3.so*.smmu板级配置文件vdev-smmu.sohypervisor 虚拟 IOMMU/SMMU 设备仅 QH/QHS host构建文件示例x86 平台/bin/smmuman smmuman /lib/dll/smmu-vtd.so smmu-vtd.soARM Renesas R-Car H3/bin/smmuman smmuman /bin/dll/smmu-rcar3.so smmu-rcar3.so /etc/smmuman/rcar-h3.smmu ./smmuman-config/rcar-h3.smmuHypervisor guest/bin/smmuman smmumanHost 构建文件需包含vdev-smmu.soVM 配置需包含vdev smmu选项。第三部分启动与停止启动通常在系统启动脚本中启动 smmumansmmuman /etc/myx86.smmu关键顺序必须在启动任何启用 DMA 的驱动之前启动 smmuman 服务。运行环境检测启动时 smmuman 检查vdev-smmu虚拟设备找到→ 在 hypervisor guest VM 中运行未找到→ 假定在宿主层运行尝试加载smmu-*.so支持库两者都不可用→ “the service reports that the required hardware isn’t present and moves to its DSS”Hypervisor Guest 中的行为不加载支持库直接与vdev-smmu虚拟设备通信忽略reserved、smmu、unit、use选项仅适用于 host 层查询 vdev-smmu 确认 host smmuman 在运行且 VM 已连接停止严禁停止“You should never stop the smmuman service after it has started.” 系统完整性依赖 smmuman 持续运行。如果服务进入 DSS系统也应转换到其自身的设计安全状态。第四部分配置配置来源smmuman 在启动时以单次扫描方式读取配置。来源包括命令行配置文件.smmu板载固件架构/板级支持库配置文件语法语法含义#注释行filename加载配置文件可嵌套$env{envvar}环境变量替换$asinfo_start{name}system page asinfo 条目的起始地址$asinfo_length{name}asinfo 条目的长度使用$asinfo_start/$asinfo_length时只能使用叶子名称不可用完整路径。选项重复规则规则行为可叠加选项所有实例均添加到配置如allow可用多次互斥选项只有最后一个实例生效如foreground配置示例 (x86)debug 2 smmu vtd require allow smbs0 $asinfo_start{smbs0},$asinfo_length{smbs0},st allow xhci $asinfo_start{xhci},$asinfo_length{xhci},st device pci:0:18.0 smbs0 device pci:0:21.0 xhci硬件信息来源环境来源x86 裸机ACPI 表仅非标准 VT-d 变体需配置文件ARM 裸机板级特定代码 配置文件固件无法提供的信息Hypervisor guestvdev-smmu*虚拟设备重要提示“Without proper guidance from the system designer, the smmuman service can’t know where the information it needs resides on the board.” 必须查阅板卡制造商文档获取 SoC 位置和取值——这些值may change,even between board revisions。第五部分smmuman 命令参考语法smmuman options运行平台QNX OS关键选项概念选项可通过命令行或*.smmu配置文件指定也可两者结合服务以单次扫描方式读取启动配置从头到尾处理用户输入的信息默认覆盖从板卡检索到的信息各架构详细选项参见架构专用页面ARM SMMU、R-Car IPMMU、x86 VT-d、Global options第六部分客户端 API 参考头文件smmu.h库libsmmu.a初始化和清理函数描述smmu_init()初始化客户端进程与 smmuman 的连接smmu_fini()终止客户端与 smmuman 的连接对象管理函数描述smmu_obj_create()创建 SMMU 对象可添加设备和内存映射smmu_obj_destroy()销毁 SMMU 对象设备管理函数描述smmu_device_add_generic()添加/移除通用设备smmu_device_add_mmio()添加/移除 MMIO 设备smmu_device_add_pci()添加/移除 PCI 设备smmu_device_report_reserved()报告 DMA 设备的保留内存区域内存映射函数描述smmu_mapping_add()添加/移除 SMMU 对象的内存映射安全与违规监控函数描述smmu_safety()查询 smmuman 服务的安全状态smmu_xfer_notify()注册接收 DMA 设备内存访问违规通知smmu_xfer_status()检索 DMA 设备尝试访问未授权内存区域的记录关键数据结构类型描述smmu_*结构体SMMUMAN 客户端 API 使用的数据结构smmu_mapping_flags内存映射权限标志smmu_status违规状态记录含fault_addr,hw_specific,flags,devidsmmu_devid设备标识符含 type: SDT_PCI / SDT_MMIO权限标志标志含义SMF_READ读访问SMF_WRITE写访问SMF_EXEC执行访问SMF_NONE无权限用于移除映射第七部分API 使用工作流所需能力能力用途smmu/attach所有连接必需smmu/target使用SMF_TARGET标志时需要保留给 hypervisor步骤 1连接服务调用smmu_init()验证服务运行并建立客户端连接。步骤 2创建 SMMU 对象调用smmu_obj_create()创建对象。多个对象允许不同设备有不同内存区域映射。步骤 3添加 DMA 设备为每个设备选择合适函数generic/MMIO/PCI。关键规则同一 SMMU 对象上的所有设备共享相同的内存区域和权限一个设备只能有一个所有者重复添加返回EBUSY客户端可以在自己的对象间移动设备步骤 4添加内存映射调用smmu_mapping_add()添加内存区域和访问权限。最佳实践先添加设备再添加内存区域。如果先添加映射再添加设备smmu_device_add_*()可能返回1— 表示新设备需要页表需重新调用smmu_mapping_add()处理所有活跃映射。步骤 5移除设备和区域移除设备调用对应的smmu_device_add_*()且sop参数设为NULL移除内存区域调用smmu_mapping_add()且 flags 设为SMF_NONE步骤 6断开连接调用smmu_obj_destroy()销毁每个创建的 SMMU 对象调用smmu_fini()终止连接DMA 违规监控任何客户端不一定是对象所有者都可以监控违规smmu_xfer_notify()— 注册违规通知smmu_xfer_status()— 随时查询违规记录再次smmu_xfer_notify()— 收到通知后重新注册因为通知后清除该客户端的通知注册第八部分完整示例以下程序连接到 smmuman 服务并监控 IOMMU/SMMU 违规报告不创建 SMMU 对象或内存映射所有 DMA 设备已在启动配置中映射#includestdio.h#includestdlib.h#includeunistd.h#includeerrno.h#includesmmu.h#includeinttypes.h#includesys/neutrino.h#includesys/siginfo.h#definePULSE_CODE_SMMU_VIOLATION0intmain(intargc,char*argv[]){intresult;// 初始化为守护进程resultprocmgr_daemon(0,PROCMGR_DAEMON_NODEVNULL|PROCMGR_DAEMON_NOCLOSE);// 连接到 smmuman 服务resultsmmu_init(0);if(result!0){fprintf(stderr,smmu_init failed, errno%d\n,errno);return-1;}// 创建通道intchannelChannelCreate_r(0);intcoidConnectAttach_r(0,0,channel,_NTO_SIDE_CHANNEL,0);// 注册脉冲事件structsigeventevent;SIGEV_PULSE_INIT(event,coid,-1,PULSE_CODE_SMMU_VIOLATION,NULL);MsgRegisterEvent(event,-1);smmu_xfer_notify(event);// 主循环等待违规for(;;){struct_pulsepulse;MsgReceivePulse(channel,pulse,sizeof(pulse),NULL);// 重新注册通知smmu_xfer_notify(event);// 处理所有待处理的违规structsmmu_statusstatus;while(smmu_xfer_status(status)1){if(status.devid.typeSDT_PCI){printf(PCI violation: fault_addr0x%PRIx64 bdf%d:%d:%d\n,status.fault_addr,status.devid.pci.bus,status.devid.pci.dev,status.devid.pci.func);}elseif(status.devid.typeSDT_MMIO){printf(MMIO violation: fault_addr0x%PRIx64 phys0x%PRIx64\n,status.fault_addr,status.devid.mmio.phys);}}}smmu_fini();return0;}第九部分术语表术语定义DMADirect Memory Access — 直接内存访问Guest在 QNX Hypervisor qvm 进程中运行的操作系统Guest-physical address客户机物理内存中的地址Host-physical address主机物理内存中的地址IOMMUInput/Output Memory Management Unit — 将 DMA I/O 总线连接到主存的 MMUIPMMURenesas R-Car 平台上的 IOMMU 实现SMMUARM 架构下的 IOMMU 实现VT-dIntel Virtualization Technology for Directed I/OReserved memory region特定设备规范所需的内存区域与映射到 SMMU 对象的内存区域不同