@@ -236,7 +236,7 @@ static int handle_prog(struct kvm_vcpu *vcpu)
* Intercept 8 indicates a loop of specification exceptions
* for protected guests.
*/
- if (kvm_s390_pv_is_protected(vcpu->kvm))
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
return -EOPNOTSUPP;
if (guestdbg_enabled(vcpu) && per_event(vcpu)) {
@@ -392,7 +392,7 @@ int handle_sthyi(struct kvm_vcpu *vcpu)
goto out;
}
- if (!kvm_s390_pv_is_protected(vcpu->kvm) && (addr & ~PAGE_MASK))
+ if (!kvm_s390_pv_cpu_is_protected(vcpu) && (addr & ~PAGE_MASK))
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
sctns = (void *)get_zeroed_page(GFP_KERNEL);
@@ -403,7 +403,7 @@ int handle_sthyi(struct kvm_vcpu *vcpu)
out:
if (!cc) {
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
memcpy((void *)(sida_origin(vcpu->arch.sie_block)),
sctns, PAGE_SIZE);
} else {
@@ -393,7 +393,7 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu)
if (psw_mchk_disabled(vcpu))
active_mask &= ~IRQ_PEND_MCHK_MASK;
/* PV guest cpus can have a single interruption injected at a time. */
- if (kvm_s390_pv_is_protected(vcpu->kvm) &&
+ if (kvm_s390_pv_cpu_is_protected(vcpu) &&
vcpu->arch.sie_block->iictl != IICTL_CODE_NONE)
active_mask &= ~(IRQ_PEND_EXT_II_MASK |
IRQ_PEND_IO_MASK |
@@ -495,7 +495,7 @@ static int __must_check __deliver_cpu_timer(struct kvm_vcpu *vcpu)
vcpu->stat.deliver_cputm++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CPU_TIMER,
0, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
vcpu->arch.sie_block->eic = EXT_IRQ_CPU_TIMER;
} else {
@@ -519,7 +519,7 @@ static int __must_check __deliver_ckc(struct kvm_vcpu *vcpu)
vcpu->stat.deliver_ckc++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_CLOCK_COMP,
0, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
vcpu->arch.sie_block->eic = EXT_IRQ_CLK_COMP;
} else {
@@ -578,7 +578,7 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
* the hypervisor does not not have the needed information for
* protected guests.
*/
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_MCHK;
vcpu->arch.sie_block->mcic = mchk->mcic;
vcpu->arch.sie_block->faddr = mchk->failing_storage_address;
@@ -735,7 +735,7 @@ static int __must_check __deliver_restart(struct kvm_vcpu *vcpu)
vcpu->stat.deliver_restart_signal++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_RESTART, 0, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_RESTART;
} else {
rc = write_guest_lc(vcpu,
@@ -785,7 +785,7 @@ static int __must_check __deliver_emergency_signal(struct kvm_vcpu *vcpu)
vcpu->stat.deliver_emergency_signal++;
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
cpu_addr, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
vcpu->arch.sie_block->eic = EXT_IRQ_EMERGENCY_SIG;
vcpu->arch.sie_block->extcpuaddr = cpu_addr;
@@ -819,7 +819,7 @@ static int __must_check __deliver_external_call(struct kvm_vcpu *vcpu)
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id,
KVM_S390_INT_EXTERNAL_CALL,
extcall.code, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_EXT;
vcpu->arch.sie_block->eic = EXT_IRQ_EXTERNAL_CALL;
vcpu->arch.sie_block->extcpuaddr = extcall.code;
@@ -871,7 +871,7 @@ static int __must_check __deliver_prog(struct kvm_vcpu *vcpu)
trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, KVM_S390_PROGRAM_INT,
pgm_info.code, 0);
- if (kvm_s390_pv_is_protected(vcpu->kvm))
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
return __deliver_prog_pv(vcpu, pgm_info.code & ~PGM_PER);
switch (pgm_info.code & ~PGM_PER) {
@@ -1010,7 +1010,7 @@ static int __must_check __deliver_service(struct kvm_vcpu *vcpu)
memset(&fi->srv_signal, 0, sizeof(ext));
clear_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
clear_bit(IRQ_PEND_EXT_SERVICE_EV, &fi->pending_irqs);
- if (kvm_s390_pv_is_protected(vcpu->kvm))
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
set_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
spin_unlock(&fi->lock);
@@ -1139,7 +1139,7 @@ static int __do_deliver_io(struct kvm_vcpu *vcpu, struct kvm_s390_io_info *io)
{
int rc;
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
vcpu->arch.sie_block->iictl = IICTL_CODE_IO;
vcpu->arch.sie_block->subchannel_id = io->subchannel_id;
vcpu->arch.sie_block->subchannel_nr = io->subchannel_nr;
@@ -1898,8 +1898,13 @@ static int __inject_io(struct kvm *kvm, struct kvm_s390_interrupt_info *inti)
kvm->stat.inject_io++;
isc = int_word_to_isc(inti->io.io_int_word);
- /* do not make use of gisa in protected mode */
- if (!kvm_s390_pv_is_protected(kvm) &&
+ /*
+ * Do not make use of gisa in protected mode. We do not use the lock
+ * checking variant as this is just a performance optimization and we
+ * do not hold the lock here. This is ok as the code will pick
+ * interrupts from both "lists" for delivery.
+ */
+ if (!kvm_s390_pv_handle(kvm) &&
gi->origin && inti->type & KVM_S390_INT_IO_AI_MASK) {
VM_EVENT(kvm, 4, "%s isc %1u", "inject: I/O (AI/gisa)", isc);
gisa_set_ipm_gisc(gi->origin, isc);
@@ -2208,10 +2213,12 @@ void kvm_s390_clear_float_irqs(struct kvm *kvm)
struct kvm_s390_float_interrupt *fi = &kvm->arch.float_int;
int i;
- spin_lock(&fi->lock);
- fi->pending_irqs = 0;
+ mutex_lock(&kvm->lock);
if (!kvm_s390_pv_is_protected(kvm))
fi->masked_irqs = 0;
+ mutex_unlock(&kvm->lock);
+ spin_lock(&fi->lock);
+ fi->pending_irqs = 0;
memset(&fi->srv_signal, 0, sizeof(fi->srv_signal));
memset(&fi->mchk, 0, sizeof(fi->mchk));
for (i = 0; i < FIRQ_LIST_COUNT; i++)
@@ -2194,7 +2194,6 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
break;
}
- mutex_lock(&kvm->lock);
kvm_s390_vcpu_block_all(kvm);
/* FMT 4 SIE needs esca */
r = sca_switch_to_extended(kvm);
@@ -2208,7 +2207,6 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
kvm_s390_vcpu_unblock_all(kvm);
/* we need to block service interrupts from now on */
set_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs);
- mutex_unlock(&kvm->lock);
break;
}
case KVM_PV_VM_DESTROY: {
@@ -2216,8 +2214,6 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
if (!kvm_s390_pv_is_protected(kvm))
break;
- /* All VCPUs have to be destroyed before this call. */
- mutex_lock(&kvm->lock);
kvm_s390_vcpu_block_all(kvm);
r = kvm_s390_pv_destroy_vm(kvm, &cmd->rc, &cmd->rrc);
if (!r)
@@ -2225,7 +2221,6 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd)
kvm_s390_vcpu_unblock_all(kvm);
/* no need to block service interrupts any more */
clear_bit(IRQ_PEND_EXT_SERVICE, &kvm->arch.float_int.masked_irqs);
- mutex_unlock(&kvm->lock);
break;
}
case KVM_PV_VM_SET_SEC_PARMS: {
@@ -2740,7 +2735,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_free_vcpus(kvm);
sca_dispose(kvm);
kvm_s390_gisa_destroy(kvm);
- if (kvm_s390_pv_is_protected(kvm)) {
+ /* do not use the lock checking variant at tear-down */
+ if (kvm_s390_pv_handle(kvm)) {
kvm_s390_pv_destroy_vm(kvm, &rc, &rrc);
kvm_s390_pv_dealloc_vm(kvm);
}
@@ -3162,8 +3158,10 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
kvm_s390_vcpu_crypto_setup(vcpu);
+ mutex_lock(&vcpu->kvm->lock);
if (kvm_s390_pv_is_protected(vcpu->kvm))
rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc);
+ mutex_unlock(&vcpu->kvm->lock);
return rc;
}
@@ -4053,14 +4051,14 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
guest_enter_irqoff();
__disable_cpu_timer_accounting(vcpu);
local_irq_enable();
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
memcpy(sie_page->pv_grregs,
vcpu->run->s.regs.gprs,
sizeof(sie_page->pv_grregs));
}
exit_reason = sie64a(vcpu->arch.sie_block,
vcpu->run->s.regs.gprs);
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
memcpy(vcpu->run->s.regs.gprs,
sie_page->pv_grregs,
sizeof(sie_page->pv_grregs));
@@ -4184,7 +4182,7 @@ static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
current->thread.fpu.fpc = 0;
/* Sync fmt2 only data */
- if (likely(!kvm_s390_pv_is_protected(vcpu->kvm))) {
+ if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) {
sync_regs_fmt2(vcpu, kvm_run);
} else {
/*
@@ -4244,7 +4242,7 @@ static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
/* Restore will be done lazily at return */
current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc;
current->thread.fpu.regs = vcpu->arch.host_fpregs.regs;
- if (likely(!kvm_s390_pv_is_protected(vcpu->kvm)))
+ if (likely(!kvm_s390_pv_cpu_is_protected(vcpu)))
store_regs_fmt2(vcpu, kvm_run);
}
@@ -4443,7 +4441,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
* ultravisor. We block all interrupts and let the next sie exit
* refresh our view.
*/
- if (kvm_s390_pv_is_protected(vcpu->kvm))
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
vcpu->arch.sie_block->gpsw.mask &= ~PSW_INT_MASK;
/*
* Another VCPU might have used IBS while we were offline.
@@ -4573,7 +4571,7 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu,
switch (mop->op) {
case KVM_S390_MEMOP_LOGICAL_READ:
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = -EINVAL;
break;
}
@@ -4589,7 +4587,7 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu,
}
break;
case KVM_S390_MEMOP_LOGICAL_WRITE:
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
r = -EINVAL;
break;
}
@@ -4655,7 +4653,7 @@ static int kvm_s390_handle_pv_vcpu(struct kvm_vcpu *vcpu,
{
int r = 0;
- if (!kvm_s390_pv_is_protected(vcpu->kvm))
+ if (!kvm_s390_pv_cpu_is_protected(vcpu))
return -EINVAL;
if (cmd->flags)
@@ -4751,7 +4749,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
case KVM_GET_ONE_REG: {
struct kvm_one_reg reg;
r = -EINVAL;
- if (kvm_s390_pv_is_protected(vcpu->kvm))
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
break;
r = -EFAULT;
if (copy_from_user(®, argp, sizeof(reg)))
@@ -15,6 +15,7 @@
#include <linux/hrtimer.h>
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <linux/lockdep.h>
#include <asm/facility.h>
#include <asm/processor.h>
#include <asm/sclp.h>
@@ -221,11 +222,6 @@ int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size,
int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state, u16 *rc,
u16 *rrc);
-static inline bool kvm_s390_pv_is_protected(struct kvm *kvm)
-{
- return !!kvm->arch.pv.handle;
-}
-
static inline u64 kvm_s390_pv_handle(struct kvm *kvm)
{
return kvm->arch.pv.handle;
@@ -236,6 +232,18 @@ static inline u64 kvm_s390_pv_handle_cpu(struct kvm_vcpu *vcpu)
return vcpu->arch.pv.handle;
}
+static inline bool kvm_s390_pv_is_protected(struct kvm *kvm)
+{
+ lockdep_assert_held(&kvm->lock);
+ return !!kvm_s390_pv_handle(kvm);
+}
+
+static inline bool kvm_s390_pv_cpu_is_protected(struct kvm_vcpu *vcpu)
+{
+ lockdep_assert_held(&vcpu->mutex);
+ return !!kvm_s390_pv_handle_cpu(vcpu);
+}
+
/* implemented in interrupt.c */
int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
@@ -872,7 +872,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
- if (!kvm_s390_pv_is_protected(vcpu->kvm) && (operand2 & 0xfff))
+ if (!kvm_s390_pv_cpu_is_protected(vcpu) && (operand2 & 0xfff))
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
switch (fc) {
@@ -893,7 +893,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
handle_stsi_3_2_2(vcpu, (void *) mem);
break;
}
- if (kvm_s390_pv_is_protected(vcpu->kvm)) {
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
memcpy((void *)sida_origin(vcpu->arch.sie_block), (void *)mem,
PAGE_SIZE);
rc = 0;
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> --- arch/s390/kvm/intercept.c | 6 +++--- arch/s390/kvm/interrupt.c | 35 +++++++++++++++++++++-------------- arch/s390/kvm/kvm-s390.c | 28 +++++++++++++--------------- arch/s390/kvm/kvm-s390.h | 18 +++++++++++++----- arch/s390/kvm/priv.c | 4 ++-- 5 files changed, 52 insertions(+), 39 deletions(-)