Magma:携号转网指南

如需大致了解 Magma,包括背景信息、硬件要求和架构说明,请参阅 Magma:概览

本文档介绍了驱动程序开发者可遵循的将 Vulkan 驱动程序移植到 Fuchsia 的流程。

要求

将 Vulkan 驱动程序移植到 Fuchsia 需要执行以下操作:

  • 硬件文档(寄存器规范、操作理论)。
  • 参考 Vulkan 实现 (Linux)。
  • 客户端驱动程序库 (ICD) 应提供符合 Vulkan 1.1/1.2 的实现。

硬件必须已通过启动,以便网络访问、磁盘存储和 fx pave 正常运行。

目前,Magma 仅支持 UMA 设备,但如果您有远大抱负,可以尝试移植到具有独立内存的 GPU。

创建桩系统驱动程序

Magma 系统驱动程序 (MSD) 类似于其他操作系统上的内核驱动程序。此时,请考虑是移植其他操作系统的现有内核驱动程序,还是从头开始编写一个。

此时,您应阅读驱动程序概念部分,了解 Fuchsia 驱动程序模型。

此选择取决于现有内核驱动程序代码的许多方面。一些注意事项:

  • 驱动程序是否具有平台抽象层,或者是否依赖于 Linux 内核接口?
  • 许可。
  • 其 ioctl 接口与 Magma 入口点的相似程度如何?

第一个编码步骤是创建一个可构建的基本 MSD。MSD 位于驱动程序目录中。它们使用 GN 构建系统构建为 fuchsia_drivers。Magma 系统驱动程序必须是开源的,但不能是 GPL,并且必须托管在 fuchsia.googlesource.com 上。

Fuchsia 驱动程序是普通的用户空间进程。这意味着它们可以访问大部分 c 库和一部分 POSIX API。与大多数进程不同,不允许进行任何文件系统访问。

目前,Magma 支持两种不同的设备类型 - 平台设备和 PCI 设备。

  • SoC 通常具有平台设备。这些不是即插即用型设备,但需要板驱动程序来将适当的资源委托给它们。
  • PCI 设备位于 PCI 总线上,由 PCI 总线驱动程序委托资源。

Fuchsia 驱动程序框架支持这两种驱动程序,因此可以像普通的 Fuchsia 驱动程序一样创建和绑定它们。

分担责任?(SoC 版本)

在 SoC 上,GPU 硬件通常会作为单独的 IP 块提供,可由 SoC 供应商进行自定义。根据供应商的自定义程度,有几种可能的处理方式。

  • 统一的 MSD,但之前已加载 SoC 专用驱动程序。
  • 为每个 SoC 或 SoC 供应商单独制作 MSD。

如果对 SoC 的自定义程度较小,最好使用统一的 MSD。供应商专用驱动程序将首先绑定,并导出 MSD 的 banjo 接口以开启/关闭 GPU、更改时钟等。这样做的好处是,通过实现新的供应商专用驱动程序,可以更轻松地将 MSD 移植到新硬件,而无需进行修改。如需了解此方法的示例,请参阅 msd-arm-maliaml-gpu

为每个 SoC 单独提供 MSD 可带来更大的灵活性,如果 GPU IP 供应商允许对 SoC 中的 IP 块进行许多自定义,则可能需要这样做。不同 SoC 的 MSD 实现可以共享一个与 SoC 无关的代码库,但会编译为独立的驱动程序。

分担责任?(PCI 版本)

PCI GPU 通常包含显示控制器硬件。显示控制器驱动程序应与 GPU 硬件分开实现,因为这样一来,该驱动程序便可存储在显示控制器应公开特定于硬件的 banjo 接口,并且 MSD 可以绑定到显示驱动程序。

如需查看拆分为两部分的 PCI 驱动程序示例,请参阅 msd-intel-genintel-display

开机

现在,MSD 正在构建,下一步是编写代码以重置设备并使其进入运行模式。此类信息包括:

