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 接口以供 MSD 开启/关闭 GPU、更改时钟等。这样做的好处是,可以通过实现新的供应商专用驱动程序,更轻松地将 MSD 移植到新硬件,而无需进行修改。如需查看此方法的示例,请参阅 msd-arm-maliaml-gpu

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

是否划分职责?(PCI 版本)

PCI GPU 通常包括显示控制器硬件。 显示控制器应公开硬件专用 banjo 接口,而 MSD 可以绑定到显示驱动程序。

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

开机

随着 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 是分配和映射内存的 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 构建可以移植到 Bazel,也可以封装在 Bazel 构建中。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 软件包包含在宇宙中,则可以通过执行 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 以查看是否已加载。错误信息会写入系统日志。
  • 运行 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 打开,并且可以使用 magma_device_import 将生成的 zircon 通道提供给 libmagma。如果系统中有多个 Magma 设备,驱动程序必须结合使用 magma_queryMAGMA_QUERY_VENDOR_ID 来确定要使用哪个设备。

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

在此阶段进行测试:

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

移除不允许使用的符号

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

只有符号许可名单中列出的符号可以使用 ID 中列出的符号。如需检查这一点,请将许可名单与通过在 ICD 共享库运行 llvm-nm -gD 获取的列表进行比较。

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

在此阶段进行测试:

实现 Fuchsia 扩展

此时,ICD 无法用于场景,也没有窗口系统集成。驱动程序必须实现特定于 Fuchsia 的 Vulkan 扩展。客户端驱动程序库应提供一致的 Vulkan 1.0/1.1/1.2 实现。

VK_FUCHSIA_external_memory

此扩展程序类似于 VK_KHR_external_memory_fd,它允许将 VkDeviceMemory 从 VMO 导入/导出到 VMO。此扩展程序已向上游传送至 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 提供和维护系统驱动程序。