2019-05-21 15:37:27

by Pierre Morel

[permalink] [raw]
Subject: [PATCH v9 0/4] vfio: ap: AP Queue Interrupt Control

This patch series implements PQAP/AQIC interception in KVM.

1) Data to handle GISA interrupt for AQIC

To implement this we need to add a new structure, vfio_ap_queue,
to be able to retrieve the mediated device associated with a queue
and specific values needed to register/unregister the interrupt
structures:
- APQN: to be able to issue the commands and search for queue
structures
- saved NIB : to keep track of the pin page for unpining it
- saved ISC : to unregister with the GIB interface
- matrix_mdev: to retrieve the associate matrix, the mediated device
and KVM

Specific handling bei keeping old values when re-registering is
needed because the guest could unregister interrupt in a invisble
manner bei issuing an un-interceptible RESET command.

Reset commands issued directly by the guest and indirectly when
removing the guest unpin the memory and deregister the ISC.

The vfio_ap_queue is associated to the ap_device during the probe
of the device and dissociated during the remove of the ap_device.

The vfio_ap_queue is associated to the matrix mediated device during
each interception of the AQIC command, so it does not need to be
dissociated until the guest is terminated.

The life of the vfio_ap_queue will be protected by the matrix_dev lock
to guaranty that no change can occur to the CRYCB or that devices can
not be removed when a vfio_ap_queue is in use.

2) KVM destroy race conditions

To make sure that KVM do not vanish and GISA is still available
when the VFIO_AP driver is in used we take a reference to KVM
during the opening of the mediated device and release it on
releasing the mediated device.

3) Interception of PQAP

The driver registers a hook structure to KVM providing:
- a pointer to a function implementing PQAP(AQIC) handling
- the reference to the module owner of the hook

On interception by KVM we do not change the behavior, returning
-EOPNOTSUPP to the user in the case AP instructions are not
supported by the host or by the guest.
Otherwise we verify the exceptions cases before trying to call
the vfio_ap hook.

In the case we do not find a hook we assume that the CRYCB has not
been setup for the guest and is empty.

4) Enabling and disabling the IRQ

When enabling the IRQ care is taken to unping the saved NIB.
When disabling IRQ care is taken to wait until the IRQ bit
of the queue status is cleared before unpining the NIB.

On RESET and before unpinning the NIB and unregistering the ISC
the IRQ is disabled using PQAP/AQIC even when a PQAP/APZQ have
been done.

5) Removing the AP device

Removing the AP device without having unassign it is clearly
discourage by the documentation.
The patch series does not check if the queue is used by a
guest. It only de-register the IRQ, unregister ISC and unpin
the NIB, then free the vfio_ap_queue.

6) Associated QEMU patch

There is a QEMU patch which is needed to enable the PQAP/AQIC
facility in the guest.

Posted in [email protected] as:
Message-Id: <[email protected]>

7) Compatibility with Dynamic configuration patches

Tony, I did not rebase this series above the dynamic configuration
patches because:
- This series do the work it needs to do without having to take
care on the dynamic configuration.
- It is guarantied that interrupt will be shut off after removing
the APQueue device
- The dynamic configuration series is not converging.

However Tony, the choice is your's, I won't be able to help
in a near future.


Pierre Morel (4):
s390: ap: kvm: add PQAP interception for AQIC
vfio: ap: register IOMMU VFIO notifier
s390: ap: implement PAPQ AQIC interception in kernel
s390: ap: kvm: Enable PQAP/AQIC facility for the guest

arch/s390/include/asm/kvm_host.h | 7 +
arch/s390/kvm/priv.c | 86 ++++++++
arch/s390/tools/gen_facilities.c | 1 +
drivers/s390/crypto/vfio_ap_drv.c | 34 ++-
drivers/s390/crypto/vfio_ap_ops.c | 379 +++++++++++++++++++++++++++++++++-
drivers/s390/crypto/vfio_ap_private.h | 15 ++
6 files changed, 514 insertions(+), 8 deletions(-)

