辅助处理器 (AP) 功能

简介

辅助处理器 (AP) 功能是一种 IBM Z 加密功能,由三个 AP 指令和 1 到 256 个 PCIe 加密适配器卡组成。 AP 设备为分配给在 IBM Z 系统 LPAR 中运行的 Linux 系统中的所有 CPU 提供加密功能。

AP 适配器卡通过 AP 总线公开。 vfio-ap 的动机是使用 VFIO 调解设备框架使 AP 卡可用于 KVM 客户机。 此实现很大程度上依赖于 s390 虚拟化功能,该功能完成了提供对 AP 设备的直接访问的大部分艰苦工作。

AP 架构概述

为了便于理解设计,让我们从一些定义开始

  • AP 适配器

    AP 适配器是一种 IBM Z 适配器卡,可以执行加密功能。 可以将 0 到 256 个适配器分配给 LPAR。 分配给运行 Linux 主机的 LPAR 的适配器将可用于 Linux 主机。 每个适配器都由一个从 0 到 255 的数字标识;但是,最大适配器数量由机器型号和/或适配器类型决定。 安装后,任何 CPU 执行的 AP 指令都可以访问 AP 适配器。

    AP 适配器卡通过系统的激活配置文件分配给给定的 LPAR,该配置文件可以通过 HMC 进行编辑。 当 Linux 主机系统在 LPAR 中进行 IPL 时,AP 总线会检测分配给 LPAR 的 AP 适配器卡,并为每个分配的适配器创建一个 sysfs 设备。 例如,如果 AP 适配器 4 和 10 (0x0a) 分配给 LPAR,则 AP 总线将创建以下 sysfs 设备条目

    /sys/devices/ap/card04
    /sys/devices/ap/card0a
    

    指向这些设备的符号链接也将在 AP 总线设备子目录中创建

    /sys/bus/ap/devices/[card04]
    /sys/bus/ap/devices/[card04]
    
  • AP 域

    适配器被划分为域。 根据适配器类型和硬件配置,一个适配器最多可以容纳 256 个域。 域由一个从 0 到 255 的数字标识;但是,最大域数量由机器型号和/或适配器类型决定。 域可以被认为是用于处理 AP 命令的一组硬件寄存器和内存。 可以使用用于明文密钥加密的安全私钥配置域。 域根据其访问方式分为两种方式之一

    • 使用域是通过 AP 指令定位以处理 AP 命令的域。

    • 控制域是通过发送到使用域的 AP 命令更改的域;例如,设置控制域的安全私钥。

    AP 使用和控制域通过系统的激活配置文件分配给给定的 LPAR,该配置文件可以通过 HMC 进行编辑。 当 Linux 主机系统在 LPAR 中进行 IPL 时,AP 总线模块会检测分配给 LPAR 的 AP 使用和控制域。 每个使用域的域编号和每个 AP 适配器的适配器编号组合起来以创建 AP 队列设备(请参见下面的 AP 队列部分)。 每个控制域的域编号将以位掩码表示并存储在 sysfs 文件 /sys/bus/ap/ap_control_domain_mask 中。 掩码中的位(从最高有效位到最低有效位)对应于域 0-255。

  • AP 队列

    AP 队列是将 AP 命令发送到特定适配器内的使用域的方式。 AP 队列由 AP 适配器 ID (APID) 和 AP 队列索引 (APQI) 组成的元组标识。 APQI 对应于适配器内的给定使用域编号。 此元组形成 AP 队列编号 (APQN),唯一标识 AP 队列。 AP 指令包括一个包含 APQN 的字段,用于标识要将 AP 命令发送到哪个 AP 队列进行处理。

    AP 总线将为每个 APQN 创建一个 sysfs 设备,该设备可以从加载 AP 总线模块时检测到的 AP 适配器和使用域编号的叉积中导出。 例如,如果适配器 4 和 10 (0x0a) 以及使用域 6 和 71 (0x47) 分配给 LPAR,则 AP 总线将创建以下 sysfs 条目

    /sys/devices/ap/card04/04.0006
    /sys/devices/ap/card04/04.0047
    /sys/devices/ap/card0a/0a.0006
    /sys/devices/ap/card0a/0a.0047
    

    以下指向这些设备的符号链接将在 AP 总线设备子目录中创建

    /sys/bus/ap/devices/[04.0006]
    /sys/bus/ap/devices/[04.0047]
    /sys/bus/ap/devices/[0a.0006]
    /sys/bus/ap/devices/[0a.0047]
    
  • AP 指令

    有三个 AP 指令

    • NQAP:将 AP 命令请求消息排队到队列

    • DQAP:从队列中取消 AP 命令回复消息的排队

    • PQAP:管理队列

    AP 指令标识要定位以处理 AP 命令的域;这必须是使用域之一。 AP 命令可能会修改不是使用域之一的域,但修改的域必须是控制域之一。

AP 和 SIE

现在让我们看一下硬件如何解释在访客上执行的 AP 指令。

