aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2012-01-04 04:25:22 -0500
committerAvi Kivity <avi@redhat.com>2012-03-05 07:52:19 -0500
commite168bf8de33e16a909df2401af1f7d419c5780de (patch)
tree49dee8cc76e65eb1347895a6cb8f8843f690066d /arch
parent27e0393f15fc8bc855c6a888387ff5ffd2181089 (diff)
KVM: s390: ucontrol: export page faults to user
This patch introduces a new exit reason in the kvm_run structure named KVM_EXIT_S390_UCONTROL. This exit indicates, that a virtual cpu has regognized a fault on the host page table. The idea is that userspace can handle this fault by mapping memory at the fault location into the cpu's address space and then continue to run the virtual cpu. Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
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...)\