diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 32 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 1 |
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 | ||
496 | static void __vcpu_run(struct kvm_vcpu *vcpu) | 496 | static 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 | ||
527 | int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 536 | int 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) | ||
29 | int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu); | 30 | int 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...)\ |