一个称为加密控制块 (CRYCB) 的卫星控制块附加到我们的主硬件虚拟化控制块。 CRYCB 包含一个 AP 控制块 (APCB),该控制块具有三个字段,用于标识分配给 KVM 访客的适配器、使用域和控制域

  • AP 掩码 (APM) 字段是一个位掩码,用于标识分配给 KVM 访客的 AP 适配器。 掩码中的每个位(从左到右)对应于一个从 0-255 的 APID。 如果设置了一个位,则相应的适配器对于 KVM 访客有效。

  • AP 队列掩码 (AQM) 字段是一个位掩码,用于标识分配给 KVM 访客的 AP 使用域。 掩码中的每个位(从左到右)对应于一个从 0-255 的 AP 队列索引 (APQI)。 如果设置了一个位,则相应的队列对于 KVM 访客有效。

  • AP 域掩码字段是一个位掩码,用于标识分配给 KVM 访客的 AP 控制域。 ADM 位掩码控制哪些域可以通过发送到访客使用域的 AP 命令请求消息进行更改。 掩码中的每个位(从左到右)对应于一个从 0-255 的域。 如果设置了一个位,则可以通过发送到使用域的 AP 命令请求消息来修改相应的域。

如果您还记得 AP 队列的描述,AP 指令包括一个 APQN,用于标识要将 AP 命令请求消息发送到哪个 AP 队列(NQAP 和 PQAP 指令),或者从中接收命令回复消息(DQAP 指令)。 APQN 的有效性由从 APM 和 AQM 计算的矩阵定义;它是所有分配的适配器编号 (APM) 与所有分配的队列索引 (AQM) 的笛卡尔积。 例如,如果将适配器 1 和 2 以及使用域 5 和 6 分配给访客,则 APQN (1,5)、(1,6)、(2,5) 和 (2,6) 对于访客有效。

APQN 可以提供安全密钥功能 - 即,每个域的私钥都存储在适配器卡上 - 因此每个 APQN 最多必须分配给一个访客或 Linux 主机

Example 1: Valid configuration:
------------------------------
Guest1: adapters 1,2  domains 5,6
Guest2: adapter  1,2  domain 7

This is valid because both guests have a unique set of APQNs:
   Guest1 has APQNs (1,5), (1,6), (2,5), (2,6);
   Guest2 has APQNs (1,7), (2,7)

Example 2: Valid configuration:
------------------------------
Guest1: adapters 1,2 domains 5,6
Guest2: adapters 3,4 domains 5,6

This is also valid because both guests have a unique set of APQNs:
   Guest1 has APQNs (1,5), (1,6), (2,5), (2,6);
   Guest2 has APQNs (3,5), (3,6), (4,5), (4,6)

Example 3: Invalid configuration:
--------------------------------
Guest1: adapters 1,2  domains 5,6
Guest2: adapter  1    domains 6,7

This is an invalid configuration because both guests have access to
APQN (1,6).

设计

该设计引入了三个新对象

  1. AP 矩阵设备

  2. VFIO AP 设备驱动程序 (vfio_ap.ko)

  3. VFIO AP 调解直通设备

VFIO AP 设备驱动程序

VFIO AP (vfio_ap) 设备驱动程序用于以下目的

  1. 提供接口以保护 APQN,以供 KVM 访客独占使用。

  2. 设置 VFIO 调解设备接口以管理 vfio_ap 调解设备,并创建 sysfs 接口以分配适配器、使用域和控制域,从而构成 KVM 访客的矩阵。

  3. 配置 APCB 中 APM、AQM 和 ADM,APCB 包含在 KVM 访客的 SIE 状态描述引用的 CRYCB 中,以授予访客访问 AP 设备矩阵的权限

为 KVM 访客独占使用保留 APQN

以下框图说明了保留 APQN 的机制

                              +------------------+
               7 remove       |                  |
         +--------------------> cex4queue driver |
         |                    |                  |
         |                    +------------------+
         |
         |
         |                    +------------------+          +----------------+
         |  5 register driver |                  | 3 create |                |
         |   +---------------->   Device core    +---------->  matrix device |
         |   |                |                  |          |                |
         |   |                +--------^---------+          +----------------+
         |   |                         |
         |   |                         +-------------------+
         |   | +-----------------------------------+       |
         |   | |      4 register AP driver         |       | 2 register device
         |   | |                                   |       |
+--------+---+-v---+                      +--------+-------+-+
|                  |                      |                  |
|      ap_bus      +--------------------- >  vfio_ap driver  |
|                  |       8 probe        |                  |
+--------^---------+                      +--^--^------------+
6 edit   |                                   |  |
  apmask |     +-----------------------------+  | 11 mdev create
  aqmask |     |           1 modprobe           |
+--------+-----+---+           +----------------+-+         +----------------+
|                  |           |                  |10 create|     mediated   |
|      admin       |           | VFIO device core |--------->     matrix     |
|                  +           |                  |         |     device     |
+------+-+---------+           +--------^---------+         +--------^-------+
       | |                              |                            |
       | | 9 create vfio_ap-passthrough |                            |
       | +------------------------------+                            |
       +-------------------------------------------------------------+
                   12  assign adapter/domain/control domain

