2022-02-05 02:16:45 +08:00
|
|
|
.. SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
======================
|
|
|
|
VFIO AP Locks Overview
|
|
|
|
======================
|
|
|
|
This document describes the locks that are pertinent to the secure operation
|
|
|
|
of the vfio_ap device driver. Throughout this document, the following variables
|
|
|
|
will be used to denote instances of the structures herein described:
|
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
struct ap_matrix_dev *matrix_dev;
|
|
|
|
struct ap_matrix_mdev *matrix_mdev;
|
|
|
|
struct kvm *kvm;
|
2022-02-05 02:16:45 +08:00
|
|
|
|
|
|
|
The Matrix Devices Lock (drivers/s390/crypto/vfio_ap_private.h)
|
2022-07-21 21:29:05 +08:00
|
|
|
---------------------------------------------------------------
|
|
|
|
|
|
|
|
.. code-block:: c
|
2022-02-05 02:16:45 +08:00
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
struct ap_matrix_dev {
|
|
|
|
...
|
|
|
|
struct list_head mdev_list;
|
|
|
|
struct mutex mdevs_lock;
|
|
|
|
...
|
|
|
|
}
|
2022-02-05 02:16:45 +08:00
|
|
|
|
|
|
|
The Matrix Devices Lock (matrix_dev->mdevs_lock) is implemented as a global
|
|
|
|
mutex contained within the single object of struct ap_matrix_dev. This lock
|
|
|
|
controls access to all fields contained within each matrix_mdev
|
|
|
|
(matrix_dev->mdev_list). This lock must be held while reading from, writing to
|
|
|
|
or using the data from a field contained within a matrix_mdev instance
|
|
|
|
representing one of the vfio_ap device driver's mediated devices.
|
|
|
|
|
|
|
|
The KVM Lock (include/linux/kvm_host.h)
|
|
|
|
---------------------------------------
|
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
struct kvm {
|
|
|
|
...
|
|
|
|
struct mutex lock;
|
|
|
|
...
|
|
|
|
}
|
2022-02-05 02:16:45 +08:00
|
|
|
|
|
|
|
The KVM Lock (kvm->lock) controls access to the state data for a KVM guest. This
|
|
|
|
lock must be held by the vfio_ap device driver while one or more AP adapters,
|
|
|
|
domains or control domains are being plugged into or unplugged from the guest.
|
|
|
|
|
|
|
|
The KVM pointer is stored in the in the matrix_mdev instance
|
|
|
|
(matrix_mdev->kvm = kvm) containing the state of the mediated device that has
|
|
|
|
been attached to the KVM guest.
|
|
|
|
|
|
|
|
The Guests Lock (drivers/s390/crypto/vfio_ap_private.h)
|
|
|
|
-----------------------------------------------------------
|
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
struct ap_matrix_dev {
|
|
|
|
...
|
|
|
|
struct list_head mdev_list;
|
|
|
|
struct mutex guests_lock;
|
|
|
|
...
|
|
|
|
}
|
2022-02-05 02:16:45 +08:00
|
|
|
|
|
|
|
The Guests Lock (matrix_dev->guests_lock) controls access to the
|
|
|
|
matrix_mdev instances (matrix_dev->mdev_list) that represent mediated devices
|
|
|
|
that hold the state for the mediated devices that have been attached to a
|
|
|
|
KVM guest. This lock must be held:
|
|
|
|
|
|
|
|
1. To control access to the KVM pointer (matrix_mdev->kvm) while the vfio_ap
|
|
|
|
device driver is using it to plug/unplug AP devices passed through to the KVM
|
|
|
|
guest.
|
|
|
|
|
|
|
|
2. To add matrix_mdev instances to or remove them from matrix_dev->mdev_list.
|
|
|
|
This is necessary to ensure the proper locking order when the list is perused
|
|
|
|
to find an ap_matrix_mdev instance for the purpose of plugging/unplugging
|
|
|
|
AP devices passed through to a KVM guest.
|
|
|
|
|
|
|
|
For example, when a queue device is removed from the vfio_ap device driver,
|
|
|
|
if the adapter is passed through to a KVM guest, it will have to be
|
|
|
|
unplugged. In order to figure out whether the adapter is passed through,
|
|
|
|
the matrix_mdev object to which the queue is assigned will have to be
|
|
|
|
found. The KVM pointer (matrix_mdev->kvm) can then be used to determine if
|
|
|
|
the mediated device is passed through (matrix_mdev->kvm != NULL) and if so,
|
|
|
|
to unplug the adapter.
|
|
|
|
|
|
|
|
It is not necessary to take the Guests Lock to access the KVM pointer if the
|
|
|
|
pointer is not used to plug/unplug devices passed through to the KVM guest;
|
|
|
|
however, in this case, the Matrix Devices Lock (matrix_dev->mdevs_lock) must be
|
|
|
|
held in order to access the KVM pointer since it is set and cleared under the
|
|
|
|
protection of the Matrix Devices Lock. A case in point is the function that
|
|
|
|
handles interception of the PQAP(AQIC) instruction sub-function. This handler
|
|
|
|
needs to access the KVM pointer only for the purposes of setting or clearing IRQ
|
|
|
|
resources, so only the matrix_dev->mdevs_lock needs to be held.
|
|
|
|
|
|
|
|
The PQAP Hook Lock (arch/s390/include/asm/kvm_host.h)
|
|
|
|
-----------------------------------------------------
|
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
typedef int (*crypto_hook)(struct kvm_vcpu *vcpu);
|
2022-02-05 02:16:45 +08:00
|
|
|
|
2022-07-21 21:29:05 +08:00
|
|
|
struct kvm_s390_crypto {
|
|
|
|
...
|
|
|
|
struct rw_semaphore pqap_hook_rwsem;
|
|
|
|
crypto_hook *pqap_hook;
|
|
|
|
...
|
|
|
|
};
|
2022-02-05 02:16:45 +08:00
|
|
|
|
|
|
|
The PQAP Hook Lock is a r/w semaphore that controls access to the function
|
2022-07-21 21:29:05 +08:00
|
|
|
pointer of the handler ``(*kvm->arch.crypto.pqap_hook)`` to invoke when the
|
2022-02-05 02:16:45 +08:00
|
|
|
PQAP(AQIC) instruction sub-function is intercepted by the host. The lock must be
|
|
|
|
held in write mode when pqap_hook value is set, and in read mode when the
|
|
|
|
pqap_hook function is called.
|