KVM: s390: Fix user triggerable bug in dead code
[pandora-kernel.git] / arch / s390 / kvm / kvm-s390.c
index 0bd3bea..f6f41dd 100644 (file)
@@ -65,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "instruction_stfl", VCPU_STAT(instruction_stfl) },
        { "instruction_tprot", VCPU_STAT(instruction_tprot) },
        { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
+       { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
        { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
        { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
        { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
@@ -127,6 +128,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        switch (ext) {
        case KVM_CAP_S390_PSW:
        case KVM_CAP_S390_GMAP:
+       case KVM_CAP_SYNC_MMU:
                r = 1;
                break;
        default:
@@ -270,10 +272,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        restore_fp_regs(&vcpu->arch.guest_fpregs);
        restore_access_regs(vcpu->arch.guest_acrs);
        gmap_enable(vcpu->arch.gmap);
+       atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
+       atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
        gmap_disable(vcpu->arch.gmap);
        save_fp_regs(&vcpu->arch.guest_fpregs);
        save_access_regs(vcpu->arch.guest_acrs);
@@ -301,7 +305,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
 
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
-       atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH | CPUSTAT_SM);
+       atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
+                                                   CPUSTAT_SM |
+                                                   CPUSTAT_STOPPED);
        vcpu->arch.sie_block->ecb   = 6;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) facilities;
@@ -412,7 +418,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
 {
        memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
-       vcpu->arch.guest_fpregs.fpc = fpu->fpc;
+       vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK;
        restore_fp_regs(&vcpu->arch.guest_fpregs);
        return 0;
 }
@@ -428,7 +434,7 @@ static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
 {
        int rc = 0;
 
-       if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
+       if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_STOPPED))
                rc = -EBUSY;
        else {
                vcpu->run->psw_mask = psw.mask;
@@ -463,6 +469,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 
 static void __vcpu_run(struct kvm_vcpu *vcpu)
 {
+       int rc;
+
        memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
 
        if (need_resched())
@@ -473,21 +481,24 @@ static void __vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_s390_deliver_pending_interrupts(vcpu);
 
+       VCPU_EVENT(vcpu, 6, "entering sie flags %x",
+                  atomic_read(&vcpu->arch.sie_block->cpuflags));
+
        vcpu->arch.sie_block->icptcode = 0;
        local_irq_disable();
        kvm_guest_enter();
        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)) {
+       rc = sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
+       local_irq_disable();
+       kvm_guest_exit();
+       local_irq_enable();
+
+       if (rc) {
                VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
                kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
        }
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
-       local_irq_disable();
-       kvm_guest_exit();
-       local_irq_enable();
 
        memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
 }
@@ -501,20 +512,10 @@ rerun_vcpu:
        if (vcpu->sigset_active)
                sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
-       atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
+       atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
 
        BUG_ON(vcpu->kvm->arch.float_int.local_int[vcpu->vcpu_id] == NULL);
 
-       switch (kvm_run->exit_reason) {
-       case KVM_EXIT_S390_SIEIC:
-       case KVM_EXIT_UNKNOWN:
-       case KVM_EXIT_INTR:
-       case KVM_EXIT_S390_RESET:
-               break;
-       default:
-               BUG();
-       }
-
        vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
        vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
 
@@ -591,6 +592,14 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
        } else
                prefix = 0;
 
+       /*
+        * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy
+        * copying in vcpu load/put. Lets update our copies before we save
+        * it into the save area
+        */
+       save_fp_regs(&vcpu->arch.guest_fpregs);
+       save_access_regs(vcpu->arch.guest_acrs);
+
        if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs),
                        vcpu->arch.guest_fpregs.fprs, 128, prefix))
                return -EFAULT;
@@ -743,7 +752,7 @@ static int __init kvm_s390_init(void)
        }
        memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
        facilities[0] &= 0xff00fff3f47c0000ULL;
-       facilities[1] &= 0x201c000000000000ULL;
+       facilities[1] &= 0x001c000000000000ULL;
        return 0;
 }