为 KVM 访客保留 AP 队列的流程是

  1. 管理员加载 vfio_ap 设备驱动程序

  2. vfio-ap 驱动程序在其初始化期间将向设备核心注册一个“矩阵”设备。 这将用作所有用于为访客配置 AP 矩阵的 vfio_ap 调解设备的父设备。

  3. /sys/devices/vfio_ap/matrix 设备由设备核心创建

  4. vfio_ap 设备驱动程序将在 AP 总线上注册类型为 10 及更高版本(CEX4 及更高版本)的 AP 队列设备。 该驱动程序将提供 vfio_ap 驱动程序的探测和删除回调接口。 不支持早于 CEX4 队列的设备,这可以通过不支持将在相对较短的未来停止使用的较旧设备来简化实现,而不会不必要地使设计复杂化,并且很少有较旧的系统可用于测试。

  5. AP 总线使用设备核心注册 vfio_ap 设备驱动程序

  6. 管理员编辑 AP 适配器和队列掩码以保留 AP 队列供 vfio_ap 设备驱动程序使用。

  7. AP 总线从默认 zcrypt cex4queue 驱动程序中删除为 vfio_ap 驱动程序保留的 AP 队列。

  8. AP 总线探测 vfio_ap 设备驱动程序以绑定为其保留的队列。

  9. 管理员创建一个要由访客使用的直通类型 vfio_ap 调解设备

  10. 管理员分配要由访客独占使用的适配器、使用域和控制域。

设置 VFIO 调解设备接口

VFIO AP 设备驱动程序利用 VFIO 调解设备核心驱动程序的通用接口

  • 注册一个 AP 调解总线驱动程序,以将 vfio_ap 调解设备添加到 VFIO 组并从中删除它。

  • 创建和销毁 vfio_ap 调解设备

  • 将 vfio_ap 调解设备添加到 AP 调解总线驱动程序并从中删除它

  • 将 vfio_ap 调解设备添加到 IOMMU 组并从中删除它

以下高级框图显示了 VFIO AP 调解设备驱动程序的主要组件和接口

+-------------+
|             |
| +---------+ | mdev_register_driver() +--------------+
| |  Mdev   | +<-----------------------+              |
| |  bus    | |                        | vfio_mdev.ko |
| | driver  | +----------------------->+              |<-> VFIO user
| +---------+ |    probe()/remove()    +--------------+    APIs
|             |
|  MDEV CORE  |
|   MODULE    |
|   mdev.ko   |
| +---------+ | mdev_register_parent() +--------------+
| |Physical | +<-----------------------+              |
| | device  | |                        |  vfio_ap.ko  |<-> matrix
| |interface| +----------------------->+              |    device
| +---------+ |       callback         +--------------+
+-------------+

在 vfio_ap 模块初始化期间,使用“mdev_parent_ops”结构注册矩阵设备,该结构提供 sysfs 属性结构、mdev 函数和回调接口以管理调解矩阵设备。

  • sysfs 属性结构

    supported_type_groups

    VFIO 调解设备框架支持创建用户定义的调解设备类型。 当设备在调解设备框架中注册时,可以通过“supported_type_groups”结构指定这些调解设备类型。 注册过程为注册设备“mdev_supported_types”子目录中指定的每种调解设备类型创建 sysfs 结构。 除了设备类型,还提供了调解设备类型的 sysfs 属性。

    VFIO AP 设备驱动程序将为直通设备注册一种调解设备类型

    /sys/devices/vfio_ap/matrix/mdev_supported_types/vfio_ap-passthrough

    将仅提供 VFIO mdev 框架所需的只读属性

    ... name
    ... device_api
    ... available_instances
    ... device_api
    

    其中

    • name

      指定调解设备类型的名称

    • device_api

      调解设备类型的 API

    • available_instances

      可以创建的 vfio_ap 调解直通设备的数量

    • device_api

      指定 VFIO API

    mdev_attr_groups

    此属性组标识调解设备的用户定义 sysfs 属性。 当设备在 VFIO 调解设备框架中注册时,将在 vfio_ap 调解设备的目录中创建“mdev_attr_groups”结构中标识的 sysfs 属性文件。 vfio_ap 调解设备的 sysfs 属性为

    assign_adapter / unassign_adapter

    用于将 AP 适配器分配给/从 vfio_ap 调解设备分配/取消分配的只写属性。 要分配/取消分配适配器,适配器的 APID 会回显到相应的属性文件中。

    assign_domain / unassign_domain

    用于将 AP 使用域分配给/从 vfio_ap 调解设备分配/取消分配的只写属性。 要分配/取消分配域,使用域的域编号会回显到相应的属性文件中。

    matrix

    用于显示从分配给 vfio_ap 调解设备的适配器和域编号的笛卡尔积导出的 APQN 的只读文件。

    guest_matrix

    用于显示从 KVM 访客 CRYCB 的 APM 和 AQM 字段分别分配的适配器和域编号的笛卡尔积导出的 APQN 的只读文件。 如果任何 APQN 未引用绑定到 vfio_ap 设备驱动程序的队列设备(即,队列不在主机的 AP 配置中),则这可能与分配给 vfio_ap 调解设备的 APQN 不同。

    assign_control_domain / unassign_control_domain

    用于将 AP 控制域分配给/从 vfio_ap 调解设备分配/取消分配的只写属性。 要分配/取消分配控制域,要分配/取消分配的域的 ID 会回显到相应的属性文件中。

    control_domains

    用于显示分配给 vfio_ap 调解设备的控制域编号的只读文件。

    ap_config

    一个读/写文件,写入后,允许一次性替换 vfio_ap 调解设备的所有三个 ap 矩阵掩码。 给出三个掩码,一个用于适配器,一个用于域,一个用于控制域。 如果给定的状态无法设置,则不会对 vfio-ap 调解设备进行任何更改。

    写入 ap_config 的数据的格式如下:{amask},{dmask},{cmask}n

    n 是一个换行符。

    amask、dmask 和 cmask 是标识应分配给调解设备的适配器、域和控制域的掩码。

    掩码的格式如下:0xNN..NN

    其中 NN..NN 是表示 256 位值的 64 个十六进制字符。 最左侧(最高有效)的位表示适配器/域 0。

    对于表示您的 mdev 当前配置的掩码示例集,只需 cat ap_config。

    设置大于系统允许的最大值的适配器或域编号将导致错误。

    此属性旨在供自动化使用。 最终用户最好使用适配器、域和控制域的相应分配/取消分配属性。

  • 函数

    create

    分配 vfio_ap 驱动程序使用的 ap_matrix_mdev 结构

    • 存储对使用 mdev 的访客的 KVM 结构的引用

    • 存储通过相应的 sysfs 属性文件分配的适配器、域和控制域的 AP 矩阵配置

    • 存储访客可用的适配器、域和控制域的 AP 矩阵配置。 可能不会向访客提供访问引用不存在或未绑定到 vfio_ap 设备驱动程序的队列设备的 APQN 的权限。

    remove

    取消分配 vfio_ap 调解设备的 ap_matrix_mdev 结构。 仅当运行的访客未使用 mdev 时,才允许这样做。

  • 回调接口

    open_device

    vfio_ap 驱动程序使用此回调为矩阵 mdev 设备注册 VFIO_GROUP_NOTIFY_SET_KVM 通知程序回调函数。 用户空间调用 open_device 回调以将矩阵 mdev 设备的 VFIO iommu 组连接到 MDEV 总线。 通过此回调提供对用于配置 KVM 访客的 KVM 结构的访问。 KVM 结构用于配置访客对通过 vfio_ap 调解设备的 sysfs 属性文件定义的 AP 矩阵的访问。

    close_device

    取消注册矩阵 mdev 设备的 VFIO_GROUP_NOTIFY_SET_KVM 通知程序回调函数,并取消配置访客的 AP 矩阵。

    ioctl

    此回调处理 vfio 框架定义的 VFIO_DEVICE_GET_INFO 和 VFIO_DEVICE_RESET ioctl。

