Skip to content

Commit

Permalink
KVM: s390: Fix external interrupt interception
Browse files Browse the repository at this point in the history
The external interrupt interception can only occur in rare cases, e.g.
when the PSW of the interrupt handler has a bad value. The old handler
for this interception simply ignored these events (except for increasing
the exit_external_interrupt counter), but for proper operation we either
have to inject the interrupts manually or we should drop to userspace in
case of errors.

Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
  • Loading branch information
Thomas Huth authored and Christian Borntraeger committed May 6, 2014
1 parent e029ae5 commit f14d82e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
5 changes: 4 additions & 1 deletion arch/s390/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ struct kvm_s390_sie_block {
psw_t gpsw; /* 0x0090 */
__u64 gg14; /* 0x00a0 */
__u64 gg15; /* 0x00a8 */
__u8 reservedb0[28]; /* 0x00b0 */
__u8 reservedb0[20]; /* 0x00b0 */
__u16 extcpuaddr; /* 0x00c4 */
__u16 eic; /* 0x00c6 */
__u32 reservedc8; /* 0x00c8 */
__u16 pgmilc; /* 0x00cc */
__u16 iprcc; /* 0x00ce */
__u32 dxc; /* 0x00d0 */
Expand Down
49 changes: 45 additions & 4 deletions arch/s390/kvm/intercept.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <asm/kvm_host.h>
#include <asm/asm-offsets.h>
#include <asm/irq.h>

#include "kvm-s390.h"
#include "gaccess.h"
Expand Down Expand Up @@ -46,9 +47,6 @@ static int handle_noop(struct kvm_vcpu *vcpu)
case 0x10:
vcpu->stat.exit_external_request++;
break;
case 0x14:
vcpu->stat.exit_external_interrupt++;
break;
default:
break; /* nothing */
}
Expand Down Expand Up @@ -233,6 +231,49 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
return rc2;
}

/**
* handle_external_interrupt - used for external interruption interceptions
*
* This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
* the new PSW does not have external interrupts disabled. In the first case,
* we've got to deliver the interrupt manually, and in the second case, we
* drop to userspace to handle the situation there.
*/
static int handle_external_interrupt(struct kvm_vcpu *vcpu)
{
u16 eic = vcpu->arch.sie_block->eic;
struct kvm_s390_interrupt irq;
psw_t newpsw;
int rc;

vcpu->stat.exit_external_interrupt++;

rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
if (rc)
return rc;
/* We can not handle clock comparator or timer interrupt with bad PSW */
if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
(newpsw.mask & PSW_MASK_EXT))
return -EOPNOTSUPP;

switch (eic) {
case EXT_IRQ_CLK_COMP:
irq.type = KVM_S390_INT_CLOCK_COMP;
break;
case EXT_IRQ_CPU_TIMER:
irq.type = KVM_S390_INT_CPU_TIMER;
break;
case EXT_IRQ_EXTERNAL_CALL:
irq.type = KVM_S390_INT_EXTERNAL_CALL;
irq.parm = vcpu->arch.sie_block->extcpuaddr;
break;
default:
return -EOPNOTSUPP;
}

return kvm_s390_inject_vcpu(vcpu, &irq);
}

/**
* Handle MOVE PAGE partial execution interception.
*
Expand Down Expand Up @@ -291,7 +332,7 @@ static const intercept_handler_t intercept_funcs[] = {
[0x08 >> 2] = handle_prog,
[0x0C >> 2] = handle_instruction_and_prog,
[0x10 >> 2] = handle_noop,
[0x14 >> 2] = handle_noop,
[0x14 >> 2] = handle_external_interrupt,
[0x18 >> 2] = handle_noop,
[0x1C >> 2] = kvm_s390_handle_wait,
[0x20 >> 2] = handle_validity,
Expand Down

0 comments on commit f14d82e

Please sign in to comment.