aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorThomas Huth <thuth@linux.vnet.ibm.com>2014-01-15 10:46:07 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-05-06 08:58:10 -0400
commitf14d82e06a008b8977b64866a4907d2e152af939 (patch)
treecff2c7389cb1afd202a49f1a3be476e5ad9c12cb /arch/s390
parente029ae5b787e08e976a683c6a45fac20fc227447 (diff)
KVM: s390: Fix external interrupt interception
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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/kvm/intercept.c49
2 files changed, 49 insertions, 5 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index f0a1dc5e5d1f..96b8a67ddaf8 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -132,7 +132,10 @@ struct kvm_s390_sie_block {
132 psw_t gpsw; /* 0x0090 */ 132 psw_t gpsw; /* 0x0090 */
133 __u64 gg14; /* 0x00a0 */ 133 __u64 gg14; /* 0x00a0 */
134 __u64 gg15; /* 0x00a8 */ 134 __u64 gg15; /* 0x00a8 */
135 __u8 reservedb0[28]; /* 0x00b0 */ 135 __u8 reservedb0[20]; /* 0x00b0 */
136 __u16 extcpuaddr; /* 0x00c4 */
137 __u16 eic; /* 0x00c6 */
138 __u32 reservedc8; /* 0x00c8 */
136 __u16 pgmilc; /* 0x00cc */ 139 __u16 pgmilc; /* 0x00cc */
137 __u16 iprcc; /* 0x00ce */ 140 __u16 iprcc; /* 0x00ce */
138 __u32 dxc; /* 0x00d0 */ 141 __u32 dxc; /* 0x00d0 */
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 99e4b76e3487..bd607cf01a5d 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -17,6 +17,7 @@
17 17
18#include <asm/kvm_host.h> 18#include <asm/kvm_host.h>
19#include <asm/asm-offsets.h> 19#include <asm/asm-offsets.h>
20#include <asm/irq.h>
20 21
21#include "kvm-s390.h" 22#include "kvm-s390.h"
22#include "gaccess.h" 23#include "gaccess.h"
@@ -46,9 +47,6 @@ static int handle_noop(struct kvm_vcpu *vcpu)
46 case 0x10: 47 case 0x10:
47 vcpu->stat.exit_external_request++; 48 vcpu->stat.exit_external_request++;
48 break; 49 break;
49 case 0x14:
50 vcpu->stat.exit_external_interrupt++;
51 break;
52 default: 50 default:
53 break; /* nothing */ 51 break; /* nothing */
54 } 52 }
@@ -234,6 +232,49 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu)
234} 232}
235 233
236/** 234/**
235 * handle_external_interrupt - used for external interruption interceptions
236 *
237 * This interception only occurs if the CPUSTAT_EXT_INT bit was set, or if
238 * the new PSW does not have external interrupts disabled. In the first case,
239 * we've got to deliver the interrupt manually, and in the second case, we
240 * drop to userspace to handle the situation there.
241 */
242static int handle_external_interrupt(struct kvm_vcpu *vcpu)
243{
244 u16 eic = vcpu->arch.sie_block->eic;
245 struct kvm_s390_interrupt irq;
246 psw_t newpsw;
247 int rc;
248
249 vcpu->stat.exit_external_interrupt++;
250
251 rc = read_guest_lc(vcpu, __LC_EXT_NEW_PSW, &newpsw, sizeof(psw_t));
252 if (rc)
253 return rc;
254 /* We can not handle clock comparator or timer interrupt with bad PSW */
255 if ((eic == EXT_IRQ_CLK_COMP || eic == EXT_IRQ_CPU_TIMER) &&
256 (newpsw.mask & PSW_MASK_EXT))
257 return -EOPNOTSUPP;
258
259 switch (eic) {
260 case EXT_IRQ_CLK_COMP:
261 irq.type = KVM_S390_INT_CLOCK_COMP;
262 break;
263 case EXT_IRQ_CPU_TIMER:
264 irq.type = KVM_S390_INT_CPU_TIMER;
265 break;
266 case EXT_IRQ_EXTERNAL_CALL:
267 irq.type = KVM_S390_INT_EXTERNAL_CALL;
268 irq.parm = vcpu->arch.sie_block->extcpuaddr;
269 break;
270 default:
271 return -EOPNOTSUPP;
272 }
273
274 return kvm_s390_inject_vcpu(vcpu, &irq);
275}
276
277/**
237 * Handle MOVE PAGE partial execution interception. 278 * Handle MOVE PAGE partial execution interception.
238 * 279 *
239 * This interception can only happen for guests with DAT disabled and 280 * This interception can only happen for guests with DAT disabled and
@@ -291,7 +332,7 @@ static const intercept_handler_t intercept_funcs[] = {
291 [0x08 >> 2] = handle_prog, 332 [0x08 >> 2] = handle_prog,
292 [0x0C >> 2] = handle_instruction_and_prog, 333 [0x0C >> 2] = handle_instruction_and_prog,
293 [0x10 >> 2] = handle_noop, 334 [0x10 >> 2] = handle_noop,
294 [0x14 >> 2] = handle_noop, 335 [0x14 >> 2] = handle_external_interrupt,
295 [0x18 >> 2] = handle_noop, 336 [0x18 >> 2] = handle_noop,
296 [0x1C >> 2] = kvm_s390_handle_wait, 337 [0x1C >> 2] = kvm_s390_handle_wait,
297 [0x20 >> 2] = handle_validity, 338 [0x20 >> 2] = handle_validity,