配置访客的 AP 资源

当调用 VFIO_GROUP_NOTIFY_SET_KVM 通知程序回调时,将执行 KVM 访客的 AP 资源配置。 当用户空间连接到 KVM 时,将调用通知程序函数。 访客的 AP 资源通过其 APCB 进行配置

  • 设置 APM 中与通过其“assign_adapter”接口分配给 vfio_ap 调解设备的 APID 对应的位。

  • 设置 AQM 中与通过其“assign_domain”接口分配给 vfio_ap 调解设备的域对应的位。

  • 设置 ADM 中与通过其“assign_control_domains”接口分配给 vfio_ap 调解设备的域 dID 对应的位。

Linux 设备模型排除了将未绑定到促进其直通的设备驱动程序的设备直通到 KVM 访客。 因此,不会将不引用绑定到 vfio_ap 设备驱动程序的队列设备的 APQN 分配给 KVM 访客的矩阵。 但是,AP 架构不提供从访客矩阵中过滤单个 APQN 的方法,因此将首先过滤通过其 sysfs“assign_adapter”、“assign_domain”和“assign_control_domain”接口分配给 vfio_ap 调解设备的适配器、域和控制域,然后再向访客提供 AP 配置

  • 将过滤未分配给主机 AP 配置的分配给矩阵 mdev 的适配器的 APID、域的 APQI 和控制域的域编号。

  • 将检查从分配给 vfio_ap mdev 的 APID 和 APQI 的笛卡尔积导出的每个 APQN,如果其中任何一个不引用绑定到 vfio_ap 设备驱动程序的队列设备,则不会将适配器插入到访客中(即,与其 APID 对应的位不会设置在访客的 APCB 中)。

AP 的 CPU 模型功能

AP 堆栈依赖于 AP 指令的存在以及三个功能:AP 功能测试 (APFT) 功能;AP 查询配置信息 (QCI) 功能;和 AP 队列中断控制功能。 这些特性/功能通过以下 CPU 模型功能提供给 KVM 访客

  1. ap:指示 AP 指令是否安装在访客上。 仅当 AP 指令安装在主机上时,KVM 才会启用此功能。

  2. apft:指示 APFT 功能在访客上可用。 仅当主机上可用时(即,设置了功能位 15),才能将此功能提供给访客。

  3. apqci:指示 AP QCI 功能在访客上可用。 仅当主机上可用时(即,设置了功能位 12),才能将此功能提供给访客。

  4. apqi:指示 AP 队列中断控制功能在访客上可用。 仅当主机上可用时(即,设置了功能位 65),才能将此功能提供给访客。

注意:如果用户选择指定与 QEMU 的“主机”模型不同的 CPU 模型,则需要显式启用 CPU 模型功能和功能;例如

/usr/bin/qemu-system-s390x ... -cpu z13,ap=on,apqci=on,apft=on,apqi=on

可以通过显式关闭 AP 特性/功能来阻止访客使用它们;例如

/usr/bin/qemu-system-s390x ... -cpu host,ap=off,apqci=off,apft=off,apqi=off

注意:如果为访客关闭了 APFT 功能 (apft=off),则访客将看不到任何 AP 设备。 在访客上注册类型 10 及更高版本 AP 设备(即,cex4card 和 cex4queue 设备驱动程序)的 zcrypt 设备驱动程序需要 APFT 功能来确定安装在给定 AP 设备上的功能。 如果访客上未安装 APFT 功能,则在访客上运行的 AP 总线将不会创建任何适配器或域设备,因为只能为访客使用配置类型 10 及更高版本的设备。