--
2.7.4

Changelog:

Changelog from v8:
- mask the reserved bits when testing the FC in pqap interception
(Tony)

Changelog from v7:
- Modification of the IRQ disable routine to call ap_aqic
even a ap_zapq has been done
(to answer a question from Christian)
- use GISA origin instead of gisa next_alert field to
initialize ap_aqic register 2
(Halil)
- Corection of the testing of the vfio_pin_pages return value.
(Halil)
- Only keep track of saved_isc and saved_pfn for a later
interrupt disabling.
(Halil)
- renaming the routine to enable/disable the interruptions

Changelog from v6:
- Not taking care if the AP queue is associated with a guest
admin is warn in the odcumentation
(Tony, Halil)
- Using WARN_ON_ONCE, direct call to report specification errors
(Christian)
- Wait until the IRQ bit is cleared when clearing interrupts
(Tony, Halil)
- Some minor changes and add some comments before
vfio_ap_free_irq_data
(Pierre)
- initializing the pointer to matrix_mdev in vfio_ap_queue
during the interception and suppress the association during
assignment and the usage of lists.
(Tony, Halil)
- Merging patches for creation of vfio_ap_queue, initialization
and use of vfio_ap_queue during interception of PQAP/AQIC
(Conny)

Changelog from v5:
- Refactoring of the PQAP interception after all discussions
(Conny, Halil (offline))
- take a big lock around open to avoid parallel changes through
assignment
- verify that at least one queue has a APID or APQI when
first assignment is done to not accept unavailable APID/APQI
(myself)
- Adding comment for locks on free_list
(Conny)
- Modified comment for
"s390: ap: setup relation betwen KVM and mediated device"
(Halil)

Changelog from v4:
- Add forgotten locking for vfio_get_queue() in pqap callback
(Conny / Halil)
- Add KVM reference counting to make sure GISA is free after IRQ
(Christian / Halil)
- Take care that ISC = 0 is a valid ISC
(Halil)
- Integrate the PQAP call back in a structure with module owner
reference counting to make sure the callback does not disappear.
- Restrict functionality to always open KVM before opening the
VFIO device.
- Search all devices in the vfio_ap driver list when associating
a queue to a mediated device
(Halil / Tony)
- Get vfio_ap_free_irq() out of vfio_ap_mdev_reset_queue() to call
it always, whatever the result of the reset.
(Tony)

Changelog from v3:
- Associating the vfio_queues during APID/APQI assign
(Tony)
- Dissociating the vfio_queues during APID/APQI unassign
(Tony)
- Taking care that the guest can directly disable the interrupt
by using a RESET
(Halil)
- Remove the patch creating the matrix bus to accelerate its
integration in Linux stable
(Christian)

Changelog from v1:
- Refactoring to handle interception in kernel instead of in
QEMU
(Halil)



2019-05-21 15:38:20

by Pierre Morel

[permalink] [raw]
Subject: [PATCH v9 1/4] s390: ap: kvm: add PQAP interception for AQIC

We prepare the interception of the PQAP/AQIC instruction for
the case the AQIC facility is enabled in the guest.

First of all we do not want to change existing behavior when
intercepting AP instructions without the SIE allowing the guest
to use AP instructions.

In this patch we only handle the AQIC interception allowed by
facility 65 which will be enabled when the complete interception
infrastructure will be present.

We add a callback inside the KVM arch structure for s390 for
a VFIO driver to handle a specific response to the PQAP
instruction with the AQIC command and only this command.

But we want to be able to return a correct answer to the guest
even there is no VFIO AP driver in the kernel.
Therefor, we inject the correct exceptions from inside KVM for the
case the callback is not initialized, which happens when the vfio_ap
driver is not loaded.

We do consider the responsability of the driver to always initialize
the PQAP callback if it defines queues by initializing the CRYCB for
a guest.
If the callback has been setup we call it.
If not we setup an answer considering that no queue is available
for the guest when no callback has been setup.

