]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/x86/kvm/x86.c
KVM: x86: zero base3 of unusable segments
[karo-tx-linux.git] / arch / x86 / kvm / x86.c
index 464da936c53dd96b2f9e89f1f0ef715bac3eafe2..02363e37d4a61e8271d7fed0a8c534e9dd90f264 100644 (file)
@@ -1763,6 +1763,7 @@ u64 get_kvmclock_ns(struct kvm *kvm)
 {
        struct kvm_arch *ka = &kvm->arch;
        struct pvclock_vcpu_time_info hv_clock;
+       u64 ret;
 
        spin_lock(&ka->pvclock_gtod_sync_lock);
        if (!ka->use_master_clock) {
@@ -1774,10 +1775,17 @@ u64 get_kvmclock_ns(struct kvm *kvm)
        hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
        spin_unlock(&ka->pvclock_gtod_sync_lock);
 
+       /* both __this_cpu_read() and rdtsc() should be on the same cpu */
+       get_cpu();
+
        kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL,
                           &hv_clock.tsc_shift,
                           &hv_clock.tsc_to_system_mul);
-       return __pvclock_read_cycles(&hv_clock, rdtsc());
+       ret = __pvclock_read_cycles(&hv_clock, rdtsc());
+
+       put_cpu();
+
+       return ret;
 }
 
 static void kvm_setup_pvclock_page(struct kvm_vcpu *v)
@@ -3288,11 +3296,14 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu,
        }
 }
 
+#define XSAVE_MXCSR_OFFSET 24
+
 static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
                                        struct kvm_xsave *guest_xsave)
 {
        u64 xstate_bv =
                *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
+       u32 mxcsr = *(u32 *)&guest_xsave->region[XSAVE_MXCSR_OFFSET / sizeof(u32)];
 
        if (boot_cpu_has(X86_FEATURE_XSAVE)) {
                /*
@@ -3300,11 +3311,13 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
                 * CPUID leaf 0xD, index 0, EDX:EAX.  This is for compatibility
                 * with old userspace.
                 */
-               if (xstate_bv & ~kvm_supported_xcr0())
+               if (xstate_bv & ~kvm_supported_xcr0() ||
+                       mxcsr & ~mxcsr_feature_mask)
                        return -EINVAL;
                load_xsave(vcpu, (u8 *)guest_xsave->region);
        } else {
-               if (xstate_bv & ~XFEATURE_MASK_FPSSE)
+               if (xstate_bv & ~XFEATURE_MASK_FPSSE ||
+                       mxcsr & ~mxcsr_feature_mask)
                        return -EINVAL;
                memcpy(&vcpu->arch.guest_fpu.state.fxsave,
                        guest_xsave->region, sizeof(struct fxregs_state));
@@ -4818,16 +4831,20 @@ emul_write:
 
 static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
 {
-       /* TODO: String I/O for in kernel device */
-       int r;
+       int r = 0, i;
 
-       if (vcpu->arch.pio.in)
-               r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
-                                   vcpu->arch.pio.size, pd);
-       else
-               r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
-                                    vcpu->arch.pio.port, vcpu->arch.pio.size,
-                                    pd);
+       for (i = 0; i < vcpu->arch.pio.count; i++) {
+               if (vcpu->arch.pio.in)
+                       r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port,
+                                           vcpu->arch.pio.size, pd);
+               else
+                       r = kvm_io_bus_write(vcpu, KVM_PIO_BUS,
+                                            vcpu->arch.pio.port, vcpu->arch.pio.size,
+                                            pd);
+               if (r)
+                       break;
+               pd += vcpu->arch.pio.size;
+       }
        return r;
 }
 
@@ -4865,6 +4882,8 @@ static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt,
        if (vcpu->arch.pio.count)
                goto data_avail;
 
+       memset(vcpu->arch.pio_data, 0, size * count);
+
        ret = emulator_pio_in_out(vcpu, size, port, val, count, true);
        if (ret) {
 data_avail:
@@ -5048,6 +5067,8 @@ static bool emulator_get_segment(struct x86_emulate_ctxt *ctxt, u16 *selector,
 
        if (var.unusable) {
                memset(desc, 0, sizeof(*desc));
+               if (base3)
+                       *base3 = 0;
                return false;
        }