示例

现在让我们提供一个示例来说明如何向 KVM 访客授予对 AP 功能的访问权限。 对于此示例,我们将展示如何配置三个访客,以便在访客上执行 lszcrypt 命令将如下所示

访客 1

CARD.DOMAIN

TYPE

MODE

05

CEX5C

CCA-Coproc

05.0004

CEX5C

CCA-Coproc

05.00ab

CEX5C

CCA-Coproc

06

CEX5A

Accelerator

06.0004

CEX5A

Accelerator

06.00ab

CEX5A

Accelerator

访客 2

CARD.DOMAIN

TYPE

MODE

05

CEX5C

CCA-Coproc

05.0047

CEX5C

CCA-Coproc

05.00ff

CEX5C

CCA-Coproc

访客 3

CARD.DOMAIN

TYPE

MODE

06

CEX5A

Accelerator

06.0047

CEX5A

Accelerator

06.00ff

CEX5A

Accelerator

这些步骤是

  1. 在 Linux 主机上安装 vfio_ap 模块。 vfio_ap 模块的依赖关系链是:* iommu * s390 * zcrypt * vfio * vfio_mdev * vfio_mdev_device * KVM

    要构建 vfio_ap 模块,必须使用选定的以下 Kconfig 元素配置内核构建:* IOMMU_SUPPORT * S390 * AP * VFIO * KVM

    如果使用 make menuconfig,请选择以下选项来构建 vfio_ap 模块

    -> Device Drivers
       -> IOMMU Hardware Support
          select S390 AP IOMMU Support
       -> VFIO Non-Privileged userspace driver framework
          -> Mediated device driver frramework
             -> VFIO driver for Mediated devices
    -> I/O subsystem
       -> VFIO support for AP devices
    
  2. 保护将由三个访客使用的 AP 队列,以便主机无法访问它们。 为了保护它们,有两个 sysfs 文件指定位掩码,将 APQN 范围的子集标记为仅可由默认 AP 队列设备驱动程序使用。 所有剩余 APQN 可供任何其他设备驱动程序使用。 vfio_ap 设备驱动程序当前是唯一的非默认设备驱动程序。 包含掩码的 sysfs 文件的位置是

    /sys/bus/ap/apmask
    /sys/bus/ap/aqmask
    

    “apmask”是一个 256 位掩码,用于标识一组 AP 适配器 ID (APID)。 掩码中的每个位(从左到右)对应于一个从 0-255 的 APID。 如果设置了一个位,则 APID 属于标记为仅可用于默认 AP 队列设备驱动程序的 APQN 子集。

    “aqmask”是一个 256 位掩码,用于标识一组 AP 队列索引 (APQI)。 掩码中的每个位(从左到右)对应于一个从 0-255 的 APQI。 如果设置了一个位,则 APQI 属于标记为仅可用于默认 AP 队列设备驱动程序的 APQN 子集。

    APID 的笛卡尔积(对应于 apmask 中设置的位)和 APQI 的笛卡尔积(对应于 aqmask 中设置的位)构成了仅可由主机默认设备驱动程序使用的 APQN 子集。 所有其他 APQN 都可供非默认设备驱动程序(如 vfio_ap 驱动程序)使用。

    例如,以下掩码

    apmask:
    0x7d00000000000000000000000000000000000000000000000000000000000000
    
    aqmask:
    0x8000000000000000000000000000000000000000000000000000000000000000
    

    掩码指示

    • 适配器 1、2、3、4、5 和 7 可供主机默认设备驱动程序使用。

    • 域 0 可供主机默认设备驱动程序使用

    • 仅可供默认主机设备驱动程序使用的 APQN 子集是

      (1,0)、(2,0)、(3,0)、(4.0)、(5,0) 和 (7,0)

    • 所有其他 APQN 都可供非默认设备驱动程序使用。

    分配给 Linux 主机的每个 AP 队列设备的 APQN 都由 AP 总线根据从 APID 和 APQI 的笛卡尔积导出的 APQN 集进行检查,APID 和 APQI 标记为可用于默认 AP 队列设备驱动程序。 如果检测到匹配项,将仅探测默认 AP 队列设备驱动程序;否则,将探测 vfio_ap 设备驱动程序。

    默认情况下,这两个掩码设置为保留所有 APQN 供默认 AP 队列设备驱动程序使用。 有两种方法可以更改默认掩码

    1. 可以通过在两个格式之一中将字符串回显到相应的 sysfs 掩码文件中来编辑 sysfs 掩码文件

      • 以 0x 开头的绝对十六进制字符串(例如“0x12345678”)会设置掩码。如果给定的字符串短于掩码,则会在右侧填充 0;例如,指定掩码值 0x41 与指定

        0x4100000000000000000000000000000000000000000000000000000000000000
        

        请记住,掩码从左到右读取,因此上面的掩码标识设备编号 1 和 7 (01000001)。

        如果字符串长于掩码,则操作将以错误 (EINVAL) 终止。

      • 掩码中的各个位可以通过在逗号分隔的列表中指定要切换的每个位号来打开和关闭。每个位号字符串必须以(‘+’)或减号(‘-’)开头,以指示要打开(‘+’)或关闭(‘-’)相应的位。一些有效值是

        • “+0”打开位 0

        • “-13”关闭位 13

        • “+0x41”打开位 65

        • “-0xff”关闭位 255

        以下示例

        +0,-6,+0x47,-0xf0

        打开位 0 和 71 (0x47)

        关闭位 6 和 240 (0xf0)

        请注意,列表中未指定的位保持操作前的状态。

    2. 也可以通过内核命令行上的参数在启动时更改掩码,如下所示

      ap.apmask=0xffff ap.aqmask=0x40

      这将创建以下掩码

      apmask:
      0xffff000000000000000000000000000000000000000000000000000000000000
      
      aqmask:
      0x4000000000000000000000000000000000000000000000000000000000000000
      

      从而产生以下两个池

      default drivers pool:    adapter 0-15, domain 1
      alternate drivers pool:  adapter 16-255, domains 0, 2-255
      

    注意: 更改掩码,以便从 vfio_ap 介导的设备(见下文)获取一个或多个 APQN 将失败并显示错误 (EBUSY)。消息会记录到内核环形缓冲区,可以使用“dmesg”命令查看。输出标识每个标记为“在使用中”的 APQN,并标识分配给它的 vfio_ap 介导的设备;例如

    用户空间可能无法重新分配已分配给 62177883-f1bb-47f0-914d-32a22e3a8804 的队列 05.0054 用户空间可能无法重新分配已分配给 cef03c3c-903d-4ecc-9a83-40694cb8aee4 的队列 04.0054