驱动程序还应根据需要获取对 MMIO 范围的访问权限,并应开始处理中断。对于 SoC,必须修改主板驱动程序,以将这些资源传递给 MSD 或 SoC 专用驱动程序,并且必须添加一个设备供 MSD 绑定。

此阶段的测试:

  • 在驱动程序启动时记录 MMIO 寄存器。

实现 MSD

以下是驱动程序可以实现的主要功能列表:

  • 初始化硬件
    • msd_driver_create
    • msd_driver_configure
    • msd_driver_destroy
    • msd_driver_create_device
    • msd_device_destroy
  • 支持参数查询
    • msd_device_query
  • 支持状态转储
    • msd_device_dump_status
  • 创建连接
    • msd_device_open
    • msd_connection_close
  • 创建缓冲区
    • msd_buffer_import
    • msd_buffer_destroy
  • 设置内存空间和缓冲区映射
    • msd_connection_map_buffer_gpu
    • msd_connection_unmap_buffer_gpu
    • msd_connection_commit_buffer
    • msd_connection_release_buffer
  • 设置硬件上下文
    • msd_connection_create_context
    • msd_context_destroy
  • 命令缓冲区调度
    • msd_context_execute_command_buffer
    • msd_connection_set_notification_callback
  • 创建信号量
    • msd_semaphore_import
    • msd_semaphore_destroy
  • 故障处理
  • 电源管理

硬件成功开机后,下一步是决定如何将现有 ioctl 映射到 MSD 入口点。

在大多数情况下,Linux DRI ioctl 与 MSD 函数之间的映射关系非常简单。不过,内存管理方面存在一个例外:在 Magma 中,分配和映射内存的是 ICD,而不是 MSD(或内核驱动程序)。这可能会改变分配 VMO 的某些命令的流程,因为 MSD 必须将已有的缓冲区导入到 GPU 硬件中。

如果该方法不适用于某些类型的内存,驱动程序可能会使用 Sysmem 堆来处理该内存的分配。客户端使用 Sysmem 分配内存,并通过正常的 Magma 接口导入句柄。然后,MSD 可以与 sysmem 通信,以获取有关内存的更多信息。

驱动程序可能不需要实现所有功能。我们建议根据 ICD 的需要逐步实现 MSD 功能。这可以在实现 MSD 函数时提供上下文,并有助于避免在不需要的函数上浪费精力。

此阶段的测试:

  • 驱动程序专用单元测试(而非硬件专用)
  • 特定于硬件的驱动程序测试(请参阅示例)。这些测试应以最小的方式使用 GPU,例如写入寄存器或使 GPU 修改内存位置。
  • 使用 Magma 接口的驱动程序专用集成测试。
  • magma-conformance-tests(属于 Magma L0)。
  • magma-info-test(属于 Magma L0)。

构建 ICD

必须将 IHV ICD 移植到 Fuchsia。ICD 应使用 Bazel SDK 构建。ICD build 可以移植到 Bazel,也可以封装在 Bazel build 中。rules_foreign_cc 是一个很好的示例,展示了如何封装现有 build。

由于 ICD ABI 限制,ICD 必须静态关联到其所有依赖项。它们只能引用以下共享库:

  • libc.so
  • libzircon.so

这会限制 ICD 可以使用的依赖项。例如,以下是一些不被允许的库和可能的替代库:

在此阶段,您可以根据需要将所有其他引用存根化。ICD 还必须链接到 SDK 中提供的 Magma 运行时库,即 @fuchsia_pkg//pkg/magma_client

Vulkan 加载程序服务从软件包中检索 ICD,并将其告知 Vulkan 客户端。ICD 必须包含在具有元数据和清单 JSON 文件的 Fuchsia 软件包中,如加载器服务文档中所述。可以使用 Bazel SDK 代码库命令将此软件包提供给设备。

如果 ICD 软件包包含在 universe 中,则可以通过执行 fx shell killall vulkan_loader.cm 重新加载。之后启动的组件将获得新的 ICD 软件包,而较旧的组件在创建 Vulkan 实例时会失败。

ICD 必须导出一组特定的符号 - 请参阅 Vulkan ABI 定义。您应在此阶段实现它们。

