aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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