保护我们示例的 APQN

为了保护 AP 队列 05.0004、05.0047、05.00ab、05.00ff、06.0004、06.0047、06.00ab 和 06.00ff 以供 vfio_ap 设备驱动程序使用,可以使用以下任一命令从默认掩码中删除相应的 APQN

echo -5,-6 > /sys/bus/ap/apmask

echo -4,-0x47,-0xab,-0xff > /sys/bus/ap/aqmask

或者可以如下设置掩码

echo 0xf9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \
> apmask

echo 0xf7fffffffffffffffeffffffffffffffffffffffffeffffffffffffffffffffe \
> aqmask

这将导致 AP 队列 05.0004、05.0047、05.00ab、05.00ff、06.0004、06.0047、06.00ab 和 06.00ff 绑定到 vfio_ap 设备驱动程序。vfio_ap 设备驱动程序的 sysfs 目录现在将包含指向绑定到它的 AP 队列设备的符号链接

/sys/bus/ap
... [drivers]
...... [vfio_ap]
......... [05.0004]
......... [05.0047]
......... [05.00ab]
......... [05.00ff]
......... [06.0004]
......... [06.0047]
......... [06.00ab]
......... [06.00ff]

请记住,只有 10 型及更高版本的适配器(即 CEX4 及更高版本)才能绑定到 vfio_ap 设备驱动程序。这样做的原因是通过不支持将在不久的将来停止使用的较旧设备来简化实现,从而不必要地使设计复杂化,并且用于测试的旧系统也很少。

因此,管理员必须注意仅保护可以绑定到 vfio_ap 设备驱动程序的 AP 队列。给定 AP 队列设备的设备类型可以从父卡的 sysfs 目录中读取。例如,要查看队列 05.0004 的硬件类型

cat /sys/bus/ap/devices/card05/hwtype