Signed-off-by: Pierre Morel <[email protected]>
Reviewed-by: Tony Krowiak <[email protected]>
---
arch/s390/include/asm/kvm_host.h | 7 +++
arch/s390/kvm/priv.c | 86 +++++++++++++++++++++++++++++++++++
drivers/s390/crypto/vfio_ap_private.h | 2 +
3 files changed, 95 insertions(+)

diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index faa7ebf..a0fc2f1 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -18,6 +18,7 @@
#include <linux/kvm_host.h>
#include <linux/kvm.h>
#include <linux/seqlock.h>
+#include <linux/module.h>
#include <asm/debug.h>
#include <asm/cpu.h>
#include <asm/fpu/api.h>
@@ -723,8 +724,14 @@ struct kvm_s390_cpu_model {
unsigned short ibc;
};

+struct kvm_s390_module_hook {
+ int (*hook)(struct kvm_vcpu *vcpu);
+ struct module *owner;
+};
+
struct kvm_s390_crypto {
struct kvm_s390_crypto_cb *crycb;
+ struct kvm_s390_module_hook *pqap_hook;
__u32 crycbd;
__u8 aes_kw;
__u8 dea_kw;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 8679bd7..ed52ffa 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -27,6 +27,7 @@
#include <asm/io.h>
#include <asm/ptrace.h>
#include <asm/sclp.h>
+#include <asm/ap.h>
#include "gaccess.h"
#include "kvm-s390.h"
#include "trace.h"
@@ -592,6 +593,89 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
}
}

