]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Merge tag 'kvm-x86-xen-6.15' of https://github.com/kvm-x86/linux into HEAD
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 19 Mar 2025 13:14:59 +0000 (09:14 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 19 Mar 2025 13:14:59 +0000 (09:14 -0400)
KVM Xen changes for 6.15

 - Don't write to the Xen hypercall page on MSR writes that are initiated by
   the host (userspace or KVM) to fix a class of bugs where KVM can write to
   guest memory at unexpected times, e.g. during vCPU creation if userspace has
   set the Xen hypercall MSR index to collide with an MSR that KVM emulates.

 - Restrict the Xen hypercall MSR indx to the unofficial synthetic range to
   reduce the set of possible collisions with MSRs that are emulated by KVM
   (collisions can still happen as KVM emulates Hyper-V MSRs, which also reside
   in the synthetic range).

 - Clean up and optimize KVM's handling of Xen MSR writes and xen_hvm_config.

 - Update Xen TSC leaves during CPUID emulation instead of modifying the CPUID
   entries when updating PV clocks, as there is no guarantee PV clocks will be
   updated between TSC frequency changes and CPUID emulation, and guest reads
   of Xen TSC should be rare, i.e. are not a hot path.

1  2 
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/kvm/xen.c

Simple merge
index f863a6f93a1a988df6228b0792fb759e328f0d3b,0b238c537893634e9eb0d3c57cea738345526b91..5e4d4934c0d3c21e536855cbd374d57ff531fd09
@@@ -2008,6 -2006,22 +2008,22 @@@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u
                } else if (function == 0x80000007) {
                        if (kvm_hv_invtsc_suppressed(vcpu))
                                *edx &= ~feature_bit(CONSTANT_TSC);
 -                              *ecx = vcpu->arch.hv_clock.tsc_to_system_mul;
 -                              *edx = vcpu->arch.hv_clock.tsc_shift;
+               } else if (IS_ENABLED(CONFIG_KVM_XEN) &&
+                          kvm_xen_is_tsc_leaf(vcpu, function)) {
+                       /*
+                        * Update guest TSC frequency information if necessary.
+                        * Ignore failures, there is no sane value that can be
+                        * provided if KVM can't get the TSC frequency.
+                        */
+                       if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu))
+                               kvm_guest_time_update(vcpu);
+                       if (index == 1) {
++                              *ecx = vcpu->arch.pvclock_tsc_mul;
++                              *edx = vcpu->arch.pvclock_tsc_shift;
+                       } else if (index == 2) {
+                               *eax = vcpu->arch.hw_tsc_khz;
+                       }
                }
        } else {
                *eax = *ebx = *ecx = *edx = 0;
index 1d809ff292fd78301d77c5dd1a7d0dc36694cb72,c3007982c88c6b86f1cd5bb1721b0840bc658ca0..69c20a68a3f017327f95f03024a5f724963d7ad9
@@@ -3166,12 -3167,11 +3166,12 @@@ static void kvm_setup_guest_pvclock(str
        kvm_gpc_mark_dirty_in_slot(gpc);
        read_unlock_irqrestore(&gpc->lock, flags);
  
 -      trace_kvm_pvclock_update(v->vcpu_id, &vcpu->hv_clock);
 +      trace_kvm_pvclock_update(vcpu->vcpu_id, &hv_clock);
  }
  
static int kvm_guest_time_update(struct kvm_vcpu *v)
+ int kvm_guest_time_update(struct kvm_vcpu *v)
  {
 +      struct pvclock_vcpu_time_info hv_clock = {};
        unsigned long flags, tgt_tsc_khz;
        unsigned seq;
        struct kvm_vcpu_arch *vcpu = &v->arch;
  
        if (unlikely(vcpu->hw_tsc_khz != tgt_tsc_khz)) {
                kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_khz * 1000LL,
 -                                 &vcpu->hv_clock.tsc_shift,
 -                                 &vcpu->hv_clock.tsc_to_system_mul);
 +                                 &vcpu->pvclock_tsc_shift,
 +                                 &vcpu->pvclock_tsc_mul);
                vcpu->hw_tsc_khz = tgt_tsc_khz;
-               kvm_xen_update_tsc_info(v);
        }
  
 -      vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
 -      vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
 +      hv_clock.tsc_shift = vcpu->pvclock_tsc_shift;
 +      hv_clock.tsc_to_system_mul = vcpu->pvclock_tsc_mul;
 +      hv_clock.tsc_timestamp = tsc_timestamp;
 +      hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
        vcpu->last_guest_tsc = tsc_timestamp;
  
        /* If the host uses TSC clocksource, then it is stable */
 -      pvclock_flags = 0;
 +      hv_clock.flags = 0;
        if (use_master_clock)
 -              pvclock_flags |= PVCLOCK_TSC_STABLE_BIT;
 +              hv_clock.flags |= PVCLOCK_TSC_STABLE_BIT;
  
 -      vcpu->hv_clock.flags = pvclock_flags;
 +      if (vcpu->pv_time.active) {
 +              /*
 +               * GUEST_STOPPED is only supported by kvmclock, and KVM's
 +               * historic behavior is to only process the request if kvmclock
 +               * is active/enabled.
 +               */
 +              if (vcpu->pvclock_set_guest_stopped_request) {
 +                      hv_clock.flags |= PVCLOCK_GUEST_STOPPED;
 +                      vcpu->pvclock_set_guest_stopped_request = false;
 +              }
 +              kvm_setup_guest_pvclock(&hv_clock, v, &vcpu->pv_time, 0);
 +
 +              hv_clock.flags &= ~PVCLOCK_GUEST_STOPPED;
 +      }
 +
 +      kvm_hv_setup_tsc_page(v->kvm, &hv_clock);
  
 -      if (vcpu->pv_time.active)
 -              kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0, false);
  #ifdef CONFIG_KVM_XEN
-       if (ka->xen_hvm_config.flags & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE)
 +      /*
 +       * For Xen guests we may need to override PVCLOCK_TSC_STABLE_BIT as unless
 +       * explicitly told to use TSC as its clocksource Xen will not set this bit.
 +       * This default behaviour led to bugs in some guest kernels which cause
 +       * problems if they observe PVCLOCK_TSC_STABLE_BIT in the pvclock flags.
 +       *
 +       * Note!  Clear TSC_STABLE only for Xen clocks, i.e. the order matters!
 +       */
++      if (ka->xen.hvm_config.flags & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE)
 +              hv_clock.flags &= ~PVCLOCK_TSC_STABLE_BIT;
 +
        if (vcpu->xen.vcpu_info_cache.active)
 -              kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_info_cache,
 -                                      offsetof(struct compat_vcpu_info, time),
 -                                      xen_pvclock_tsc_unstable);
 +              kvm_setup_guest_pvclock(&hv_clock, v, &vcpu->xen.vcpu_info_cache,
 +                                      offsetof(struct compat_vcpu_info, time));
        if (vcpu->xen.vcpu_time_info_cache.active)
 -              kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0,
 -                                      xen_pvclock_tsc_unstable);
 +              kvm_setup_guest_pvclock(&hv_clock, v, &vcpu->xen.vcpu_time_info_cache, 0);
  #endif
 -      kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock);
        return 0;
  }
  
Simple merge
Simple merge