hwtype 必须为 10 或更高(CEX4 或更新版本)才能绑定到 vfio_ap 设备驱动程序。

  1. 创建配置三个客户机的 AP 矩阵所需的介导设备,并提供一个接口供客户机使用 vfio_ap 驱动程序

    /sys/devices/vfio_ap/matrix/
    --- [mdev_supported_types]
    ------ [vfio_ap-passthrough] (passthrough vfio_ap mediated device type)
    --------- create
    --------- [devices]
    

    要为三个客户机创建介导设备

    uuidgen > create
    uuidgen > create
    uuidgen > create
    
    or
    
    echo $uuid1 > create
    echo $uuid2 > create
    echo $uuid3 > create
    

    这将在 [devices] 子目录中创建三个介导设备,其名称与写入 create 属性文件的 UUID 相同。我们称它们为 $uuid1、$uuid2 和 $uuid3,这是创建后的 sysfs 目录结构

    /sys/devices/vfio_ap/matrix/
    --- [mdev_supported_types]
    ------ [vfio_ap-passthrough]
    --------- [devices]
    ------------ [$uuid1]
    --------------- assign_adapter
    --------------- assign_control_domain
    --------------- assign_domain
    --------------- matrix
    --------------- unassign_adapter
    --------------- unassign_control_domain
    --------------- unassign_domain
    
    ------------ [$uuid2]
    --------------- assign_adapter
    --------------- assign_control_domain
    --------------- assign_domain
    --------------- matrix
    --------------- unassign_adapter
    ----------------unassign_control_domain
    ----------------unassign_domain
    
    ------------ [$uuid3]
    --------------- assign_adapter
    --------------- assign_control_domain
    --------------- assign_domain
    --------------- matrix
    --------------- unassign_adapter
    ----------------unassign_control_domain
    ----------------unassign_domain
    
    注意 *:除非使用

    mdevctl 工具创建并持久化,否则 vfio_ap mdev 在重新启动后不会持久存在。

  2. 管理员现在需要为介导设备 $uuid1(对于 Guest1)、$uuid2(对于 Guest2)和 $uuid3(对于 Guest3)配置矩阵。

    这是 Guest1 的矩阵配置方式

    echo 5 > assign_adapter
    echo 6 > assign_adapter
    echo 4 > assign_domain
    echo 0xab > assign_domain
    

    可以使用 assign_control_domain sysfs 文件以类似的方式分配控制域。

    如果在配置适配器、域或控制域时出错,可以使用 unassign_xxx 文件取消分配适配器、域或控制域。

    要显示 Guest1 的矩阵配置

    cat matrix
    

    要显示分配给 Guest1 或将分配给 Guest1 的矩阵

    cat guest_matrix
    

    这是 Guest2 的矩阵配置方式

    echo 5 > assign_adapter
    echo 0x47 > assign_domain
    echo 0xff > assign_domain
    

    这是 Guest3 的矩阵配置方式

    echo 6 > assign_adapter
    echo 0x47 > assign_domain
    echo 0xff > assign_domain
    

    为了成功分配适配器

    • 指定的适配器编号必须表示一个值,从 0 到为系统配置的最大适配器编号。如果指定的适配器编号高于最大值,则操作将以错误 (ENODEV) 终止。

      注意:可以通过 sysfs

      /sys/bus/ap/ap_max_adapter_id 属性文件获取最大适配器编号。

    • 每个 APQN 都来自已分配适配器的 APID 和先前分配域的 APQI 的笛卡尔积

      • 必须仅对 vfio_ap 设备驱动程序可用,如 sysfs /sys/bus/ap/apmask 和 /sys/bus/ap/aqmask 属性文件中所指定。如果甚至有一个 APQN 保留供主机设备驱动程序使用,则操作将以错误 (EADDRNOTAVAIL) 终止。

      • 不得分配给另一个 vfio_ap 介导的设备。如果甚至有一个 APQN 分配给另一个 vfio_ap 介导的设备,则操作将以错误 (EBUSY) 终止。

      • 在编辑 sysfs /sys/bus/ap/apmask 和 sys/bus/ap/aqmask 属性文件时,不得进行分配,否则操作可能会以错误 (EBUSY) 终止。

    为了成功分配域

    • 指定的域编号必须表示一个值,从 0 到为系统配置的最大域编号。如果指定的域编号高于最大值,则操作将以错误 (ENODEV) 终止。

      注意:可以通过 sysfs

      /sys/bus/ap/ap_max_domain_id 属性文件获取最大域编号。

    • 每个 APQN 都来自已分配域的 APQI 和先前分配适配器的 APID 的笛卡尔积

    • 必须仅对 vfio_ap 设备驱动程序可用,如 sysfs /sys/bus/ap/apmask 和 /sys/bus/ap/aqmask 属性文件中所指定。如果甚至有一个 APQN 保留供主机设备驱动程序使用,则操作将以错误 (EADDRNOTAVAIL) 终止。

    • 不得分配给另一个 vfio_ap 介导的设备。如果甚至有一个 APQN 分配给另一个 vfio_ap 介导的设备,则操作将以错误 (EBUSY) 终止。

    • 在编辑 sysfs /sys/bus/ap/apmask 和 sys/bus/ap/aqmask 属性文件时,不得进行分配,否则操作可能会以错误 (EBUSY) 终止。

    为了成功分配控制域

    • 指定的域编号必须表示一个值,从 0 到为系统配置的最大域编号。如果指定的控制域编号高于最大值,则操作将以错误 (ENODEV) 终止。

  3. 启动 Guest1

    /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \
       -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid1 ...
    
  1. 启动 Guest2

    /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \
       -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid2 ...
    
  1. 启动 Guest3

    /usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \
       -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid3 ...
    

关闭客户机时,可以删除 vfio_ap 介导的设备。

再次使用我们的示例,删除 vfio_ap 介导的设备 $uuid1

/sys/devices/vfio_ap/matrix/
   --- [mdev_supported_types]
   ------ [vfio_ap-passthrough]
   --------- [devices]
   ------------ [$uuid1]
   --------------- remove
echo 1 > remove

这将删除所有矩阵 mdev 设备的 sysfs 结构,包括 mdev 设备本身。要重新创建和重新配置矩阵 mdev 设备,必须再次执行从步骤 3 开始的所有步骤。请注意,如果使用 vfio_ap mdev 的客户机仍在运行,则删除将失败。

不必删除 vfio_ap mdev,但如果 Linux 主机在剩余的生命周期内没有客户机使用它,则可能需要删除它。如果删除了 vfio_ap mdev,则可能还需要重新配置为默认驱动程序保留的适配器和队列池。

热插拔/拔出支持:

如果满足以下条件,可以将适配器、域或控制域热插拔到正在运行的 KVM 客户机中,方法是将其分配给客户机正在使用的 vfio_ap 介导的设备

  • 适配器、域或控制域也必须分配给主机的 AP 配置。

  • 来自包括已分配适配器的 APID 和已分配域的 APQI 的笛卡尔积的每个 APQN 必须引用绑定到 vfio_ap 设备驱动程序的队列设备。

  • 要热插拔域,来自包括已分配域的 APQI 和已分配适配器的 APID 的笛卡尔积的每个 APQN 必须引用绑定到 vfio_ap 设备驱动程序的队列设备。

可以通过从客户机正在使用的 vfio_ap 介导的设备取消分配适配器、域或控制域来从正在运行的 KVM 客户机中热拔出适配器、域或控制域。