+/*
+ * handle_pqap: Handling pqap interception
+ * @vcpu: the vcpu having issue the pqap instruction
+ *
+ * We now support PQAP/AQIC instructions and we need to correctly
+ * answer the guest even if no dedicated driver's hook is available.
+ *
+ * The intercepting code calls a dedicated callback for this instruction
+ * if a driver did register one in the CRYPTO satellite of the
+ * SIE block.
+ *
+ * If no callback is available, the queues are not available, return this
+ * response code to the caller and set CC to 3.
+ * Else return the response code returned by the callback.
+ */
+static int handle_pqap(struct kvm_vcpu *vcpu)
+{
+ struct ap_queue_status status = {};
+ unsigned long reg0;
+ int ret;
+ uint8_t fc;
+
+ /* Verify that the AP instruction are available */
+ if (!ap_instructions_available())
+ return -EOPNOTSUPP;
+ /* Verify that the guest is allowed to use AP instructions */
+ if (!(vcpu->arch.sie_block->eca & ECA_APIE))
+ return -EOPNOTSUPP;
+ /*
+ * The only possibly intercepted functions when AP instructions are
+ * available for the guest are AQIC and TAPQ with the t bit set
+ * since we do not set IC.3 (FIII) we currently will only intercept
+ * the AQIC function code.
+ */
+ reg0 = vcpu->run->s.regs.gprs[0];
+ fc = (reg0 >> 24) & 0xff;
+ if (WARN_ON_ONCE(fc != 0x03))
+ return -EOPNOTSUPP;
+
+ /* PQAP instruction is allowed for guest kernel only */
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ /* Common PQAP instruction specification exceptions */
+ /* bits 41-47 must all be zeros */
+ if (reg0 & 0x007f0000UL)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ /* APFT not install and T bit set */
+ if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL))
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ /* APXA not installed and APID greater 64 or APQI greater 16 */
+ if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL))
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* AQIC function code specific exception */
+ /* facility 65 not present for AQIC function code */
+ if (!test_kvm_facility(vcpu->kvm, 65))
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /*
+ * Verify that the hook callback is registered, lock the owner
+ * and call the hook.
+ */
+ if (vcpu->kvm->arch.crypto.pqap_hook) {
+ if (!try_module_get(vcpu->kvm->arch.crypto.pqap_hook->owner))
+ return -EOPNOTSUPP;
+ ret = vcpu->kvm->arch.crypto.pqap_hook->hook(vcpu);
+ module_put(vcpu->kvm->arch.crypto.pqap_hook->owner);
+ if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000)
+ kvm_s390_set_psw_cc(vcpu, 3);
+ return ret;
+ }
+ /*
+ * A vfio_driver must register a hook.
+ * No hook means no driver to enable the SIE CRYCB and no queues.
+ * We send this response to the guest.
+ */
+ status.response_code = 0x01;
+ memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status));
+ kvm_s390_set_psw_cc(vcpu, 3);
+ return 0;
+}
+
static int handle_stfl(struct kvm_vcpu *vcpu)
{
int rc;
@@ -878,6 +962,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
return handle_sthyi(vcpu);
case 0x7d:
return handle_stsi(vcpu);
+ case 0xaf:
+ return handle_pqap(vcpu);
case 0xb1:
return handle_stfl(vcpu);
case 0xb2:
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index 76b7f98..a910be1 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -16,6 +16,7 @@
#include <linux/mdev.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/kvm_host.h>

#include "ap_bus.h"

@@ -81,6 +82,7 @@ struct ap_matrix_mdev {
struct ap_matrix matrix;
struct notifier_block group_notifier;
struct kvm *kvm;
+ struct kvm_s390_module_hook pqap_hook;
};

extern int vfio_ap_mdev_register(void);
--
2.7.4


2019-05-23 15:38:56

by Anthony Krowiak

[permalink] [raw]
Subject: Re: [PATCH v9 0/4] vfio: ap: AP Queue Interrupt Control

On 5/21/19 11:34 AM, Pierre Morel wrote:
> This patch series implements PQAP/AQIC interception in KVM.
>
> 1) Data to handle GISA interrupt for AQIC
>
> To implement this we need to add a new structure, vfio_ap_queue,
> to be able to retrieve the mediated device associated with a queue
> and specific values needed to register/unregister the interrupt
> structures:
> - APQN: to be able to issue the commands and search for queue
> structures
> - saved NIB : to keep track of the pin page for unpining it
> - saved ISC : to unregister with the GIB interface
> - matrix_mdev: to retrieve the associate matrix, the mediated device
> and KVM
>
> Specific handling bei keeping old values when re-registering is
> needed because the guest could unregister interrupt in a invisble
> manner bei issuing an un-interceptible RESET command.
>
> Reset commands issued directly by the guest and indirectly when
> removing the guest unpin the memory and deregister the ISC.
>
> The vfio_ap_queue is associated to the ap_device during the probe
> of the device and dissociated during the remove of the ap_device.
>
> The vfio_ap_queue is associated to the matrix mediated device during
> each interception of the AQIC command, so it does not need to be
> dissociated until the guest is terminated.
>
> The life of the vfio_ap_queue will be protected by the matrix_dev lock
> to guaranty that no change can occur to the CRYCB or that devices can
> not be removed when a vfio_ap_queue is in use.
>
> 2) KVM destroy race conditions
>
> To make sure that KVM do not vanish and GISA is still available
> when the VFIO_AP driver is in used we take a reference to KVM
> during the opening of the mediated device and release it on
> releasing the mediated device.
>
> 3) Interception of PQAP
>
> The driver registers a hook structure to KVM providing:
> - a pointer to a function implementing PQAP(AQIC) handling
> - the reference to the module owner of the hook
>
> On interception by KVM we do not change the behavior, returning
> -EOPNOTSUPP to the user in the case AP instructions are not
> supported by the host or by the guest.
> Otherwise we verify the exceptions cases before trying to call
> the vfio_ap hook.
>
> In the case we do not find a hook we assume that the CRYCB has not
> been setup for the guest and is empty.
>
> 4) Enabling and disabling the IRQ
>
> When enabling the IRQ care is taken to unping the saved NIB.
> When disabling IRQ care is taken to wait until the IRQ bit
> of the queue status is cleared before unpining the NIB.
>
> On RESET and before unpinning the NIB and unregistering the ISC
> the IRQ is disabled using PQAP/AQIC even when a PQAP/APZQ have
> been done.
>
> 5) Removing the AP device
>
> Removing the AP device without having unassign it is clearly
> discourage by the documentation.
> The patch series does not check if the queue is used by a
> guest. It only de-register the IRQ, unregister ISC and unpin
> the NIB, then free the vfio_ap_queue.
>
> 6) Associated QEMU patch
>
> There is a QEMU patch which is needed to enable the PQAP/AQIC
> facility in the guest.
>
> Posted in [email protected] as:
> Message-Id: <[email protected]>
>
> 7) Compatibility with Dynamic configuration patches
>
> Tony, I did not rebase this series above the dynamic configuration
> patches because:
> - This series do the work it needs to do without having to take
> care on the dynamic configuration.
> - It is guarantied that interrupt will be shut off after removing
> the APQueue device
> - The dynamic configuration series is not converging.

