aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2014-02-21 02:59:59 -0500
committerChristian Borntraeger <borntraeger@de.ibm.com>2014-05-16 08:57:28 -0400
commit4953919feedaeb6d0161ecea920c35d1d1f639d3 (patch)
treef62ccaca28067e90562b6231f0e2dfac55f5a24b
parentd26b8655f088ac6e972fd8f016b8dfa7cc1b9e5a (diff)
KVM: s390: interpretive execution of SIGP EXTERNAL CALL
If the sigp interpretation facility is installed, most SIGP EXTERNAL CALL operations will be interpreted instead of intercepted. A partial execution interception will occurr at the sending cpu only if the target cpu is in the wait state ("W" bit in the cpuflags set). Instruction interception will only happen in error cases (e.g. cpu addr invalid). As a sending cpu might set the external call interrupt pending flags at the target cpu at every point in time, we can't handle this kind of interrupt using our kvm interrupt injection mechanism. The injection will be done automatically by the SIE when preparing the start of the target cpu. Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> CC: Thomas Huth <thuth@linux.vnet.ibm.com> [Adopt external call injection to check for sigp interpretion] Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h4
-rw-r--r--arch/s390/kvm/intercept.c4
-rw-r--r--arch/s390/kvm/interrupt.c30
-rw-r--r--arch/s390/kvm/kvm-s390.c2
-rw-r--r--arch/s390/kvm/kvm-s390.h2
-rw-r--r--arch/s390/kvm/sigp.c35
-rw-r--r--arch/s390/kvm/trace.h23
7 files changed, 94 insertions, 6 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 96b8a67ddaf8..dc182a5b02b7 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -32,8 +32,10 @@
32#define KVM_NR_IRQCHIPS 1 32#define KVM_NR_IRQCHIPS 1
33#define KVM_IRQCHIP_NUM_PINS 4096 33#define KVM_IRQCHIP_NUM_PINS 4096
34 34
35#define SIGP_CTRL_C 0x00800000
36
35struct sca_entry { 37struct sca_entry {
36 atomic_t scn; 38 atomic_t ctrl;
37 __u32 reserved; 39 __u32 reserved;
38 __u64 sda; 40 __u64 sda;
39 __u64 reserved2[2]; 41 __u64 reserved2[2];
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 147b87fefecd..a0b586c1913c 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -272,6 +272,8 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu)
272 irq.type = KVM_S390_INT_CPU_TIMER; 272 irq.type = KVM_S390_INT_CPU_TIMER;
273 break; 273 break;
274 case EXT_IRQ_EXTERNAL_CALL: 274 case EXT_IRQ_EXTERNAL_CALL:
275 if (kvm_s390_si_ext_call_pending(vcpu))
276 return 0;
275 irq.type = KVM_S390_INT_EXTERNAL_CALL; 277 irq.type = KVM_S390_INT_EXTERNAL_CALL;
276 irq.parm = vcpu->arch.sie_block->extcpuaddr; 278 irq.parm = vcpu->arch.sie_block->extcpuaddr;
277 break; 279 break;
@@ -323,6 +325,8 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
323{ 325{
324 if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */ 326 if (vcpu->arch.sie_block->ipa == 0xb254) /* MVPG */
325 return handle_mvpg_pei(vcpu); 327 return handle_mvpg_pei(vcpu);
328 if (vcpu->arch.sie_block->ipa >> 8 == 0xae) /* SIGP */
329 return kvm_s390_handle_sigp_pei(vcpu);
326 330
327 return -EOPNOTSUPP; 331 return -EOPNOTSUPP;
328} 332}
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 75cd3217cd5a..bf0d9bc15bcd 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -148,9 +148,8 @@ static void __unset_cpu_idle(struct kvm_vcpu *vcpu)
148 148
149static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) 149static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
150{ 150{
151 atomic_clear_mask(CPUSTAT_ECALL_PEND | 151 atomic_clear_mask(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT,
152 CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, 152 &vcpu->arch.sie_block->cpuflags);
153 &vcpu->arch.sie_block->cpuflags);
154 vcpu->arch.sie_block->lctl = 0x0000; 153 vcpu->arch.sie_block->lctl = 0x0000;
155 vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); 154 vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT);
156 155
@@ -524,6 +523,20 @@ static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
524 } 523 }
525} 524}
526 525
526/* Check whether SIGP interpretation facility has an external call pending */
527int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu)
528{
529 atomic_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl;
530
531 if (!psw_extint_disabled(vcpu) &&
532 (vcpu->arch.sie_block->gcr[0] & 0x2000ul) &&
533 (atomic_read(sigp_ctrl) & SIGP_CTRL_C) &&
534 (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
535 return 1;
536
537 return 0;
538}
539
527int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu) 540int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
528{ 541{
529 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int; 542 struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -554,6 +567,9 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
554 if (!rc && kvm_cpu_has_pending_timer(vcpu)) 567 if (!rc && kvm_cpu_has_pending_timer(vcpu))
555 rc = 1; 568 rc = 1;
556 569
570 if (!rc && kvm_s390_si_ext_call_pending(vcpu))
571 rc = 1;
572
557 return rc; 573 return rc;
558} 574}
559 575
@@ -610,7 +626,8 @@ no_timer:
610 while (list_empty(&vcpu->arch.local_int.list) && 626 while (list_empty(&vcpu->arch.local_int.list) &&
611 list_empty(&vcpu->arch.local_int.float_int->list) && 627 list_empty(&vcpu->arch.local_int.float_int->list) &&
612 (!vcpu->arch.local_int.timer_due) && 628 (!vcpu->arch.local_int.timer_due) &&
613 !signal_pending(current)) { 629 !signal_pending(current) &&
630 !kvm_s390_si_ext_call_pending(vcpu)) {
614 set_current_state(TASK_INTERRUPTIBLE); 631 set_current_state(TASK_INTERRUPTIBLE);
615 spin_unlock_bh(&vcpu->arch.local_int.lock); 632 spin_unlock_bh(&vcpu->arch.local_int.lock);
616 spin_unlock(&vcpu->arch.local_int.float_int->lock); 633 spin_unlock(&vcpu->arch.local_int.float_int->lock);
@@ -667,6 +684,11 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
667 } 684 }
668 atomic_set(&li->active, 0); 685 atomic_set(&li->active, 0);
669 spin_unlock_bh(&li->lock); 686 spin_unlock_bh(&li->lock);
687
688 /* clear pending external calls set by sigp interpretation facility */
689 atomic_clear_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
690 atomic_clear_mask(SIGP_CTRL_C,
691 &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl);
670} 692}
671 693
672void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) 694void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index d91feb2f03ea..2c243124a4e2 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -633,7 +633,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
633 vcpu->arch.sie_block->ecb |= 0x10; 633 vcpu->arch.sie_block->ecb |= 0x10;
634 634
635 vcpu->arch.sie_block->ecb2 = 8; 635 vcpu->arch.sie_block->ecb2 = 8;
636 vcpu->arch.sie_block->eca = 0xC1002000U; 636 vcpu->arch.sie_block->eca = 0xD1002000U;
637 if (sclp_has_siif()) 637 if (sclp_has_siif())
638 vcpu->arch.sie_block->eca |= 1; 638 vcpu->arch.sie_block->eca |= 1;
639 vcpu->arch.sie_block->fac = (int) (long) vfacilities; 639 vcpu->arch.sie_block->fac = (int) (long) vfacilities;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index e489945921ac..87edfc919db9 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -154,6 +154,7 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu);
154 154
155/* implemented in sigp.c */ 155/* implemented in sigp.c */
156int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); 156int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
157int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
157 158
158/* implemented in kvm-s390.c */ 159/* implemented in kvm-s390.c */
159long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable); 160long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
@@ -214,6 +215,7 @@ static inline int kvm_s390_inject_prog_cond(struct kvm_vcpu *vcpu, int rc)
214int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); 215int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
215int psw_extint_disabled(struct kvm_vcpu *vcpu); 216int psw_extint_disabled(struct kvm_vcpu *vcpu);
216void kvm_s390_destroy_adapters(struct kvm *kvm); 217void kvm_s390_destroy_adapters(struct kvm *kvm);
218int kvm_s390_si_ext_call_pending(struct kvm_vcpu *vcpu);
217 219
218/* implemented in guestdbg.c */ 220/* implemented in guestdbg.c */
219void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); 221void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index c0b99e0f6b63..d0341d2e54b1 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -458,3 +458,38 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
458 kvm_s390_set_psw_cc(vcpu, rc); 458 kvm_s390_set_psw_cc(vcpu, rc);
459 return 0; 459 return 0;
460} 460}
461
462/*
463 * Handle SIGP partial execution interception.
464 *
465 * This interception will occur at the source cpu when a source cpu sends an
466 * external call to a target cpu and the target cpu has the WAIT bit set in
467 * its cpuflags. Interception will occurr after the interrupt indicator bits at
468 * the target cpu have been set. All error cases will lead to instruction
469 * interception, therefore nothing is to be checked or prepared.
470 */
471int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
472{
473 int r3 = vcpu->arch.sie_block->ipa & 0x000f;
474 u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
475 struct kvm_vcpu *dest_vcpu;
476 u8 order_code = kvm_s390_get_base_disp_rs(vcpu);
477
478 trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
479
480 if (order_code == SIGP_EXTERNAL_CALL) {
481 dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
482 BUG_ON(dest_vcpu == NULL);
483
484 spin_lock_bh(&dest_vcpu->arch.local_int.lock);
485 if (waitqueue_active(&dest_vcpu->wq))
486 wake_up_interruptible(&dest_vcpu->wq);
487 dest_vcpu->preempted = true;
488 spin_unlock_bh(&dest_vcpu->arch.local_int.lock);
489
490 kvm_s390_set_psw_cc(vcpu, SIGP_CC_ORDER_CODE_ACCEPTED);
491 return 0;
492 }
493
494 return -EOPNOTSUPP;
495}
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
index 579b42afab40..916834d7a73a 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/trace.h
@@ -239,6 +239,29 @@ TRACE_EVENT(kvm_s390_handle_sigp,
239 __entry->cpu_addr, __entry->parameter) 239 __entry->cpu_addr, __entry->parameter)
240 ); 240 );
241 241
242TRACE_EVENT(kvm_s390_handle_sigp_pei,
243 TP_PROTO(VCPU_PROTO_COMMON, __u8 order_code, __u16 cpu_addr),
244 TP_ARGS(VCPU_ARGS_COMMON, order_code, cpu_addr),
245
246 TP_STRUCT__entry(
247 VCPU_FIELD_COMMON
248 __field(__u8, order_code)
249 __field(__u16, cpu_addr)
250 ),
251
252 TP_fast_assign(
253 VCPU_ASSIGN_COMMON
254 __entry->order_code = order_code;
255 __entry->cpu_addr = cpu_addr;
256 ),
257
258 VCPU_TP_PRINTK("handle sigp pei order %02x (%s), cpu address %04x",
259 __entry->order_code,
260 __print_symbolic(__entry->order_code,
261 sigp_order_codes),
262 __entry->cpu_addr)
263 );
264
242TRACE_EVENT(kvm_s390_handle_diag, 265TRACE_EVENT(kvm_s390_handle_diag,
243 TP_PROTO(VCPU_PROTO_COMMON, __u16 code), 266 TP_PROTO(VCPU_PROTO_COMMON, __u16 code),
244 TP_ARGS(VCPU_ARGS_COMMON, code), 267 TP_ARGS(VCPU_ARGS_COMMON, code),