此阶段的测试:

  • 共享库上的 readelf -d,以确保除了 libc.solibzircon.so 之外,它没有其他依赖项。
  • 使用 fx shell cat /svc/fuchsia.vulkan.loader.Loader 启动 Vulkan 加载器,并检查 ffx inspect show core/vulkan_loader 以查看是否已加载。错误将发送到 syslog。
  • 运行 vulkan_icd_load 测试。此测试将检查系统上是否有任何 ICD 可正常运行,因此在运行此测试之前,请确保系统上没有其他 ICD。

将 ICD 连接到 Magma

此时,ICD 应使用提供给 vk_icdInitializeOpenInNamespaceCallback 的回调连接到 /loader-gpu-devices/class/gpu 目录。ICD 可以使用 fuchsia.io.Directory FIDL 协议列出目录内容。此目录包含系统上所有 MSD 的设备节点,每个节点都以唯一的三位数命名。数字在一次启动中保持稳定,但每当重新加载 MSD 时(例如在设备重新启动时)可能会发生变化。

可以使用 vk_icdInitializeOpenInNamespaceCallback 打开每个 magma 设备路径,并使用 magma_device_import 将生成的 zircon 渠道提供给 libmagma。如果系统上有多个 magma 设备,驱动程序将需要使用 magma_queryMAGMA_QUERY_VENDOR_ID 来确定要使用哪个设备。

在此阶段之后,magma_* 函数将正常运行,因此可以逐步将 ioctl() 调用转换为等效的 Magma 调用。

此阶段的测试:

  • vkreadback(绘制颜色,然后读回帧缓冲区值)。这是 Magma L0 的一部分)。
  • Vulkan 一致性测试。理想情况下,在此阶段完成后,通过率应达到 100%。如需了解详情,请参阅 Magma 测试策略

移除不允许使用的符号

在关联 ICD 时,请使用版本脚本,以确保它仅公开 Fuchsia 系统 ABI 允许的符号。

只能使用 符号许可名单中列出的 ICD 符号。若要检查这一点,请将许可名单与通过在 ICD 共享库上运行 llvm-nm -gD 获得的列表进行比较。

某些不受支持的文件操作可能会替换为对提供给 vk_icdInitializeOpenInNamespaceCallbackOpenInNamespace 回调的调用。

此阶段的测试:

实现 Fuchsia 扩展程序

目前,ICD 无法与 scenic 搭配使用,并且没有窗口系统集成。驱动程序必须实现 Fuchsia 特定的 Vulkan 扩展。客户端驱动程序库应提供符合 Vulkan 1.0/1.1/1.2 的实现。

VK_FUCHSIA_external_memory

此扩展与 VK_KHR_external_memory_fd 类似,允许从 VMO 导入/导出 VkDeviceMemory。此扩展已上游到 Vulkan 规范

此阶段的测试:

  • vkext --gtest_filter=VulkanExtension.*Magma L0 的一部分)。

VK_FUCHSIA_external_semaphore

此扩展与 VK_KHR_external_semaphore_fd 类似,允许将二进制信号量导入/导出到 Zircon 事件或从 Zircon 事件导入/导出二进制信号量。此扩展已上游到 Vulkan 规范

此阶段的测试:

  • vkext --gtest_filter=VulkanExtension.*Magma L0 的一部分)。
  • vulkan-cts-zircon(属于 Vulkan CTS)。

VK_FUCHSIA_buffer_collection

此扩展程序与 sysmem 交互,并允许客户端协商图像格式和分配内存。如需了解详情,请参阅 sysmem 文档。

此扩展程序目前正在开发中,可能会发生变化,但可在 Fuchsia 内部 Vulkan 标头中找到。

此阶段的测试:

验证

上述每个子部分中列出的所有测试都必须通过。如需了解详情和查看完整的测试用例列表,请参阅测试策略文档

长期支持

必须使用硬件供应商提供的新代码更新 MSD 和 ICD。 理想情况下,代码会向上游提交,GPU 供应商将使用 Zircon DDK 提供并维护系统驱动程序。