Would you consider the following?

* Take dynconfig patch "s390: vfio-ap: wait for queue empty on queue
reset" and include it in your series. This patch modifies the
reset function to wait for queue empty.

* In dynconfig patch "s390: vfio-ap: handle bind and unbind of AP queue
device" the following functions are introduced:

void vfio_ap_mdev_probe_queue(struct ap_queue *queue)
void vfio_ap_mdev_remove_queue(struct ap_queue *queue)

The vfio_ap_mdev_probe_queue function is called from the vfio_ap
driver probe callback. You could embed the code you've introduced in
the probe callback there. Of course, you would need to return int
from the function for the -ENOMEM error.

The vfio_ap_mdev_remove_queue function is called from the vfio_ap
driver remove callback. You could embed the code you've introduced in
the remove callback there.

* Move your vfio_ap_irq_disable function to vfio_ap_ops.c and make it a
static function.

* Leave the vfio_ap_mdev_reset_queue function as a static function in
vfio_ap_ops.c

If you do the things above, then I can base the dynconfig series on
the IRQ series without much of a merge issue. What say you?

Note: I've included review comments for patch 3/4 to match the
suggestions above.

>
> However Tony, the choice is your's, I won't be able to help
> in a near future.
>
>
> Pierre Morel (4):
> s390: ap: kvm: add PQAP interception for AQIC
> vfio: ap: register IOMMU VFIO notifier
> s390: ap: implement PAPQ AQIC interception in kernel
> s390: ap: kvm: Enable PQAP/AQIC facility for the guest
>
> arch/s390/include/asm/kvm_host.h | 7 +
> arch/s390/kvm/priv.c | 86 ++++++++
> arch/s390/tools/gen_facilities.c | 1 +
> drivers/s390/crypto/vfio_ap_drv.c | 34 ++-
> drivers/s390/crypto/vfio_ap_ops.c | 379 +++++++++++++++++++++++++++++++++-
> drivers/s390/crypto/vfio_ap_private.h | 15 ++
> 6 files changed, 514 insertions(+), 8 deletions(-)
>

2019-06-04 14:58:03

by Halil Pasic

[permalink] [raw]
Subject: Re: [PATCH v9 0/4] vfio: ap: AP Queue Interrupt Control

On Thu, 23 May 2019 11:36:12 -0400
Tony Krowiak <[email protected]> wrote:

> On 5/21/19 11:34 AM, Pierre Morel wrote:
> > This patch series implements PQAP/AQIC interception in KVM.
> >

[..]

> >
> > Tony, I did not rebase this series above the dynamic configuration
> > patches because:
> > - This series do the work it needs to do without having to take
> > care on the dynamic configuration.
> > - It is guarantied that interrupt will be shut off after removing
> > the APQueue device
> > - The dynamic configuration series is not converging.
>
> Would you consider the following?
>
> * Take dynconfig patch "s390: vfio-ap: wait for queue empty on queue

[..]

>
> If you do the things above, then I can base the dynconfig series on
> the IRQ series without much of a merge issue. What say you?
>
> Note: I've included review comments for patch 3/4 to match the
> suggestions above.
>
> >
> > However Tony, the choice is your's, I won't be able to help
> > in a near future.

