aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/vfio_ap_ops.c
diff options
context:
space:
mode:
authorTony Krowiak <akrowiak@linux.ibm.com>2021-11-04 16:41:37 -0400
committerVasily Gorbik <gor@linux.ibm.com>2022-02-06 23:31:29 +0100
commit68f554b7d250b632d5fa17063f84c618c48b32a8 (patch)
treed4829e366585d7cbd54bf0f1eab93e48faf05d92 /drivers/s390/crypto/vfio_ap_ops.c
parentMAINTAINERS: update file path for S390 VFIO AP DRIVER (diff)
downloadlinux-dev-68f554b7d250b632d5fa17063f84c618c48b32a8.tar.xz
linux-dev-68f554b7d250b632d5fa17063f84c618c48b32a8.zip
s390/vfio-ap: add s390dbf logging to the handle_pqap function
This patch adds s390dbf logging to the function that handles interception of the PQAP(AQIC) instruction. Several items of data are validated before ultimately calling the functions that execute the PQAP(AQIC) instruction on behalf of the guest to which the queue for which interrupts are being enabled or disabled is attached. Currently, the handle_pqap function sets status response code 01 (queue not available) in the status word that is normally returned from the PQAP(AQIC) instruction under the following conditions: * Set when the function pointer to the handler is not set in the kvm_s390_crypto object (i.e., the PQAP hook is not registered). * Set when the KVM pointer is not set in the ap_matrix_mdev object (i.e., the matrix mdev is not passed through to a guest). * Set when the queue for which interrupts are being enabled or disabled is either not bound to the vfio_ap device driver or not assigned to the matrix mdev. Setting the response code returned to userspace without also logging a message in the kernel makes it impossible to determine whether the response was due to an error detected by the vfio_ap device driver or because the response code was returned by the firmware in response to the PQAP(AQIC) instruction, so this patch logs a message to the s390dbf log for the vfio_ap device driver for each of the situations described above. Signed-off-by: Tony Krowiak <akrowiak@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to '')
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c74
1 files changed, 68 insertions, 6 deletions
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index abc0b9b88386..537d7dd158a7 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -16,10 +16,12 @@
#include <linux/bitops.h>
#include <linux/kvm_host.h>
#include <linux/module.h>
+#include <linux/uuid.h>
#include <asm/kvm.h>
#include <asm/zcrypt.h>
#include "vfio_ap_private.h"
+#include "vfio_ap_debug.h"
#define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
#define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
@@ -257,6 +259,48 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
}
/**
+ * vfio_ap_le_guid_to_be_uuid - convert a little endian guid array into an array
+ * of big endian elements that can be passed by
+ * value to an s390dbf sprintf event function to
+ * format a UUID string.
+ *
+ * @guid: the object containing the little endian guid
+ * @uuid: a six-element array of long values that can be passed by value as
+ * arguments for a formatting string specifying a UUID.
+ *
+ * The S390 Debug Feature (s390dbf) allows the use of "%s" in the sprintf
+ * event functions if the memory for the passed string is available as long as
+ * the debug feature exists. Since a mediated device can be removed at any
+ * time, it's name can not be used because %s passes the reference to the string
+ * in memory and the reference will go stale once the device is removed .
+ *
+ * The s390dbf string formatting function allows a maximum of 9 arguments for a
+ * message to be displayed in the 'sprintf' view. In order to use the bytes
+ * comprising the mediated device's UUID to display the mediated device name,
+ * they will have to be converted into an array whose elements can be passed by
+ * value to sprintf. For example:
+ *
+ * guid array: { 83, 78, 17, 62, bb, f1, f0, 47, 91, 4d, 32, a2, 2e, 3a, 88, 04 }
+ * mdev name: 62177883-f1bb-47f0-914d-32a22e3a8804
+ * array returned: { 62177883, f1bb, 47f0, 914d, 32a2, 2e3a8804 }
+ * formatting string: "%08lx-%04lx-%04lx-%04lx-%02lx%04lx"
+ */
+static void vfio_ap_le_guid_to_be_uuid(guid_t *guid, unsigned long *uuid)
+{
+ /*
+ * The input guid is ordered in little endian, so it needs to be
+ * reordered for displaying a UUID as a string. This specifies the
+ * guid indices in proper order.
+ */
+ uuid[0] = le32_to_cpup((__le32 *)guid);
+ uuid[1] = le16_to_cpup((__le16 *)&guid->b[4]);
+ uuid[2] = le16_to_cpup((__le16 *)&guid->b[6]);
+ uuid[3] = *((__u16 *)&guid->b[8]);
+ uuid[4] = *((__u16 *)&guid->b[10]);
+ uuid[5] = *((__u32 *)&guid->b[12]);
+}
+
+/**
* handle_pqap - PQAP instruction callback
*
* @vcpu: The vcpu on which we received the PQAP instruction
@@ -281,30 +325,48 @@ static int handle_pqap(struct kvm_vcpu *vcpu)
{
uint64_t status;
uint16_t apqn;
+ unsigned long uuid[6];
struct vfio_ap_queue *q;
struct ap_queue_status qstatus = {
.response_code = AP_RESPONSE_Q_NOT_AVAIL, };
struct ap_matrix_mdev *matrix_mdev;
+ apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
+
/* If we do not use the AIV facility just go to userland */
- if (!(vcpu->arch.sie_block->eca & ECA_AIV))
+ if (!(vcpu->arch.sie_block->eca & ECA_AIV)) {
+ VFIO_AP_DBF_WARN("%s: AIV facility not installed: apqn=0x%04x, eca=0x%04x\n",
+ __func__, apqn, vcpu->arch.sie_block->eca);
+
return -EOPNOTSUPP;
+ }
- apqn = vcpu->run->s.regs.gprs[0] & 0xffff;
mutex_lock(&matrix_dev->lock);
-
- if (!vcpu->kvm->arch.crypto.pqap_hook)
+ if (!vcpu->kvm->arch.crypto.pqap_hook) {
+ VFIO_AP_DBF_WARN("%s: PQAP(AQIC) hook not registered with the vfio_ap driver: apqn=0x%04x\n",
+ __func__, apqn);
goto out_unlock;
+ }
+
matrix_mdev = container_of(vcpu->kvm->arch.crypto.pqap_hook,
struct ap_matrix_mdev, pqap_hook);
/* If the there is no guest using the mdev, there is nothing to do */
- if (!matrix_mdev->kvm)
+ if (!matrix_mdev->kvm) {
+ vfio_ap_le_guid_to_be_uuid(&matrix_mdev->mdev->uuid, uuid);
+ VFIO_AP_DBF_WARN("%s: mdev %08lx-%04lx-%04lx-%04lx-%04lx%08lx not in use: apqn=0x%04x\n",
+ __func__, uuid[0], uuid[1], uuid[2],
+ uuid[3], uuid[4], uuid[5], apqn);
goto out_unlock;
+ }
q = vfio_ap_get_queue(matrix_mdev, apqn);
- if (!q)
+ if (!q) {
+ VFIO_AP_DBF_WARN("%s: Queue %02x.%04x not bound to the vfio_ap driver\n",
+ __func__, AP_QID_CARD(apqn),
+ AP_QID_QUEUE(apqn));
goto out_unlock;
+ }
status = vcpu->run->s.regs.gprs[1];