aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-05-06 11:20:37 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-05-06 11:20:37 -0400
commit2ce316f0b9b2103e27585180b6aa6f17f0175f0e (patch)
treecebd0e69fec5c801e650d68fc226692cb4967969
parent1171903d899b1930f502b4c10a2a3565d6603c71 (diff)
parentf14d82e06a008b8977b64866a4907d2e152af939 (diff)
Merge tag 'kvm-s390-20140506' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into kvm-next
1. Fixes an error return code for the breakpoint setup 2. External interrupt fixes 2.1. Some interrupt conditions like cpu timer or clock comparator stay pending even after the interrupt is injected. If the external new PSW is enabled for interrupts this will result in an endless loop. Usually this indicates a programming error in the guest OS. Lets detect such situations and go to userspace. We will provide a QEMU patch that sets the guest in panicked/crashed state to avoid wasting CPU cycles. 2.2 Resend external interrupts back to the guest if the HW could not do it. -
-rw-r--r--Documentation/virtual/kvm/api.txt2
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/kvm/guestdbg.c5
-rw-r--r--arch/s390/kvm/intercept.c49
-rw-r--r--arch/s390/kvm/interrupt.c32
-rw-r--r--include/uapi/linux/kvm.h2
6 files changed, 88 insertions, 7 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 2014ff12b492..0581f6c40f2b 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2211,6 +2211,8 @@ KVM_S390_SIGP_STOP (vcpu) - sigp restart
2211KVM_S390_PROGRAM_INT (vcpu) - program check; code in parm 2211KVM_S390_PROGRAM_INT (vcpu) - program check; code in parm
2212KVM_S390_SIGP_SET_PREFIX (vcpu) - sigp set prefix; prefix address in parm 2212KVM_S390_SIGP_SET_PREFIX (vcpu) - sigp set prefix; prefix address in parm
2213KVM_S390_RESTART (vcpu) - restart 2213KVM_S390_RESTART (vcpu) - restart
2214KVM_S390_INT_CLOCK_COMP (vcpu) - clock comparator interrupt
2215KVM_S390_INT_CPU_TIMER (vcpu) - CPU timer interrupt
2214KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt 2216KVM_S390_INT_VIRTIO (vm) - virtio external interrupt; external interrupt
2215 parameters in parm and parm64 2217 parameters in parm and parm64
2216KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm 2218KVM_S390_INT_SERVICE (vm) - sclp external interrupt; sclp parameter in parm
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/guestdbg.c b/arch/s390/kvm/guestdbg.c
index 757ccef62fd5..3e8d4092ce30 100644
--- a/arch/s390/kvm/guestdbg.c
+++ b/arch/s390/kvm/guestdbg.c
@@ -223,9 +223,10 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu,
223 goto error; 223 goto error;
224 } 224 }
225 225
226 ret = copy_from_user(bp_data, dbg->arch.hw_bp, size); 226 if (copy_from_user(bp_data, dbg->arch.hw_bp, size)) {
227 if (ret) 227 ret = -EFAULT;
228 goto error; 228 goto error;
229 }
229 230
230 for (i = 0; i < dbg->arch.nr_hw_bp; i++) { 231 for (i = 0; i < dbg->arch.nr_hw_bp; i++) {
231 switch (bp_data[i].type) { 232 switch (bp_data[i].type) {
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,
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index d9526bb29194..75cd3217cd5a 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -27,6 +27,8 @@
27#define IOINT_CSSID_MASK 0x03fc0000 27#define IOINT_CSSID_MASK 0x03fc0000
28#define IOINT_AI_MASK 0x04000000 28#define IOINT_AI_MASK 0x04000000
29 29
30static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
31
30static int is_ioint(u64 type) 32static int is_ioint(u64 type)
31{ 33{
32 return ((type & 0xfffe0000u) != 0xfffe0000u); 34 return ((type & 0xfffe0000u) != 0xfffe0000u);
@@ -89,6 +91,14 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu,
89 if (vcpu->arch.sie_block->gcr[0] & 0x4000ul) 91 if (vcpu->arch.sie_block->gcr[0] & 0x4000ul)
90 return 1; 92 return 1;
91 return 0; 93 return 0;
94 case KVM_S390_INT_CLOCK_COMP:
95 return ckc_interrupts_enabled(vcpu);
96 case KVM_S390_INT_CPU_TIMER:
97 if (psw_extint_disabled(vcpu))
98 return 0;
99 if (vcpu->arch.sie_block->gcr[0] & 0x400ul)
100 return 1;
101 return 0;
92 case KVM_S390_INT_SERVICE: 102 case KVM_S390_INT_SERVICE:
93 case KVM_S390_INT_PFAULT_INIT: 103 case KVM_S390_INT_PFAULT_INIT:
94 case KVM_S390_INT_PFAULT_DONE: 104 case KVM_S390_INT_PFAULT_DONE:
@@ -166,6 +176,8 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu,
166 case KVM_S390_INT_PFAULT_INIT: 176 case KVM_S390_INT_PFAULT_INIT:
167 case KVM_S390_INT_PFAULT_DONE: 177 case KVM_S390_INT_PFAULT_DONE:
168 case KVM_S390_INT_VIRTIO: 178 case KVM_S390_INT_VIRTIO:
179 case KVM_S390_INT_CLOCK_COMP:
180 case KVM_S390_INT_CPU_TIMER:
169 if (psw_extint_disabled(vcpu)) 181 if (psw_extint_disabled(vcpu))
170 __set_cpuflag(vcpu, CPUSTAT_EXT_INT); 182 __set_cpuflag(vcpu, CPUSTAT_EXT_INT);
171 else 183 else
@@ -326,6 +338,24 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
326 &vcpu->arch.sie_block->gpsw, 338 &vcpu->arch.sie_block->gpsw,
327 sizeof(psw_t)); 339 sizeof(psw_t));
328 break; 340 break;
341 case KVM_S390_INT_CLOCK_COMP:
342 trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
343 inti->ext.ext_params, 0);
344 deliver_ckc_interrupt(vcpu);
345 break;
346 case KVM_S390_INT_CPU_TIMER:
347 trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
348 inti->ext.ext_params, 0);
349 rc = put_guest_lc(vcpu, EXT_IRQ_CPU_TIMER,
350 (u16 *)__LC_EXT_INT_CODE);
351 rc |= write_guest_lc(vcpu, __LC_EXT_OLD_PSW,
352 &vcpu->arch.sie_block->gpsw,
353 sizeof(psw_t));
354 rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
355 &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
356 rc |= put_guest_lc(vcpu, inti->ext.ext_params,
357 (u32 *)__LC_EXT_PARAMS);
358 break;
329 case KVM_S390_INT_SERVICE: 359 case KVM_S390_INT_SERVICE:
330 VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", 360 VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
331 inti->ext.ext_params); 361 inti->ext.ext_params);
@@ -984,6 +1014,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
984 break; 1014 break;
985 case KVM_S390_SIGP_STOP: 1015 case KVM_S390_SIGP_STOP:
986 case KVM_S390_RESTART: 1016 case KVM_S390_RESTART:
1017 case KVM_S390_INT_CLOCK_COMP:
1018 case KVM_S390_INT_CPU_TIMER:
987 VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); 1019 VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type);
988 inti->type = s390int->type; 1020 inti->type = s390int->type;
989 break; 1021 break;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 836e15b7abc8..2b83cf35437a 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -416,6 +416,8 @@ struct kvm_s390_psw {
416#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u 416#define KVM_S390_INT_PFAULT_INIT 0xfffe0004u
417#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u 417#define KVM_S390_INT_PFAULT_DONE 0xfffe0005u
418#define KVM_S390_MCHK 0xfffe1000u 418#define KVM_S390_MCHK 0xfffe1000u
419#define KVM_S390_INT_CLOCK_COMP 0xffff1004u
420#define KVM_S390_INT_CPU_TIMER 0xffff1005u
419#define KVM_S390_INT_VIRTIO 0xffff2603u 421#define KVM_S390_INT_VIRTIO 0xffff2603u
420#define KVM_S390_INT_SERVICE 0xffff2401u 422#define KVM_S390_INT_SERVICE 0xffff2401u
421#define KVM_S390_INT_EMERGENCY 0xffff1201u 423#define KVM_S390_INT_EMERGENCY 0xffff1201u