为 KVM 客户机过度配置 AP 队列:

本文中,过度配置定义为将不引用主机 AP 配置中的 AP 设备的适配器或域分配给 vfio_ap 介导的设备。这里的想法是,当适配器或域可用时,它将使用已分配给它的 vfio_ap 介导的设备自动热插拔到 KVM 客户机中,只要插入后产生的每个新 APQN 都引用绑定到 vfio_ap 设备驱动程序的队列设备。

驱动程序功能

vfio_ap 驱动程序公开一个包含受支持功能的 sysfs 文件。这样做的目的是为了第三方工具(如 Libvirt 和 mdevctl)可以查询特定功能的可用性。

可以在这里找到功能列表:/sys/bus/matrix/devices/matrix/features

条目以空格分隔。每个条目由字母数字和下划线字符的组合组成。

示例:cat /sys/bus/matrix/devices/matrix/features guest_matrix dyn ap_config

公告了以下功能

---------------+---------------------------------------------------------------+ | 标志 | 描述 | +==============+===============================================================+ | guest_matrix | guest_matrix 属性存在。它报告适配器和域的矩阵, | | | 当 mdev 连接到客户机时,适配器和域的矩阵将被传递给客户机。 | +--------------+---------------------------------------------------------------+ | dyn | 指示 AP 适配器、域和控制的热插拔/拔出 | | | 附加 mdev 的客户机的域。 | +------------+-----------------------------------------------------------------+ | ap_config | 用于对 mdev 配置进行一次性修改的 ap_config 接口 | +--------------+---------------------------------------------------------------+

限制

对于使用 AP 设备的客户机,不支持实时客户机迁移,除非系统管理员进行干预。在可以迁移 KVM 客户机之前,必须删除 vfio_ap 介导的设备。不幸的是,在 KVM 客户机正在使用 mdev 时,无法手动删除它(即,echo 1 > /sys/devices/vfio_ap/matrix/$UUID/remove)。如果客户机由 QEMU 模拟,则可以通过以下两种方式之一从客户机中热拔出其 mdev

  1. 如果 KVM 客户机是使用 libvirt 启动的,则可以通过以下命令热拔出 mdev

    virsh detach-device <guestname> <path-to-device-xml>

    例如,要从名为“my-guest”的客户机中热拔出 mdev 62177883-f1bb-47f0-914d-32a22e3a8804

    virsh detach-device my-guest ~/config/my-guest-hostdev.xml

    my-guest-hostdev.xml 的内容

      <hostdev mode='subsystem' type='mdev' managed='no' model='vfio-ap'>
        <source>
          <address uuid='62177883-f1bb-47f0-914d-32a22e3a8804'/>
        </source>
      </hostdev>


virsh qemu-monitor-command <guest-name> --hmp "device-del <device-id>"

For example, to hot unplug the vfio_ap mediated device identified on the
qemu command line with 'id=hostdev0' from the guest named 'my-guest':
virsh qemu-monitor-command my-guest --hmp "device_del hostdev0"
  1. 可以通过将 qemu 监视器附加到客户机并使用以下 qemu 监视器命令来热拔出 vfio_ap 介导的设备

    (QEMU) device-del id=<device-id>

    例如,要热拔出在 qemu 命令行上以“id=hostdev0”指定的 vfio_ap 介导的设备(在启动客户机时)

    (QEMU) device-del id=hostdev0

在 KVM 客户机完成实时迁移后,可以通过以下两种方式之一将 AP 配置还原到目标系统上的 KVM 客户机中,方法是将 vfio_ap 介导的设备热插拔到客户机中

  1. 如果 KVM 客户机是使用 libvirt 启动的,则可以通过以下 virsh 命令将矩阵介导的设备热插拔到客户机中

    virsh attach-device <guestname> <path-to-device-xml>

    例如,要将 mdev 62177883-f1bb-47f0-914d-32a22e3a8804 热插拔到名为“my-guest”的客户机中

    virsh attach-device my-guest ~/config/my-guest-hostdev.xml

    my-guest-hostdev.xml 的内容

         <hostdev mode='subsystem' type='mdev' managed='no' model='vfio-ap'>
           <source>
             <address uuid='62177883-f1bb-47f0-914d-32a22e3a8804'/>
           </source>
         </hostdev>


virsh qemu-monitor-command <guest-name> --hmp \
"device_add vfio-ap,sysfsdev=<path-to-mdev>,id=<device-id>"

   For example, to hot plug the vfio_ap mediated device
   62177883-f1bb-47f0-914d-32a22e3a8804 into the guest named 'my-guest' with
   device-id hostdev0:

   virsh qemu-monitor-command my-guest --hmp \
   "device_add vfio-ap,\
   sysfsdev=/sys/devices/vfio_ap/matrix/62177883-f1bb-47f0-914d-32a22e3a8804,\
   id=hostdev0"
  1. 可以通过将 qemu 监视器附加到客户机并使用以下 qemu 监视器命令来热插拔 vfio_ap 介导的设备

    (qemu) device_add “vfio-ap,sysfsdev=<path-to-mdev>,id=<device-id>”

    例如,要将 vfio_ap 介导的设备 62177883-f1bb-47f0-914d-32a22e3a8804 插入到设备 ID hostdev0 的客户机中

    (QEMU) device-add “vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/62177883-f1bb-47f0-914d-32a22e3a8804,id=hostdev0”