aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/kvm/kvm-s390.c32
-rw-r--r--arch/s390/kvm/kvm-s390.h1
2 files changed, 28 insertions, 5 deletions
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 2d3248895def..af05328aca25 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -493,8 +493,10 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
493 return -EINVAL; /* not implemented yet */ 493 return -EINVAL; /* not implemented yet */
494} 494}
495 495
496static void __vcpu_run(struct kvm_vcpu *vcpu) 496static int __vcpu_run(struct kvm_vcpu *vcpu)
497{ 497{
498 int rc;
499
498 memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); 500 memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
499 501
500 if (need_resched()) 502 if (need_resched())
@@ -511,9 +513,15 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
511 local_irq_enable(); 513 local_irq_enable();
512 VCPU_EVENT(vcpu, 6, "entering sie flags %x", 514 VCPU_EVENT(vcpu, 6, "entering sie flags %x",
513 atomic_read(&vcpu->arch.sie_block->cpuflags)); 515 atomic_read(&vcpu->arch.sie_block->cpuflags));
514 if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) { 516 rc = sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
515 VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); 517 if (rc) {
516 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); 518 if (kvm_is_ucontrol(vcpu->kvm)) {
519 rc = SIE_INTERCEPT_UCONTROL;
520 } else {
521 VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
522 kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
523 rc = 0;
524 }
517 } 525 }
518 VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", 526 VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
519 vcpu->arch.sie_block->icptcode); 527 vcpu->arch.sie_block->icptcode);
@@ -522,6 +530,7 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
522 local_irq_enable(); 530 local_irq_enable();
523 531
524 memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16); 532 memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
533 return rc;
525} 534}
526 535
527int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) 536int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -542,6 +551,7 @@ rerun_vcpu:
542 case KVM_EXIT_UNKNOWN: 551 case KVM_EXIT_UNKNOWN:
543 case KVM_EXIT_INTR: 552 case KVM_EXIT_INTR:
544 case KVM_EXIT_S390_RESET: 553 case KVM_EXIT_S390_RESET:
554 case KVM_EXIT_S390_UCONTROL:
545 break; 555 break;
546 default: 556 default:
547 BUG(); 557 BUG();
@@ -553,7 +563,9 @@ rerun_vcpu:
553 might_fault(); 563 might_fault();
554 564
555 do { 565 do {
556 __vcpu_run(vcpu); 566 rc = __vcpu_run(vcpu);
567 if (rc)
568 break;
557 rc = kvm_handle_sie_intercept(vcpu); 569 rc = kvm_handle_sie_intercept(vcpu);
558 } while (!signal_pending(current) && !rc); 570 } while (!signal_pending(current) && !rc);
559 571
@@ -565,6 +577,16 @@ rerun_vcpu:
565 rc = -EINTR; 577 rc = -EINTR;
566 } 578 }
567 579
580#ifdef CONFIG_KVM_S390_UCONTROL
581 if (rc == SIE_INTERCEPT_UCONTROL) {
582 kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL;
583 kvm_run->s390_ucontrol.trans_exc_code =
584 current->thread.gmap_addr;
585 kvm_run->s390_ucontrol.pgm_code = 0x10;
586 rc = 0;
587 }
588#endif
589
568 if (rc == -EOPNOTSUPP) { 590 if (rc == -EOPNOTSUPP) {
569 /* intercept cannot be handled in-kernel, prepare kvm-run */ 591 /* intercept cannot be handled in-kernel, prepare kvm-run */
570 kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; 592 kvm_run->exit_reason = KVM_EXIT_S390_SIEIC;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 45b236a7c730..62aa5f19bb98 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -26,6 +26,7 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
26 26
27/* negativ values are error codes, positive values for internal conditions */ 27/* negativ values are error codes, positive values for internal conditions */
28#define SIE_INTERCEPT_RERUNVCPU (1<<0) 28#define SIE_INTERCEPT_RERUNVCPU (1<<0)
29#define SIE_INTERCEPT_UCONTROL (1<<1)
29int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); 30int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
30 31
31#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\ 32#define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\