Since Pierre won't available for a while, and the patches look good
enough to me, I would like to pick these if nobody objects.

Any objection?

@Tony: Could you please have another look at patch 3? That is the only
one you haven't r-b yet...

Regards,
Halil

2019-06-12 18:00:41

by Harald Freudenberger

[permalink] [raw]
Subject: Re: [PATCH v9 1/4] s390: ap: kvm: add PQAP interception for AQIC

On 21.05.19 17:34, Pierre Morel wrote:
> We prepare the interception of the PQAP/AQIC instruction for
> the case the AQIC facility is enabled in the guest.
>
> First of all we do not want to change existing behavior when
> intercepting AP instructions without the SIE allowing the guest
> to use AP instructions.
>
> In this patch we only handle the AQIC interception allowed by
> facility 65 which will be enabled when the complete interception
> infrastructure will be present.
>
> We add a callback inside the KVM arch structure for s390 for
> a VFIO driver to handle a specific response to the PQAP
> instruction with the AQIC command and only this command.
>
> But we want to be able to return a correct answer to the guest
> even there is no VFIO AP driver in the kernel.
> Therefor, we inject the correct exceptions from inside KVM for the
> case the callback is not initialized, which happens when the vfio_ap
> driver is not loaded.
>
> We do consider the responsability of the driver to always initialize
> the PQAP callback if it defines queues by initializing the CRYCB for
> a guest.
> If the callback has been setup we call it.
> If not we setup an answer considering that no queue is available
> for the guest when no callback has been setup.
>
> Signed-off-by: Pierre Morel <[email protected]>
> Reviewed-by: Tony Krowiak <[email protected]>
> ---
> arch/s390/include/asm/kvm_host.h | 7 +++
> arch/s390/kvm/priv.c | 86 +++++++++++++++++++++++++++++++++++
> drivers/s390/crypto/vfio_ap_private.h | 2 +
> 3 files changed, 95 insertions(+)
>
> diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
> index faa7ebf..a0fc2f1 100644
> --- a/arch/s390/include/asm/kvm_host.h
> +++ b/arch/s390/include/asm/kvm_host.h
> @@ -18,6 +18,7 @@
> #include <linux/kvm_host.h>
> #include <linux/kvm.h>
> #include <linux/seqlock.h>
> +#include <linux/module.h>
> #include <asm/debug.h>
> #include <asm/cpu.h>
> #include <asm/fpu/api.h>
> @@ -723,8 +724,14 @@ struct kvm_s390_cpu_model {
> unsigned short ibc;
> };
>
> +struct kvm_s390_module_hook {
> + int (*hook)(struct kvm_vcpu *vcpu);
> + struct module *owner;
> +};
> +
> struct kvm_s390_crypto {
> struct kvm_s390_crypto_cb *crycb;
> + struct kvm_s390_module_hook *pqap_hook;
> __u32 crycbd;
> __u8 aes_kw;
> __u8 dea_kw;
> diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
> index 8679bd7..ed52ffa 100644
> --- a/arch/s390/kvm/priv.c
> +++ b/arch/s390/kvm/priv.c
> @@ -27,6 +27,7 @@
> #include <asm/io.h>
> #include <asm/ptrace.h>
> #include <asm/sclp.h>
> +#include <asm/ap.h>
> #include "gaccess.h"
> #include "kvm-s390.h"
> #include "trace.h"
> @@ -592,6 +593,89 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
> }
> }
>
> +/*
> + * handle_pqap: Handling pqap interception
> + * @vcpu: the vcpu having issue the pqap instruction
> + *
> + * We now support PQAP/AQIC instructions and we need to correctly
> + * answer the guest even if no dedicated driver's hook is available.
> + *
> + * The intercepting code calls a dedicated callback for this instruction
> + * if a driver did register one in the CRYPTO satellite of the
> + * SIE block.
> + *
> + * If no callback is available, the queues are not available, return this
> + * response code to the caller and set CC to 3.
> + * Else return the response code returned by the callback.
> + */
> +static int handle_pqap(struct kvm_vcpu *vcpu)
> +{
> + struct ap_queue_status status = {};
> + unsigned long reg0;
> + int ret;
> + uint8_t fc;
> +
> + /* Verify that the AP instruction are available */
> + if (!ap_instructions_available())
> + return -EOPNOTSUPP;
> + /* Verify that the guest is allowed to use AP instructions */
> + if (!(vcpu->arch.sie_block->eca & ECA_APIE))
> + return -EOPNOTSUPP;
> + /*
> + * The only possibly intercepted functions when AP instructions are
> + * available for the guest are AQIC and TAPQ with the t bit set
> + * since we do not set IC.3 (FIII) we currently will only intercept
> + * the AQIC function code.
> + */
> + reg0 = vcpu->run->s.regs.gprs[0];
> + fc = (reg0 >> 24) & 0xff;
> + if (WARN_ON_ONCE(fc != 0x03))
> + return -EOPNOTSUPP;
> +
> + /* PQAP instruction is allowed for guest kernel only */
> + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
> + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
> +
> + /* Common PQAP instruction specification exceptions */
> + /* bits 41-47 must all be zeros */
> + if (reg0 & 0x007f0000UL)
> + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
> + /* APFT not install and T bit set */
> + if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL))
> + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
> + /* APXA not installed and APID greater 64 or APQI greater 16 */
> + if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL))
> + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
> +
> + /* AQIC function code specific exception */
> + /* facility 65 not present for AQIC function code */
> + if (!test_kvm_facility(vcpu->kvm, 65))
> + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
> +
> + /*
> + * Verify that the hook callback is registered, lock the owner
> + * and call the hook.
> + */
> + if (vcpu->kvm->arch.crypto.pqap_hook) {
> + if (!try_module_get(vcpu->kvm->arch.crypto.pqap_hook->owner))
> + return -EOPNOTSUPP;
> + ret = vcpu->kvm->arch.crypto.pqap_hook->hook(vcpu);
> + module_put(vcpu->kvm->arch.crypto.pqap_hook->owner);
> + if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000)
> + kvm_s390_set_psw_cc(vcpu, 3);
> + return ret;
> + }
> + /*
> + * A vfio_driver must register a hook.
> + * No hook means no driver to enable the SIE CRYCB and no queues.
> + * We send this response to the guest.
> + */
> + status.response_code = 0x01;
> + memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status));
> + kvm_s390_set_psw_cc(vcpu, 3);
> + return 0;
> +}
> +
> static int handle_stfl(struct kvm_vcpu *vcpu)
> {
> int rc;
> @@ -878,6 +962,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
> return handle_sthyi(vcpu);
> case 0x7d:
> return handle_stsi(vcpu);
> + case 0xaf:
> + return handle_pqap(vcpu);
> case 0xb1:
> return handle_stfl(vcpu);
> case 0xb2:
> diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
> index 76b7f98..a910be1 100644
> --- a/drivers/s390/crypto/vfio_ap_private.h
> +++ b/drivers/s390/crypto/vfio_ap_private.h
> @@ -16,6 +16,7 @@
> #include <linux/mdev.h>
> #include <linux/delay.h>
> #include <linux/mutex.h>
> +#include <linux/kvm_host.h>
>
> #include "ap_bus.h"
>
> @@ -81,6 +82,7 @@ struct ap_matrix_mdev {
> struct ap_matrix matrix;
> struct notifier_block group_notifier;
> struct kvm *kvm;
> + struct kvm_s390_module_hook pqap_hook;
> };
>
> extern int vfio_ap_mdev_register(void);
acked-by: Harald Freudenberger <[email protected]>

2019-07-01 12:42:01

by Halil Pasic

[permalink] [raw]
Subject: Re: [PATCH v9 0/4] vfio: ap: AP Queue Interrupt Control

On Tue, 21 May 2019 17:34:33 +0200
Pierre Morel <[email protected]> wrote:

> This patch series implements PQAP/AQIC interception in KVM.

Thanks, applied