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。特定于供应商的驱动程序将先绑定,并将 banjo 接口导出给 MSD,以便开启/关闭 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_context_execute_immediate_commands
    • msd_connection_set_notification_callback
  • 创建信号量
    • msd_semaphore_import
    • msd_semaphore_destroy
  • 故障处理
  • 电源管理

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

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

如果这种方法不适用于某些类型的内存,驱动程序可以使用 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 构建可以移植到 Bazel,也可以封装在 Bazel 构建中。rules_foreign_cc 就是关于如何封装现有 build 的一个很好的示例。

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

  • libc.so
  • libzircon.so

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

在此阶段,您可以根据需要为所有其他引用添加桩。ICD 还必须关联到 SDK 中以 @fuchsia_pkg//pkg/magma_client 形式提供的 Magma 运行时库。

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(例如设备重启时)时都可能会发生变化。

每个 magma 设备路径都可以使用 vk_icdInitializeOpenInNamespaceCallback 打开,并且生成的 zircon 通道可以使用 magma_device_import 提供给 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_icdInitializeOpenInNamespaceCallback 提供的 OpenInNamespace 回调的调用。

此阶段的测试:

实现 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 事件导入/导出二进制信号量。此扩展已上游到 Vulkan 规范

此阶段的测试:

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

VK_FUCHSIA_buffer_collection

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

此扩展目前处于开发阶段,可能会发生变化,但可以在 Fuchsia 内部的 Vulkan 头文件中找到。

此阶段的测试:

验证

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

长期支持

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