KVM: s390: ucontrol: export page faults to user
authorCarsten Otte <cotte@de.ibm.com>
Wed, 4 Jan 2012 09:25:22 +0000 (10:25 +0100)
committerAvi Kivity <avi@redhat.com>
Mon, 5 Mar 2012 12:52:19 +0000 (14:52 +0200)
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>
Documentation/virtual/kvm/api.txt
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
include/linux/kvm.h

index ee394b263261dceb9a833b3f7aa6da1d7ba0e861..6e53ff51422f7f0fb8ea3282b04779adbddc175e 100644 (file)
@@ -1694,6 +1694,20 @@ s390 specific.
 
 s390 specific.
 
+               /* KVM_EXIT_S390_UCONTROL */
+               struct {
+                       __u64 trans_exc_code;
+                       __u32 pgm_code;
+               } s390_ucontrol;
+
+s390 specific. A page fault has occurred for a user controlled virtual
+machine (KVM_VM_S390_UNCONTROL) on it's host page table that cannot be
+resolved by the kernel.
+The program code and the translation exception code that were placed
+in the cpu's lowcore are presented here as defined by the z Architecture
+Principles of Operation Book in the Chapter for Dynamic Address Translation
+(DAT)
+
                /* KVM_EXIT_DCR */
                struct {
                        __u32 dcrn;
index 2d3248895defc67ceea1e4be38a2567a58f013a6..af05328aca25b557cbe2a0629e2677ff94036968 100644 (file)
@@ -493,8 +493,10 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
        return -EINVAL; /* not implemented yet */
 }
 
-static void __vcpu_run(struct kvm_vcpu *vcpu)
+static int __vcpu_run(struct kvm_vcpu *vcpu)
 {
+       int rc;
+
        memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
 
        if (need_resched())
@@ -511,9 +513,15 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
        local_irq_enable();
        VCPU_EVENT(vcpu, 6, "entering sie flags %x",
                   atomic_read(&vcpu->arch.sie_block->cpuflags));
-       if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) {
-               VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
-               kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+       rc = sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
+       if (rc) {
+               if (kvm_is_ucontrol(vcpu->kvm)) {
+                       rc = SIE_INTERCEPT_UCONTROL;
+               } else {
+                       VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
+                       kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+                       rc = 0;
+               }
        }
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
@@ -522,6 +530,7 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
        local_irq_enable();
 
        memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
+       return rc;
 }
 
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -542,6 +551,7 @@ rerun_vcpu:
        case KVM_EXIT_UNKNOWN:
        case KVM_EXIT_INTR:
        case KVM_EXIT_S390_RESET:
+       case KVM_EXIT_S390_UCONTROL:
                break;
        default:
                BUG();
@@ -553,7 +563,9 @@ rerun_vcpu:
        might_fault();
 
        do {
-               __vcpu_run(vcpu);
+               rc = __vcpu_run(vcpu);
+               if (rc)
+                       break;
                rc = kvm_handle_sie_intercept(vcpu);
        } while (!signal_pending(current) && !rc);
 
@@ -565,6 +577,16 @@ rerun_vcpu:
                rc = -EINTR;
        }
 
+#ifdef CONFIG_KVM_S390_UCONTROL
+       if (rc == SIE_INTERCEPT_UCONTROL) {
+               kvm_run->exit_reason = KVM_EXIT_S390_UCONTROL;
+               kvm_run->s390_ucontrol.trans_exc_code =
+                       current->thread.gmap_addr;
+               kvm_run->s390_ucontrol.pgm_code = 0x10;
+               rc = 0;
+       }
+#endif
+
        if (rc == -EOPNOTSUPP) {
                /* intercept cannot be handled in-kernel, prepare kvm-run */
                kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
index 45b236a7c7301d455ed3f012da53608f3977d764..62aa5f19bb98807597f37b8d15119fcb6b51e603 100644 (file)
@@ -26,6 +26,7 @@ typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
 
 /* negativ values are error codes, positive values for internal conditions */
 #define SIE_INTERCEPT_RERUNVCPU                (1<<0)
+#define SIE_INTERCEPT_UCONTROL         (1<<1)
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
 
 #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
index 0a66c10726914f04fd73e24c024e4a63c7df3927..7f686f6708b0cb5cc1a1edf9593b208dcf5f672b 100644 (file)
@@ -162,6 +162,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_INTERNAL_ERROR   17
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_PAPR_HCALL      19
+#define KVM_EXIT_S390_UCONTROL   20
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@ struct kvm_run {
 #define KVM_S390_RESET_CPU_INIT  8
 #define KVM_S390_RESET_IPL       16
                __u64 s390_reset_flags;
+               /* KVM_EXIT_S390_UCONTROL */
+               struct {
+                       __u64 trans_exc_code;
+                       __u32 pgm_code;
+               } s390_ucontrol;
                /* KVM_EXIT_DCR */
                struct {
                        __u32 dcrn;