AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/11/11 17:18 flow patch-triage
5m Args:
null

Results:
{
  "EnableConfigs": [
    "KVM",
    "KVM_INTEL",
    "KVM_AMD",
    "KVM_XEN"
  ],
  "FocusSymbols": [
    "kvm_vcpu_ioctl_get_clock_guest",
    "kvm_vcpu_ioctl_set_clock_guest",
    "kvm_set_tsc_khz",
    "kvm_synchronize_tsc",
    "kvm_arch_tsc_get_attr",
    "kvm_arch_tsc_set_attr",
    "kvm_update_masterclock",
    "kvm_vm_ioctl_set_clock",
    "kvm_write_system_time",
    "kvm_xen_start_timer"
  ],
  "KMSANReasoning": "The patch series refactors x86 KVM timestamp counter (TSC) synchronization and master clock tracking, allowing the master clock to remain active even when vCPUs have divergent TSC offsets (provided their TSC frequencies match). It also adds KVM_GET_CLOCK_GUEST and KVM_SET_CLOCK_GUEST ioctls along with the KVM_VCPU_TSC_SCALE device attribute to support precise kvmclock migration.\n\nEvaluating the memory safety aspects contrasting KMSAN and KASAN:\n1. Structures copied to userspace:\n   - KVM_GET_CLOCK_GUEST copies `struct pvclock_vcpu_time_info hv_clock = {}`, which is completely zero-initialized on the stack. Because it is declared `__attribute__((__packed__))`, there are no hidden compiler alignment holes, and all fields (including `pad0` and `pad[2]`) are explicitly zeroed before copying to userspace.\n   - KVM_VCPU_TSC_SCALE copies `struct kvm_vcpu_tsc_scale scale` consisting of two `__u64` members (16 bytes total) with no internal or trailing padding holes; both members (`tsc_ratio` and `tsc_frac_bits`) are explicitly assigned before `copy_to_user`.\n   - In `kvm_vm_ioctl_get_clock`, `struct kvm_clock_data data` was already zero-initialized with `{ 0 }`.\n2. Stack and heap initialization:\n   - New struct members in `struct kvm_arch` and `struct kvm_vcpu_arch` reside in objects allocated with zero-initialization (`kzalloc` and `kmem_cache_zalloc`).\n   - All newly introduced or modified local variables on the stack (e.g., `tsc_shift`, `tsc_mult`, `host_tsc`, `ns`, `clock`) are fully initialized by helper functions or explicitly in all control flow branches before being evaluated or passed onward.\n3. Bug profiles and sanitizer coverage:\n   - The primary risks in this patch series involve concurrency and locking protocol updates (`tsc_write_lock`, `pvclock_sc` seqcount, vCPU request propagation), as well as fixed-point arithmetic, shift bounds, and clock monotonicity logic.\n   - Concurrency bugs are covered by LOCKDEP and standard race checkers; any potential memory corruption or out-of-bounds access is covered by KASAN.\n   - There are no risks of uninitialized memory reads or kernel info-leaks.\n\nTherefore, running a dedicated KMSAN fuzzing session is not justified.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series introduces new KVM ioctls (KVM_GET_CLOCK_GUEST, KVM_SET_CLOCK_GUEST), a new vCPU device attribute (KVM_VCPU_TSC_SCALE), and significantly refactors KVM TSC synchronization and master clock management (allowing divergent TSC offsets without disabling master clock mode, updating generation tracking, and refining pvclock updates). These changes modify reachable, executable code in the x86 KVM subsystem accessible via userspace ioctls and warrant fuzzing.",
  "WorthFuzzing": true
}

1/1 2026/11/11 17:18 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 840dfffc5f02909c098eb4036b0c016646e5edff\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Nov 11 17:18:20 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst\nindex ddc61ea36ac59d..44c6152c5768da 100644\n--- a/Documentation/virt/kvm/api.rst\n+++ b/Documentation/virt/kvm/api.rst\n@@ -2023,6 +2023,14 @@ If the KVM_CAP_VM_TSC_CONTROL capability is advertised, this can also\n be used as a vm ioctl to set the initial tsc frequency of subsequently\n created vCPUs.  Note, the vm ioctl is only allowed prior to creating vCPUs.\n \n+Changing the frequency of a vCPU with the vcpu ioctl re-synchronizes\n+its TSC: for a vCPU which has run, or whose TSC userspace has written,\n+the current guest TSC value is preserved across the change (the TSC\n+offset, as visible through the KVM_VCPU_TSC_OFFSET attribute, is\n+rewritten accordingly); otherwise the vCPU is synchronized to the\n+VM's existing TSC timeline at the new frequency. Setting the current\n+frequency again is a no-op.\n+\n For TSC protected Confidential Computing (CoCo) VMs where TSC frequency\n is configured once at VM scope and remains unchanged during VM's\n lifetime, the vm ioctl should be used to configure the TSC frequency\n@@ -6759,6 +6767,59 @@ if the guest_memfd memory was pinned in IOMMU page tables.\n \n See also: :ref:`KVM_SET_MEMORY_ATTRIBUTES`.\n \n+4.147 KVM_GET_CLOCK_GUEST\n+----------------------------\n+\n+:Capability: KVM_CAP_CLOCK_GUEST\n+:Architectures: x86_64\n+:Type: vcpu ioctl\n+:Parameters: struct pvclock_vcpu_time_info (out)\n+:Returns: 0 on success, \u003c0 on error\n+\n+Retrieves the current time information structure used for KVM/PV clocks,\n+in precisely the form advertised to the guest vCPU, which gives parameters\n+for a direct conversion from a guest TSC value to nanoseconds.\n+\n+The structure is in terms of the given vCPU's TSC. It must be passed back\n+to KVM_SET_CLOCK_GUEST on the *same* vCPU (on the destination VM, for\n+migration); vCPUs may legitimately have different TSC offsets, which would\n+otherwise be silently folded into the restored KVM clock.\n+\n+When the KVM clock is not in \"master clock\" mode, for example because the\n+host TSC is unreliable or the guest TSCs are oddly configured, the KVM clock\n+is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest TSC.\n+In this case, the KVM_GET_CLOCK_GUEST ioctl returns -ENODATA.\n+\n+4.148 KVM_SET_CLOCK_GUEST\n+----------------------------\n+\n+:Capability: KVM_CAP_CLOCK_GUEST\n+:Architectures: x86_64\n+:Type: vcpu ioctl\n+:Parameters: struct pvclock_vcpu_time_info (in)\n+:Returns: 0 on success, \u003c0 on error\n+\n+Sets the KVM clock (for the whole VM) in terms of the vCPU TSC, using the\n+pvclock structure as returned by KVM_GET_CLOCK_GUEST. This allows the precise\n+arithmetic relationship between guest TSC and KVM clock to be preserved by\n+userspace across migration.\n+\n+When the KVM clock is not in \"master clock\" mode, and the KVM clock is actually\n+defined by the host CLOCK_MONOTONIC_RAW, this ioctl returns -ENODATA. Userspace\n+may choose to set the clock using the less precise KVM_SET_CLOCK ioctl, or may\n+choose to fail, denying migration to a host whose TSC is misbehaving. A host\n+whose CPU TSC frequency is unknown (only possible without\n+X86_FEATURE_CONSTANT_TSC) is never in \"master clock\" mode, so it also returns\n+-ENODATA.\n+\n+If the mul/shift fields of the provided pvclock structure encode a TSC\n+frequency inconsistent with the vCPU's actual TSC frequency, this ioctl\n+returns -ERANGE.\n+\n+If the vCPU's current TSC is behind the tsc_timestamp in the provided\n+structure, this ioctl returns -EINVAL. Restore the guest TSC (which the\n+documented migration procedure keeps monotonic) before invoking it.\n+\n .. _kvm_run:\n \n 5. The kvm_run structure\ndiff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst\nindex deb5c51bc00c87..8dc6ad904429dd 100644\n--- a/Documentation/virt/kvm/devices/vcpu.rst\n+++ b/Documentation/virt/kvm/devices/vcpu.rst\n@@ -239,6 +239,7 @@ including the layout of the stolen time structure.\n :Architectures: x86\n \n 4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET\n+----------------------------------\n \n :Parameters: 64-bit unsigned TSC offset\n \n@@ -253,7 +254,10 @@ Returns:\n Specifies the guest's TSC offset relative to the host's TSC. The guest's\n TSC is then derived by the following equation:\n \n-  guest_tsc = host_tsc + KVM_VCPU_TSC_OFFSET\n+  guest_tsc = ((host_tsc * tsc_ratio) \u003e\u003e tsc_frac_bits) + KVM_VCPU_TSC_OFFSET\n+\n+The values of tsc_ratio and tsc_frac_bits can be obtained using\n+the KVM_VCPU_TSC_SCALE attribute.\n \n This attribute is useful to adjust the guest's TSC on live migration,\n so that the TSC counts the time during which the VM was paused. The\n@@ -261,44 +265,117 @@ following describes a possible algorithm to use for this purpose.\n \n From the source VMM process:\n \n-1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_src),\n+1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_src),\n    kvmclock nanoseconds (guest_src), and host CLOCK_REALTIME nanoseconds\n-   (host_src).\n+   (time_src) at a given moment (Tsrc). The host_tsc field is only valid\n+   when the returned flags include KVM_CLOCK_HOST_TSC.\n+\n+2. For each vCPU[i]:\n+\n+   a. Read the KVM_VCPU_TSC_OFFSET attribute to record the guest TSC offset\n+      (ofs_src[i]).\n+\n+   b. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling\n+      ratio (ratio_src[i], frac_bits_src[i]). If the attribute is not\n+      supported (-ENXIO), there is no hardware TSC scaling and identity\n+      scaling applies: use ratio 1, frac_bits 0.\n+\n+   c. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the\n+      guest's TSC (freq[i]).\n+\n+   d. Use host_tsc_src and the scaling/offset factors to calculate this\n+      vCPU's TSC at time Tsrc:\n+\n+      tsc_src[i] = ((host_tsc_src * ratio_src[i]) \u003e\u003e frac_bits_src[i]) + ofs_src[i]\n \n-2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the\n-   guest TSC offset (ofs_src[i]).\n+      Note that frac_bits may be as high as 48, so this multiplication\n+      needs a 128-bit intermediate to avoid overflow.\n \n-3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the\n-   guest's TSC (freq).\n+3. Invoke the KVM_GET_CLOCK_GUEST ioctl on the boot vCPU to return the KVM\n+   clock as a function of the guest TSC (pvti_src). (This ioctl may not\n+   succeed if the host and guest TSCs are not consistent and well-behaved.)\n \n From the destination VMM process:\n \n-4. Invoke the KVM_SET_CLOCK ioctl, providing the source nanoseconds from\n-   kvmclock (guest_src) and CLOCK_REALTIME (host_src) in their respective\n-   fields.  Ensure that the KVM_CLOCK_REALTIME flag is set in the provided\n-   structure.\n+4. Invoke the KVM_SET_TSC_KHZ ioctl to set the scaled frequency of the\n+   guest's TSC (freq[i]) — either on the VM before creating the vCPUs, or\n+   on each vCPU after creating it (as the exemplar test does). When using\n+   the per-vCPU form, set the frequency before performing step 7 on that\n+   vCPU: KVM_VCPU_TSC_SCALE reports the ratio for the currently\n+   configured frequency.\n+\n+5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_dst) and\n+   host CLOCK_REALTIME nanoseconds (time_dst) at a given moment (Tdst),\n+   again checking KVM_CLOCK_HOST_TSC in the returned flags.\n+\n+6. Calculate the number of nanoseconds elapsed between Tsrc and Tdst:\n+\n+   ΔT = time_dst - time_src\n+\n+7. As each vCPU[i] is created:\n+\n+   a. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling\n+      ratio (ratio_dst[i], frac_bits_dst[i]). As in step 2b, -ENXIO means\n+      identity scaling: use ratio 1, frac_bits 0.\n+\n+   b. Calculate the intended guest TSC value at time Tdst, taking care\n+      with the units (ΔT is in nanoseconds; freq, as set by\n+      KVM_SET_TSC_KHZ, is in kHz):\n \n-   KVM will advance the VM's kvmclock to account for elapsed time since\n-   recording the clock values.  Note that this will cause problems in\n-   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized\n-   between the source and destination, and a reasonably short time passes\n-   between the source pausing the VMs and the destination executing\n-   steps 4-7.\n+      tsc_dst[i] = tsc_src[i] + (ΔT * freq[i] / 10^6)\n+\n+   c. Use host_tsc_dst and the scaling factors to calculate this vCPU's\n+      raw scaled TSC at time Tdst without offsetting:\n+\n+      raw_dst[i] = ((host_tsc_dst * ratio_dst[i]) \u003e\u003e frac_bits_dst[i])\n+\n+   d. Calculate ofs_dst[i] = tsc_dst[i] - raw_dst[i] and set the resulting\n+      offset using the KVM_VCPU_TSC_OFFSET attribute.\n+\n+8. If pvti_src was provided, invoke the KVM_SET_CLOCK_GUEST ioctl on the boot\n+   vCPU to restore the KVM clock as a precise function of the guest TSC.\n+\n+9. If KVM_SET_CLOCK_GUEST was not available or failed (e.g. because the\n+   master clock is not active), fall back to the KVM_SET_CLOCK ioctl,\n+   providing the source nanoseconds from kvmclock (guest_src) and\n+   CLOCK_REALTIME (time_src) in their respective fields. Ensure that the\n+   KVM_CLOCK_REALTIME flag is set in the provided structure.\n+\n+   KVM will restore the VM's kvmclock, accounting for elapsed time since\n+   the clock values were recorded. Note that this will cause problems in\n+   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized between\n+   the source and destination, and a reasonably short time passes between\n+   the source pausing the VMs and the destination resuming them.\n+   Due to the KVM_[SG]ET_CLOCK API using CLOCK_REALTIME instead of\n+   CLOCK_TAI, leap seconds during the migration may also introduce errors.\n+\n+4.2 ATTRIBUTE: KVM_VCPU_TSC_SCALE\n+---------------------------------\n+\n+:Parameters: struct kvm_vcpu_tsc_scale\n+\n+Returns:\n+\n+\t ======= ======================================\n+\t -EFAULT Error writing the result to the\n+\t\t provided address.\n+\t -ENXIO  Attribute not supported (no TSC scaling)\n+\t -EINVAL Invalid request to write the attribute\n+\t ======= ======================================\n \n-5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_dest) and\n-   kvmclock nanoseconds (guest_dest).\n+This read-only attribute reports the guest's TSC scaling factor, in the form\n+of a fixed-point number represented by the following structure::\n \n-6. Adjust the guest TSC offsets for every vCPU to account for (1) time\n-   elapsed since recording state and (2) difference in TSCs between the\n-   source and destination machine:\n+  struct kvm_vcpu_tsc_scale {\n+\t__u64 tsc_ratio;\n+\t__u64 tsc_frac_bits;\n+  };\n \n-   ofs_dst[i] = ofs_src[i] -\n-     (guest_src - guest_dest) * freq +\n-     (tsc_src - tsc_dest)\n+The tsc_frac_bits field indicates the location of the fixed point, such that\n+host TSC values are converted to guest TSC using the formula:\n \n-   (\"ofs[i] + tsc - guest * freq\" is the guest TSC value corresponding to\n-   a time of 0 in kvmclock.  The above formula ensures that it is the\n-   same on the destination as it was on the source).\n+  guest_tsc = ((host_tsc * tsc_ratio) \u003e\u003e tsc_frac_bits) + offset\n \n-7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the\n-   respective value derived in the previous step.\n+Userspace can use this to precisely calculate the guest TSC from the host\n+TSC at any given moment. This is needed for accurate migration of guests,\n+as described in the documentation for the KVM_VCPU_TSC_OFFSET attribute.\ndiff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst\nindex 662231e958a075..4548b61a7652a8 100644\n--- a/Documentation/virt/kvm/locking.rst\n+++ b/Documentation/virt/kvm/locking.rst\n@@ -263,7 +263,7 @@ time it will be set using the Dirty tracking mechanism described above.\n \n :Type:\t\traw_spinlock_t\n :Arch:\t\tx86\n-:Protects:\t- kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset}\n+:Protects:\t- kvm_arch::{cur_tsc_write,cur_tsc_nsec,cur_tsc_offset}\n \t\t- tsc offset in vmcb\n :Comment:\t'raw' because updating the tsc offsets must not be preempted.\n \ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 9fadc98d3c4998..773f7c800f6aac 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -14663,8 +14663,8 @@ S:\tSupported\n T:\tgit git://git.kernel.org/pub/scm/virt/kvm/kvm.git\n F:\tarch/um/include/asm/kvm_para.h\n F:\tarch/x86/include/asm/kvm_para.h\n-F:\tarch/x86/include/asm/pvclock-abi.h\n F:\tarch/x86/include/uapi/asm/kvm_para.h\n+F:\tarch/x86/include/uapi/asm/pvclock-abi.h\n F:\tarch/x86/kernel/kvm.c\n F:\tarch/x86/kernel/kvmclock.c\n F:\tinclude/asm-generic/kvm_para.h\n@@ -29780,8 +29780,8 @@ R:\tBoris Ostrovsky \u003cboris.ostrovsky@oracle.com\u003e\n L:\txen-devel@lists.xenproject.org (moderated for non-subscribers)\n S:\tSupported\n F:\tarch/x86/configs/xen.config\n-F:\tarch/x86/include/asm/pvclock-abi.h\n F:\tarch/x86/include/asm/xen/\n+F:\tarch/x86/include/uapi/asm/pvclock-abi.h\n F:\tarch/x86/platform/pvh/\n F:\tarch/x86/xen/\n \ndiff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h\nindex e2eef7057bd353..59260f08765402 100644\n--- a/arch/x86/include/asm/kvm_host.h\n+++ b/arch/x86/include/asm/kvm_host.h\n@@ -887,6 +887,8 @@ struct kvm_vcpu_arch {\n \tu64 this_tsc_nsec;\n \tu64 this_tsc_write;\n \tu64 this_tsc_generation;\n+\tu64 this_tsc_freq_generation;\n+\tbool user_set_tsc;\n \tbool tsc_catchup;\n \tbool tsc_always_catchup;\n \ts8 virtual_tsc_shift;\n@@ -1236,15 +1238,16 @@ struct kvm_arch {\n \t * preemption-disabled region, so it must be a raw spinlock.\n \t */\n \traw_spinlock_t tsc_write_lock;\n-\tu64 last_tsc_nsec;\n-\tu64 last_tsc_write;\n-\tu32 last_tsc_khz;\n-\tu64 last_tsc_offset;\n-\tu64 last_tsc_scaling_ratio;\n+\tu32 cur_tsc_khz;\n+\tu64 cur_tsc_scaling_ratio;\n \tu64 cur_tsc_nsec;\n \tu64 cur_tsc_write;\n \tu64 cur_tsc_offset;\n \tu64 cur_tsc_generation;\n+\tbool all_vcpus_matched_tsc;\n+\tbool all_vcpus_matched_freq;\n+\tint nr_vcpus_matched_freq;\n+\tu64 cur_tsc_freq_generation;\n \tint nr_vcpus_matched_tsc;\n \n \tu32 default_tsc_khz;\n@@ -1269,7 +1272,6 @@ struct kvm_arch {\n #endif\n \n \tbool backwards_tsc_observed;\n-\tbool boot_vcpu_runs_old_kvmclock;\n \tu32 bsp_vcpu_id;\n \n \tu64 disabled_quirks;\ndiff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h\nindex 1585ec8040666e..f8274d8e471d63 100644\n--- a/arch/x86/include/uapi/asm/kvm.h\n+++ b/arch/x86/include/uapi/asm/kvm.h\n@@ -12,6 +12,7 @@\n #include \u003clinux/types.h\u003e\n #include \u003clinux/ioctl.h\u003e\n #include \u003clinux/stddef.h\u003e\n+#include \u003casm/pvclock-abi.h\u003e\n \n #define KVM_PIO_PAGE_OFFSET 1\n #define KVM_COALESCED_MMIO_PAGE_OFFSET 2\n@@ -963,6 +964,12 @@ struct kvm_hyperv_eventfd {\n /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */\n #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */\n #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */\n+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */\n+\n+struct kvm_vcpu_tsc_scale {\n+\t__u64 tsc_ratio;\n+\t__u64 tsc_frac_bits;\n+};\n \n /* x86-specific KVM_EXIT_HYPERCALL flags. */\n #define KVM_EXIT_HYPERCALL_LONG_MODE\t_BITULL(0)\ndiff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/uapi/asm/pvclock-abi.h\nsimilarity index 82%\nrename from arch/x86/include/asm/pvclock-abi.h\nrename to arch/x86/include/uapi/asm/pvclock-abi.h\nindex b9fece5fc96d6f..6d70cf64036293 100644\n--- a/arch/x86/include/asm/pvclock-abi.h\n+++ b/arch/x86/include/uapi/asm/pvclock-abi.h\n@@ -1,6 +1,9 @@\n-/* SPDX-License-Identifier: GPL-2.0 */\n+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */\n #ifndef _ASM_X86_PVCLOCK_ABI_H\n #define _ASM_X86_PVCLOCK_ABI_H\n+\n+#include \u003clinux/types.h\u003e\n+\n #ifndef __ASSEMBLER__\n \n /*\n@@ -24,20 +27,20 @@\n  */\n \n struct pvclock_vcpu_time_info {\n-\tu32   version;\n-\tu32   pad0;\n-\tu64   tsc_timestamp;\n-\tu64   system_time;\n-\tu32   tsc_to_system_mul;\n-\ts8    tsc_shift;\n-\tu8    flags;\n-\tu8    pad[2];\n+\t__u32   version;\n+\t__u32   pad0;\n+\t__u64   tsc_timestamp;\n+\t__u64   system_time;\n+\t__u32   tsc_to_system_mul;\n+\t__s8    tsc_shift;\n+\t__u8    flags;\n+\t__u8    pad[2];\n } __attribute__((__packed__)); /* 32 bytes */\n \n struct pvclock_wall_clock {\n-\tu32   version;\n-\tu32   sec;\n-\tu32   nsec;\n+\t__u32   version;\n+\t__u32   sec;\n+\t__u32   nsec;\n } __attribute__((__packed__));\n \n #define PVCLOCK_TSC_STABLE_BIT\t(1 \u003c\u003c 0)\ndiff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c\nindex e91650af44c207..94cd4d73689a77 100644\n--- a/arch/x86/kvm/msrs.c\n+++ b/arch/x86/kvm/msrs.c\n@@ -1275,24 +1275,30 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_o\n static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time,\n \t\t\t\t  bool old_msr, bool host_initiated)\n {\n-\tstruct kvm_arch *ka = \u0026vcpu-\u003ekvm-\u003earch;\n-\n-\tif (vcpu-\u003evcpu_id == 0 \u0026\u0026 !host_initiated) {\n-\t\tif (ka-\u003eboot_vcpu_runs_old_kvmclock != old_msr)\n-\t\t\tkvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);\n-\n-\t\tka-\u003eboot_vcpu_runs_old_kvmclock = old_msr;\n-\t}\n+\t/*\n+\t * Slide the master clock reference point forward, so that the\n+\t * pvclock written below carries a recent tsc_timestamp. SUSE's\n+\t * 2.6.16 kernel (the only known user of the legacy MSR with a\n+\t * reason to care) re-requests the time by rewriting this MSR\n+\t * whenever tsc_timestamp falls more than 1/5 jiffie behind the\n+\t * TSC, and would livelock against a fixed reference point; each\n+\t * rewrite now genuinely freshens it. A write with the enable\n+\t * bit clear deactivates the pvclock; there is nothing to\n+\t * freshen.\n+\t */\n+\tif (old_msr \u0026\u0026 !host_initiated \u0026\u0026 (system_time \u0026 1))\n+\t\tkvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);\n \n \tvcpu-\u003earch.time = system_time;\n-\tkvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);\n \n \t/* we verify if the enable bit is set... */\n-\tif (system_time \u0026 1)\n+\tif (system_time \u0026 1) {\n \t\tkvm_gpc_activate(\u0026vcpu-\u003earch.pv_time, system_time \u0026 ~1ULL,\n \t\t\t\t sizeof(struct pvclock_vcpu_time_info));\n-\telse\n+\t\tkvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);\n+\t} else {\n \t\tkvm_gpc_deactivate(\u0026vcpu-\u003earch.pv_time);\n+\t}\n \n \treturn;\n }\n@@ -1639,7 +1645,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)\n \t\tbreak;\n \tcase MSR_IA32_TSC:\n \t\tif (msr_info-\u003ehost_initiated) {\n-\t\t\tkvm_synchronize_tsc(vcpu, \u0026data);\n+\t\t\tkvm_synchronize_tsc(vcpu, \u0026data, true);\n \t\t} else if (!vcpu-\u003earch.guest_tsc_protected) {\n \t\t\tu64 adj = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data) -\n \t\t\t\t  vcpu-\u003earch.l1_tsc_offset;\ndiff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h\nindex 93de876c318ce5..704683532ef018 100644\n--- a/arch/x86/kvm/trace.h\n+++ b/arch/x86/kvm/trace.h\n@@ -1003,25 +1003,25 @@ TRACE_EVENT(kvm_write_tsc_offset,\n \t{VDSO_CLOCKMODE_TSC,  \"tsc\"}\t\t\t\\\n \n TRACE_EVENT(kvm_update_master_clock,\n-\tTP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched),\n-\tTP_ARGS(use_master_clock, host_clock, offset_matched),\n+\tTP_PROTO(bool use_master_clock, unsigned int host_clock, bool freq_matched),\n+\tTP_ARGS(use_master_clock, host_clock, freq_matched),\n \n \tTP_STRUCT__entry(\n \t\t__field(\t\tbool,\tuse_master_clock\t)\n \t\t__field(\tunsigned int,\thost_clock\t\t)\n-\t\t__field(\t\tbool,\toffset_matched\t\t)\n+\t\t__field(\t\tbool,\tfreq_matched\t\t)\n \t),\n \n \tTP_fast_assign(\n \t\t__entry-\u003euse_master_clock\t= use_master_clock;\n \t\t__entry-\u003ehost_clock\t\t= host_clock;\n-\t\t__entry-\u003eoffset_matched\t\t= offset_matched;\n+\t\t__entry-\u003efreq_matched\t\t= freq_matched;\n \t),\n \n-\tTP_printk(\"masterclock %d hostclock %s offsetmatched %u\",\n+\tTP_printk(\"masterclock %d hostclock %s freqmatched %u\",\n \t\t  __entry-\u003euse_master_clock,\n \t\t  __print_symbolic(__entry-\u003ehost_clock, host_clocks),\n-\t\t  __entry-\u003eoffset_matched)\n+\t\t  __entry-\u003efreq_matched)\n );\n \n TRACE_EVENT(kvm_track_tsc,\ndiff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c\nindex 32563a91fba99a..2136c1f6803207 100644\n--- a/arch/x86/kvm/x86.c\n+++ b/arch/x86/kvm/x86.c\n@@ -210,6 +210,10 @@ module_param(pi_inject_timer, bint, 0644);\n static bool __read_mostly mitigate_smt_rsb;\n module_param(mitigate_smt_rsb, bool, 0444);\n \n+#ifdef CONFIG_X86_64\n+static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);\n+#endif\n+\n #define KVM_SUPPORTED_XCR0     (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \\\n \t\t\t\t| XFEATURE_MASK_YMM | XFEATURE_MASK_BNDREGS \\\n \t\t\t\t| XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \\\n@@ -885,60 +889,6 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)\n \t       kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending();\n }\n \n-#ifdef CONFIG_X86_64\n-struct pvclock_clock {\n-\tint vclock_mode;\n-\tu64 cycle_last;\n-\tu64 mask;\n-\tu32 mult;\n-\tu32 shift;\n-\tu64 base_cycles;\n-\tu64 offset;\n-};\n-\n-struct pvclock_gtod_data {\n-\tseqcount_t\tseq;\n-\n-\tstruct pvclock_clock clock; /* extract of a clocksource struct */\n-\tstruct pvclock_clock raw_clock; /* extract of a clocksource struct */\n-\n-\tktime_t\t\toffs_boot;\n-\tu64\t\twall_time_sec;\n-};\n-\n-static struct pvclock_gtod_data pvclock_gtod_data;\n-\n-static void update_pvclock_gtod(struct timekeeper *tk)\n-{\n-\tstruct pvclock_gtod_data *vdata = \u0026pvclock_gtod_data;\n-\n-\twrite_seqcount_begin(\u0026vdata-\u003eseq);\n-\n-\t/* copy pvclock gtod data */\n-\tvdata-\u003eclock.vclock_mode\t= tk-\u003etkr_mono.clock-\u003evdso_clock_mode;\n-\tvdata-\u003eclock.cycle_last\t\t= tk-\u003etkr_mono.cycle_last;\n-\tvdata-\u003eclock.mask\t\t= tk-\u003etkr_mono.mask;\n-\tvdata-\u003eclock.mult\t\t= tk-\u003etkr_mono.mult;\n-\tvdata-\u003eclock.shift\t\t= tk-\u003etkr_mono.shift;\n-\tvdata-\u003eclock.base_cycles\t= tk-\u003etkr_mono.xtime_nsec;\n-\tvdata-\u003eclock.offset\t\t= tk-\u003etkr_mono.base;\n-\n-\tvdata-\u003eraw_clock.vclock_mode\t= tk-\u003etkr_raw.clock-\u003evdso_clock_mode;\n-\tvdata-\u003eraw_clock.cycle_last\t= tk-\u003etkr_raw.cycle_last;\n-\tvdata-\u003eraw_clock.mask\t\t= tk-\u003etkr_raw.mask;\n-\tvdata-\u003eraw_clock.mult\t\t= tk-\u003etkr_raw.mult;\n-\tvdata-\u003eraw_clock.shift\t\t= tk-\u003etkr_raw.shift;\n-\tvdata-\u003eraw_clock.base_cycles\t= tk-\u003etkr_raw.xtime_nsec;\n-\tvdata-\u003eraw_clock.offset\t\t= tk-\u003etkr_raw.base;\n-\n-\tvdata-\u003ewall_time_sec            = tk-\u003extime_sec;\n-\n-\tvdata-\u003eoffs_boot\t\t= tk-\u003eoffs_boot;\n-\n-\twrite_seqcount_end(\u0026vdata-\u003eseq);\n-}\n-#endif\n-\n static s64 get_kvmclock_base_ns(void)\n {\n \t/* Count up from boot time, but with the frequency of the raw clock.  */\n@@ -1027,7 +977,7 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)\n \t/* Guest TSC same frequency as host TSC? */\n \tif (!scale) {\n \t\tkvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio);\n-\t\treturn 0;\n+\t\tgoto clear_catchup;\n \t}\n \n \t/* TSC scaling supported? */\n@@ -1053,13 +1003,34 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)\n \t}\n \n \tkvm_vcpu_write_tsc_multiplier(vcpu, ratio);\n+\n+clear_catchup:\n+\t/*\n+\t * A frequency which no longer needs catchup must also stop it: a\n+\t * previous above-host-rate setting on scaling-less hardware set\n+\t * the always-catchup flags, and nothing else ever clears them.\n+\t * Only undo that pairing — tsc_catchup alone also serves the\n+\t * unstable-host-TSC compensation in kvm_arch_vcpu_load().\n+\t */\n+\tif (vcpu-\u003earch.tsc_always_catchup) {\n+\t\tvcpu-\u003earch.tsc_always_catchup = 0;\n+\t\tvcpu-\u003earch.tsc_catchup = 0;\n+\t}\n \treturn 0;\n }\n \n-static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)\n+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,\n+\t\t\t\t   u64 host_tsc, s64 ns, bool user_initiated);\n+\n+static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)\n {\n+\tbool freq_changed = (vcpu-\u003earch.virtual_tsc_khz != user_tsc_khz);\n \tu32 thresh_lo, thresh_hi;\n+\tu32 tsc_mult;\n+\ts8 tsc_shift;\n \tint use_scaling = 0;\n+\tu64 tsc, host_tsc;\n+\ts64 ns;\n \n \t/* tsc_khz can be zero if TSC calibration fails */\n \tif (user_tsc_khz == 0) {\n@@ -1070,9 +1041,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)\n \n \t/* Compute a scale to convert nanoseconds in TSC cycles */\n \tkvm_get_time_scale(user_tsc_khz * 1000LL, NSEC_PER_SEC,\n-\t\t\t   \u0026vcpu-\u003earch.virtual_tsc_shift,\n-\t\t\t   \u0026vcpu-\u003earch.virtual_tsc_mult);\n-\tvcpu-\u003earch.virtual_tsc_khz = user_tsc_khz;\n+\t\t\t   \u0026tsc_shift, \u0026tsc_mult);\n \n \t/*\n \t * Compute the variation in TSC rate which is acceptable\n@@ -1087,7 +1056,67 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)\n \t\t\t user_tsc_khz, thresh_lo, thresh_hi);\n \t\tuse_scaling = 1;\n \t}\n-\treturn set_tsc_khz(vcpu, user_tsc_khz, use_scaling);\n+\n+\t/*\n+\t * Sample the guest TSC before changing the ratio, so continuity\n+\t * can be preserved across the change — as a {guest TSC, host\n+\t * clock} tuple, not a bare value: the synchronization below\n+\t * computes the new offset against the tuple's own reference\n+\t * point, so the guest TSC keeps counting through this function\n+\t * and any delay here (preemption included) costs nothing.\n+\t */\n+#ifdef CONFIG_X86_64\n+\tif (!kvm_get_time_and_clockread(\u0026ns, \u0026host_tsc))\n+#endif\n+\t{\n+\t\thost_tsc = rdtsc();\n+\t\tns = get_kvmclock_base_ns();\n+\t}\n+\ttsc = kvm_read_l1_tsc(vcpu, host_tsc);\n+\n+\tif (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))\n+\t\treturn -1;\n+\n+\t/*\n+\t * Commit the new frequency only once set_tsc_khz() can no longer\n+\t * fail: a failed ioctl must leave no trace, or a retry with the\n+\t * still-active frequency would wrongly look like a change.\n+\t */\n+\tvcpu-\u003earch.virtual_tsc_shift = tsc_shift;\n+\tvcpu-\u003earch.virtual_tsc_mult = tsc_mult;\n+\tvcpu-\u003earch.virtual_tsc_khz = user_tsc_khz;\n+\n+\t/*\n+\t * At vCPU creation (@init) the vCPU is not yet counted in\n+\t * online_vcpus, so synchronizing here would corrupt the VM-wide\n+\t * matching state (and leave it corrupted if creation subsequently\n+\t * fails). The initial synchronization happens in\n+\t * kvm_arch_vcpu_postcreate() instead. An unchanged frequency is\n+\t * a no-op for synchronization: don't disturb the generation\n+\t * tracking of a configured vCPU.\n+\t */\n+\tif (init || !freq_changed)\n+\t\treturn 0;\n+\n+\t/*\n+\t * Changing the frequency changes the vCPU's position on the\n+\t * generation's cycle timeline, so re-synchronize. For a vCPU\n+\t * which has run, preserve the guest TSC value read above across\n+\t * the change; likewise if userspace has written a TSC on this\n+\t * vCPU — a zero write would discard it. Otherwise the vCPU holds\n+\t * only its creation-time synchronization, so synchronize as for\n+\t * a zero write. When the generation is already at the new\n+\t * frequency this places the vCPU on its timeline rather than\n+\t * opening a gratuitous new generation and orphaning the matched\n+\t * state of its siblings; the first vCPU to adopt a new frequency\n+\t * necessarily opens a new generation, starting at zero — mixed\n+\t * frequencies within a VM forfeit the master clock anyway.\n+\t */\n+\tif (vcpu-\u003earch.last_vmentry_cpu != -1 || vcpu-\u003earch.user_set_tsc)\n+\t\tkvm_synchronize_tsc_at(vcpu, \u0026tsc, host_tsc, ns, false);\n+\telse\n+\t\tkvm_synchronize_tsc_at(vcpu, NULL, host_tsc, ns, false);\n+\treturn 0;\n }\n \n static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)\n@@ -1104,42 +1133,97 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)\n }\n \n #ifdef CONFIG_X86_64\n+static int kvm_host_vclock_mode;\n+\n static inline bool gtod_is_based_on_tsc(int mode)\n {\n \treturn mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;\n }\n-#endif\n \n-static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generation)\n+static bool kvm_use_master_clock(struct kvm *kvm)\n+{\n+\tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n+\n+\treturn ka-\u003eall_vcpus_matched_freq \u0026\u0026\n+\t\t!ka-\u003ebackwards_tsc_observed;\n+}\n+\n+static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclock)\n {\n-#ifdef CONFIG_X86_64\n \tstruct kvm_arch *ka = \u0026vcpu-\u003ekvm-\u003earch;\n-\tstruct pvclock_gtod_data *gtod = \u0026pvclock_gtod_data;\n+\tbool prev_matched_tsc = ka-\u003eall_vcpus_matched_tsc;\n+\tbool prev_matched_freq = ka-\u003eall_vcpus_matched_freq;\n+\n+\t/*\n+\t * Track whether all vCPUs have matching TSC offsets (for\n+\t * PVCLOCK_TSC_STABLE_BIT) and matching frequencies (for\n+\t * master clock eligibility).\n+\t */\n+\n+\t/*\n+\t * A new vCPU might already have incremented -\u003eonline_vcpus\n+\t * and cause a temporary false negative here. But will then\n+\t * call kvm_synchronize_tsc() from kvm_arch_vcpu_postcreate()\n+\t * and finish the job.\n+\t */\n+\tint online = atomic_read(\u0026vcpu-\u003ekvm-\u003eonline_vcpus);\n+\t/*\n+\t * WRITE_ONCE() pairs with the READ_ONCE() in kvm_guest_time_update(),\n+\t * which samples the flag locklessly (outside both tsc_write_lock and\n+\t * its pvclock seqcount read section); the race is benign (a stale\n+\t * value merely delays the PVCLOCK_TSC_STABLE_BIT broadcast to the\n+\t * masterclock update which is requested below).\n+\t */\n+\tWRITE_ONCE(ka-\u003eall_vcpus_matched_tsc,\n+\t\t   ka-\u003enr_vcpus_matched_tsc \u003e= online);\n+\n+\tupdate_mclock |= (prev_matched_tsc != ka-\u003eall_vcpus_matched_tsc);\n+\n+\t/*\n+\t * all_vcpus_matched_freq starts true and is cleared when\n+\t * __kvm_synchronize_tsc() detects a frequency mismatch.\n+\t * Re-enable when all vCPUs have synced with matching frequency.\n+\t * If all offsets also match, that implies frequencies match too.\n+\t */\n+\tif (ka-\u003eall_vcpus_matched_tsc ||\n+\t    ka-\u003enr_vcpus_matched_freq \u003e= online)\n+\t\tka-\u003eall_vcpus_matched_freq = true;\n+\n+\t/*\n+\t * A frequency-match transition needs a masterclock update too:\n+\t * when the last vCPU reaches the new frequency, the masterclock\n+\t * scaling factors still describe the old one, and no toggle of\n+\t * use_master_clock occurs to trigger the refresh.\n+\t */\n+\tupdate_mclock |= (prev_matched_freq != ka-\u003eall_vcpus_matched_freq);\n \n \t/*\n \t * To use the masterclock, the host clocksource must be based on TSC\n-\t * and all vCPUs must have matching TSCs.  Note, the count for matching\n-\t * vCPUs doesn't include the reference vCPU, hence \"+1\".\n+\t * and all vCPUs must have matching TSC *frequency*. Different offsets\n+\t * are fine — each vCPU's pvclock has its own tsc_timestamp that\n+\t * accounts for its offset.\n \t */\n-\tbool use_master_clock = (ka-\u003enr_vcpus_matched_tsc + 1 ==\n-\t\t\t\t atomic_read(\u0026vcpu-\u003ekvm-\u003eonline_vcpus)) \u0026\u0026\n-\t\t\t\tgtod_is_based_on_tsc(gtod-\u003eclock.vclock_mode);\n+\tint host_vclock_mode = READ_ONCE(kvm_host_vclock_mode);\n+\tbool use_master_clock = kvm_use_master_clock(vcpu-\u003ekvm) \u0026\u0026\n+\t\t\t\tgtod_is_based_on_tsc(host_vclock_mode);\n \n \t/*\n-\t * Request a masterclock update if the masterclock needs to be toggled\n-\t * on/off, or when starting a new generation and the masterclock is\n-\t * enabled (compute_guest_tsc() requires the masterclock snapshot to be\n-\t * taken _after_ the new generation is created).\n+\t * Request a masterclock update if needed: toggling master clock,\n+\t * new generation requiring a fresh snapshot, or a change in\n+\t * all_vcpus_matched_tsc (to broadcast PVCLOCK_TSC_STABLE_BIT).\n \t */\n-\tif ((ka-\u003euse_master_clock \u0026\u0026 new_generation) ||\n+\tif ((ka-\u003euse_master_clock \u0026\u0026 update_mclock) ||\n \t    (ka-\u003euse_master_clock != use_master_clock))\n \t\tkvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);\n \n \ttrace_kvm_track_tsc(vcpu-\u003evcpu_id, ka-\u003enr_vcpus_matched_tsc,\n \t\t\t    atomic_read(\u0026vcpu-\u003ekvm-\u003eonline_vcpus),\n-\t\t            ka-\u003euse_master_clock, gtod-\u003eclock.vclock_mode);\n-#endif\n+\t\t\t    ka-\u003euse_master_clock, host_vclock_mode);\n }\n+#else\n+static inline void kvm_track_tsc_matching(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t  bool update_mclock) {}\n+#endif\n \n /*\n  * Multiply tsc by a fixed point number represented by ratio.\n@@ -1305,7 +1389,7 @@ static inline bool kvm_check_tsc_unstable(void)\n \t * TSC is marked unstable when we're running on Hyper-V,\n \t * 'TSC page' clocksource is good.\n \t */\n-\tif (pvclock_gtod_data.clock.vclock_mode == VDSO_CLOCKMODE_HVCLOCK)\n+\tif (READ_ONCE(kvm_host_vclock_mode) == VDSO_CLOCKMODE_HVCLOCK)\n \t\treturn false;\n #endif\n \treturn check_tsc_unstable();\n@@ -1326,21 +1410,55 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,\n \tif (vcpu-\u003earch.guest_tsc_protected)\n \t\treturn;\n \n-\tif (user_set_tsc)\n+\tif (user_set_tsc) {\n \t\tvcpu-\u003ekvm-\u003earch.user_set_tsc = true;\n+\t\tvcpu-\u003earch.user_set_tsc = true;\n+\t}\n \n \t/*\n-\t * We also track th most recent recorded KHZ, write and time to\n-\t * allow the matching interval to be extended at each write.\n+\t * Track the TSC frequency, scaling ratio, and offset for the current\n+\t * generation. These are used to detect matching TSC writes and to\n+\t * compute the guest TSC from the host clock.\n+\t *\n+\t * If the frequency changed, master clock mode can no longer be used\n+\t * since the kvmclock scaling factors differ between vCPUs.\n \t */\n-\tkvm-\u003earch.last_tsc_nsec = ns;\n-\tkvm-\u003earch.last_tsc_write = tsc;\n-\tkvm-\u003earch.last_tsc_khz = vcpu-\u003earch.virtual_tsc_khz;\n-\tkvm-\u003earch.last_tsc_offset = offset;\n-\tkvm-\u003earch.last_tsc_scaling_ratio = vcpu-\u003earch.l1_tsc_scaling_ratio;\n+\tif (vcpu-\u003earch.virtual_tsc_khz != kvm-\u003earch.cur_tsc_khz) {\n+\t\tkvm-\u003earch.cur_tsc_freq_generation++;\n+\t\tkvm-\u003earch.all_vcpus_matched_freq = false;\n+\t\tkvm-\u003earch.nr_vcpus_matched_freq = 0;\n+\t}\n+\n+\t/* Count each vCPU once per freq generation */\n+\tif (vcpu-\u003earch.this_tsc_freq_generation != kvm-\u003earch.cur_tsc_freq_generation) {\n+\t\tvcpu-\u003earch.this_tsc_freq_generation = kvm-\u003earch.cur_tsc_freq_generation;\n+\t\tkvm-\u003earch.nr_vcpus_matched_freq++;\n+\t}\n+\n+\tkvm-\u003earch.cur_tsc_khz = vcpu-\u003earch.virtual_tsc_khz;\n+\tkvm-\u003earch.cur_tsc_scaling_ratio = vcpu-\u003earch.l1_tsc_scaling_ratio;\n \n \tvcpu-\u003earch.last_guest_tsc = tsc;\n \n+\t/*\n+\t * The offset written below is absolute, superseding any backwards-TSC\n+\t * compensation still pending from kvm_arch_enable_virtualization_cpu()\n+\t * (which has already been folded into cur_tsc_offset, and thus into\n+\t * a matched @offset); applying it again at the next vcpu_load would\n+\t * double it.\n+\t */\n+\tvcpu-\u003earch.tsc_offset_adjustment = 0;\n+\n+\t/*\n+\t * If the offset changes, the guest-visible pvclock must be\n+\t * rewritten before the vCPU runs again: its tsc_timestamp was\n+\t * computed with the old offset, and the masterclock (which now\n+\t * survives offset changes) will not request the refresh for a\n+\t * matched write.\n+\t */\n+\tif (offset != vcpu-\u003earch.l1_tsc_offset)\n+\t\tkvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);\n+\n \tkvm_vcpu_write_tsc_offset(vcpu, offset);\n \n \tif (!matched) {\n@@ -1350,39 +1468,47 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,\n \t\t * nanosecond time, offset, and write, so if TSCs are in\n \t\t * sync, we can match exact offset, and if not, we can match\n \t\t * exact software computation in compute_guest_tsc()\n-\t\t *\n-\t\t * These values are tracked in kvm-\u003earch.cur_xxx variables.\n \t\t */\n \t\tkvm-\u003earch.cur_tsc_generation++;\n+\t\tWRITE_ONCE(kvm-\u003earch.all_vcpus_matched_tsc, false);\n+\t\tkvm-\u003earch.nr_vcpus_matched_tsc = 0;\n \t\tkvm-\u003earch.cur_tsc_nsec = ns;\n \t\tkvm-\u003earch.cur_tsc_write = tsc;\n \t\tkvm-\u003earch.cur_tsc_offset = offset;\n-\t\tkvm-\u003earch.nr_vcpus_matched_tsc = 0;\n-\t} else if (vcpu-\u003earch.this_tsc_generation != kvm-\u003earch.cur_tsc_generation) {\n+\t}\n+\n+\tif (vcpu-\u003earch.this_tsc_generation != kvm-\u003earch.cur_tsc_generation) {\n+\t\tvcpu-\u003earch.this_tsc_generation = kvm-\u003earch.cur_tsc_generation;\n \t\tkvm-\u003earch.nr_vcpus_matched_tsc++;\n \t}\n \n-\t/* Keep track of which generation this VCPU has synchronized to */\n-\tvcpu-\u003earch.this_tsc_generation = kvm-\u003earch.cur_tsc_generation;\n \tvcpu-\u003earch.this_tsc_nsec = kvm-\u003earch.cur_tsc_nsec;\n \tvcpu-\u003earch.this_tsc_write = kvm-\u003earch.cur_tsc_write;\n \n \tkvm_track_tsc_matching(vcpu, !matched);\n }\n \n-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)\n+/*\n+ * Synchronize the vCPU's TSC against an explicit {host_tsc, ns} reference\n+ * point: @value (when non-NULL) is the guest TSC *at* @host_tsc, not at\n+ * some unspecified \"now\". The offset is computed against that reference,\n+ * so a sampled value stays valid however much time passes between the\n+ * sampling and this call.\n+ */\n+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,\n+\t\t\t\t   u64 host_tsc, s64 ns, bool user_initiated)\n {\n-\tu64 data = user_value ? *user_value : 0;\n+\tu64 data = value ? *value : 0;\n \tstruct kvm *kvm = vcpu-\u003ekvm;\n-\tu64 offset, ns, elapsed;\n+\tu64 offset, elapsed;\n \tunsigned long flags;\n \tbool matched = false;\n \tbool synchronizing = false;\n \n \traw_spin_lock_irqsave(\u0026kvm-\u003earch.tsc_write_lock, flags);\n-\toffset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);\n-\tns = get_kvmclock_base_ns();\n-\telapsed = ns - kvm-\u003earch.last_tsc_nsec;\n+\n+\toffset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);\n+\telapsed = ns - kvm-\u003earch.cur_tsc_nsec;\n \n \tif (vcpu-\u003earch.virtual_tsc_khz) {\n \t\tif (data == 0) {\n@@ -1392,9 +1518,10 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)\n \t\t\t */\n \t\t\tsynchronizing = true;\n \t\t} else if (kvm-\u003earch.user_set_tsc) {\n-\t\t\tu64 tsc_exp = kvm-\u003earch.last_tsc_write +\n+\t\t\tu64 tsc_exp = kvm-\u003earch.cur_tsc_write +\n \t\t\t\t\t\tnsec_to_cycles(vcpu, elapsed);\n \t\t\tu64 tsc_hz = vcpu-\u003earch.virtual_tsc_khz * 1000LL;\n+\t\t\tu64 window;\n \t\t\t/*\n \t\t\t * Here lies UAPI baggage: when a user-initiated TSC write has\n \t\t\t * a small delta (1 second) of virtual cycle time against the\n@@ -1409,9 +1536,18 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)\n \t\t\t * to this 'correction' to make it sync up with values that only\n \t\t\t * come from the kernel's default vCPU creation. Make the 1-second\n \t\t\t * slop hack only trigger if the user_set_tsc flag is already set.\n+\t\t\t *\n+\t\t\t * A kernel-internal write (a frequency change preserving the\n+\t\t\t * guest TSC) carries an exact value sampled with its own\n+\t\t\t * reference point, not a racy userspace one; a vCPU on the\n+\t\t\t * generation's line still matches it to within arithmetic\n+\t\t\t * rounding, but one which genuinely diverged (e.g. by a guest\n+\t\t\t * TSC_ADJUST write) must not be snapped back by up to a\n+\t\t\t * second. Use a 1ms window for those.\n \t\t\t */\n-\t\t\tsynchronizing = data \u003c tsc_exp + tsc_hz \u0026\u0026\n-\t\t\t\t\tdata + tsc_hz \u003e tsc_exp;\n+\t\t\twindow = user_initiated ? tsc_hz : tsc_hz / 1000;\n+\t\t\tsynchronizing = data \u003c tsc_exp + window \u0026\u0026\n+\t\t\t\t\tdata + window \u003e tsc_exp;\n \t\t}\n \t}\n \n@@ -1423,21 +1559,52 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)\n \t * it's better to try to match offsets from the beginning.\n          */\n \tif (synchronizing \u0026\u0026\n-\t    vcpu-\u003earch.virtual_tsc_khz == kvm-\u003earch.last_tsc_khz) {\n-\t\tif (!kvm_check_tsc_unstable()) {\n+\t    vcpu-\u003earch.virtual_tsc_khz == kvm-\u003earch.cur_tsc_khz) {\n+\t\t/*\n+\t\t * If synchronizing, extrapolate the generation's value to\n+\t\t * \"now\": the matching window slides forward with wall time,\n+\t\t * anchored on the generation's origin alone (a matched\n+\t\t * write no longer updates any stored reference point).\n+\t\t */\n+\t\tu64 delta = nsec_to_cycles(vcpu, elapsed);\n+\n+\t\tdata = kvm-\u003earch.cur_tsc_write + delta;\n+\n+\t\t/*\n+\t\t * The generation's offset can be reused directly: it is in\n+\t\t * this vCPU's scaling domain, because every generation is\n+\t\t * opened by a vCPU (the initial VM-creation generation is\n+\t\t * not matchable) and set_tsc_khz() derives the scaling\n+\t\t * ratio deterministically from the kHz value, so two vCPUs\n+\t\t * at the same frequency carry the same ratio.\n+\t\t */\n+\t\tif (!kvm_check_tsc_unstable())\n \t\t\toffset = kvm-\u003earch.cur_tsc_offset;\n-\t\t} else {\n-\t\t\tu64 delta = nsec_to_cycles(vcpu, elapsed);\n-\t\t\tdata += delta;\n-\t\t\toffset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);\n-\t\t}\n+\t\telse\n+\t\t\toffset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);\n \t\tmatched = true;\n \t}\n \n-\t__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, !!user_value);\n+\t__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, user_initiated);\n \traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n }\n \n+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)\n+{\n+\tu64 host_tsc;\n+\ts64 ns;\n+\n+#ifdef CONFIG_X86_64\n+\tif (!kvm_get_time_and_clockread(\u0026ns, \u0026host_tsc))\n+#endif\n+\t{\n+\t\thost_tsc = rdtsc();\n+\t\tns = get_kvmclock_base_ns();\n+\t}\n+\n+\tkvm_synchronize_tsc_at(vcpu, value, host_tsc, ns, user_initiated);\n+}\n+\n #ifdef CONFIG_X86_64\n \n static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap,\n@@ -1564,12 +1731,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n {\n #ifdef CONFIG_X86_64\n \tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n-\tint vclock_mode;\n-\tbool host_tsc_clocksource, vcpus_matched;\n+\tbool host_tsc_clocksource;\n \n \tlockdep_assert_held(\u0026kvm-\u003earch.tsc_write_lock);\n-\tvcpus_matched = (ka-\u003enr_vcpus_matched_tsc + 1 ==\n-\t\t\tatomic_read(\u0026kvm-\u003eonline_vcpus));\n \n \t/*\n \t * If the host uses TSC clock, then passthrough TSC as stable\n@@ -1579,9 +1743,8 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n \t\t\t\t\t\u0026ka-\u003emaster_kernel_ns,\n \t\t\t\t\t\u0026ka-\u003emaster_cycle_now);\n \n-\tka-\u003euse_master_clock = host_tsc_clocksource \u0026\u0026 vcpus_matched\n-\t\t\t\t\u0026\u0026 !ka-\u003ebackwards_tsc_observed\n-\t\t\t\t\u0026\u0026 !ka-\u003eboot_vcpu_runs_old_kvmclock;\n+\tka-\u003euse_master_clock = host_tsc_clocksource \u0026\u0026\n+\t\t\t\tkvm_use_master_clock(kvm);\n \n \tif (ka-\u003euse_master_clock) {\n \t\tu64 tsc_hz;\n@@ -1594,7 +1757,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n \t\t * get_kvmclock() to compute kvmclock from the host TSC\n \t\t * without needing a vCPU reference.\n \t\t */\n-\t\tka-\u003emaster_tsc_scaling_ratio = ka-\u003elast_tsc_scaling_ratio;\n+\t\tka-\u003emaster_tsc_scaling_ratio = ka-\u003ecur_tsc_scaling_ratio;\n \t\ttsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;\n \t\tif (tsc_hz \u0026\u0026 kvm_caps.has_tsc_control)\n \t\t\ttsc_hz = kvm_scale_tsc(tsc_hz,\n@@ -1607,9 +1770,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n \t\t\tka-\u003euse_master_clock = false;\n \t}\n \n-\tvclock_mode = pvclock_gtod_data.clock.vclock_mode;\n-\ttrace_kvm_update_master_clock(ka-\u003euse_master_clock, vclock_mode,\n-\t\t\t\t\tvcpus_matched);\n+\ttrace_kvm_update_master_clock(ka-\u003euse_master_clock,\n+\t\t\t\t      READ_ONCE(kvm_host_vclock_mode),\n+\t\t\t\t      ka-\u003eall_vcpus_matched_freq);\n #endif\n }\n \n@@ -1618,10 +1781,51 @@ static void kvm_make_mclock_inprogress_request(struct kvm *kvm)\n \tkvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);\n }\n \n-static void __kvm_start_pvclock_update(struct kvm *kvm)\n+static void kvm_clear_mclock_inprogress_request(struct kvm *kvm)\n+{\n+\tstruct kvm_vcpu *vcpu;\n+\tunsigned long i;\n+\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tkvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);\n+}\n+\n+static bool __kvm_start_pvclock_update(struct kvm *kvm, struct kvm_vcpu *requesting_vcpu)\n {\n+\tstruct kvm_vcpu *vcpu;\n+\tunsigned long i;\n+\n \traw_spin_lock_irq(\u0026kvm-\u003earch.tsc_write_lock);\n+\n+\t/*\n+\t * If another vCPU already did the update while we were waiting\n+\t * for the lock, our request will have been cleared. Bail out,\n+\t * clearing the KVM_REQ_MCLOCK_INPROGRESS kicks made on entry to\n+\t * kvm_update_masterclock() so vCPUs can enter the guest again.\n+\t *\n+\t * Clearing them VM-wide can also clear kicks just made by yet\n+\t * another updater still waiting for tsc_write_lock, letting\n+\t * vCPUs run while that update is in flight. That is not new:\n+\t * kvm_end_pvclock_update() has always cleared the request on\n+\t * every vCPU regardless of which updater made it. The window is\n+\t * harmless to readers (the pvclock seqcount covers the master\n+\t * state); a vCPU which slips in runs on the old snapshot until\n+\t * its KVM_REQ_CLOCK_UPDATE is serviced, exactly as if it had\n+\t * entered just before the update began.\n+\t */\n+\tif (requesting_vcpu \u0026\u0026\n+\t    !kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, requesting_vcpu)) {\n+\t\tkvm_clear_mclock_inprogress_request(kvm);\n+\t\traw_spin_unlock_irq(\u0026kvm-\u003earch.tsc_write_lock);\n+\t\treturn false;\n+\t}\n+\n+\t/* The update is VM-wide; prevent other vCPUs from redoing it. */\n+\tkvm_for_each_vcpu(i, vcpu, kvm)\n+\t\tkvm_clear_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);\n+\n \twrite_seqcount_begin(\u0026kvm-\u003earch.pvclock_sc);\n+\treturn true;\n }\n \n static void kvm_start_pvclock_update(struct kvm *kvm)\n@@ -1629,7 +1833,7 @@ static void kvm_start_pvclock_update(struct kvm *kvm)\n \tkvm_make_mclock_inprogress_request(kvm);\n \n \t/* no guest entries from this point */\n-\t__kvm_start_pvclock_update(kvm);\n+\t__kvm_start_pvclock_update(kvm, NULL);\n }\n \n static void kvm_end_pvclock_update(struct kvm *kvm)\n@@ -1638,22 +1842,35 @@ static void kvm_end_pvclock_update(struct kvm *kvm)\n \tstruct kvm_vcpu *vcpu;\n \tunsigned long i;\n \n-\twrite_seqcount_end(\u0026ka-\u003epvclock_sc);\n-\traw_spin_unlock_irq(\u0026ka-\u003etsc_write_lock);\n \tkvm_for_each_vcpu(i, vcpu, kvm)\n \t\tkvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);\n \n \t/* guest entries allowed */\n-\tkvm_for_each_vcpu(i, vcpu, kvm)\n-\t\tkvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);\n+\tkvm_clear_mclock_inprogress_request(kvm);\n+\n+\twrite_seqcount_end(\u0026ka-\u003epvclock_sc);\n+\traw_spin_unlock_irq(\u0026ka-\u003etsc_write_lock);\n }\n \n-static void kvm_update_masterclock(struct kvm *kvm)\n+static void kvm_update_masterclock(struct kvm *kvm, struct kvm_vcpu *vcpu)\n {\n+\t/*\n+\t * The Hyper-V TSC page request is made before the dedupe check\n+\t * in __kvm_start_pvclock_update() because it takes a mutex and\n+\t * so cannot sit inside the tsc_write_lock critical section where\n+\t * the winning updater is known. A losing vCPU may therefore mark\n+\t * the page HOST_CHANGED after the winner has already rewritten\n+\t * it; the next clock update then rewrites the page again with\n+\t * the same contents, which the TSC-page sequence protocol makes\n+\t * safe against concurrently running guests.\n+\t */\n \tkvm_hv_request_tsc_page_update(kvm);\n-\tkvm_start_pvclock_update(kvm);\n-\tpvclock_update_vm_gtod_copy(kvm);\n-\tkvm_end_pvclock_update(kvm);\n+\tkvm_make_mclock_inprogress_request(kvm);\n+\n+\tif (__kvm_start_pvclock_update(kvm, vcpu)) {\n+\t\tpvclock_update_vm_gtod_copy(kvm);\n+\t\tkvm_end_pvclock_update(kvm);\n+\t}\n }\n \n /*\n@@ -1680,6 +1897,7 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,\n \tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n \tstruct pvclock_vcpu_time_info hv_clock;\n \tstruct timespec64 ts;\n+\tu64 clock;\n \n \tif (!ka-\u003euse_master_clock)\n \t\treturn false;\n@@ -1687,10 +1905,6 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,\n \tif (!kvm_get_walltime_and_clockread(\u0026ts, \u0026data-\u003ehost_tsc))\n \t\treturn false;\n \n-\tdata-\u003erealtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;\n-\tdata-\u003eflags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |\n-\t\t       KVM_CLOCK_TSC_STABLE;\n-\n \thv_clock.tsc_timestamp = ka-\u003emaster_cycle_now;\n \thv_clock.system_time = ka-\u003emaster_kernel_ns + ka-\u003ekvmclock_offset;\n \n@@ -1705,13 +1919,34 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,\n \t\tu64 tsc_delta = data-\u003ehost_tsc - ka-\u003emaster_cycle_now;\n \n \t\ttsc_delta = kvm_scale_tsc(tsc_delta, ka-\u003emaster_tsc_scaling_ratio);\n-\t\tdata-\u003eclock = hv_clock.system_time +\n-\t\t\t      pvclock_scale_delta(tsc_delta,\n-\t\t\t\t\t\t  hv_clock.tsc_to_system_mul,\n-\t\t\t\t\t\t  hv_clock.tsc_shift);\n+\t\tclock = hv_clock.system_time +\n+\t\t\tpvclock_scale_delta(tsc_delta,\n+\t\t\t\t\t    hv_clock.tsc_to_system_mul,\n+\t\t\t\t\t    hv_clock.tsc_shift);\n \t} else {\n-\t\tdata-\u003eclock = __pvclock_read_cycles(\u0026hv_clock, data-\u003ehost_tsc);\n+\t\tclock = __pvclock_read_cycles(\u0026hv_clock, data-\u003ehost_tsc);\n \t}\n+\n+\t/*\n+\t * Sanity-check the snapshot: if the elapsed time it computes from\n+\t * the host TSC disagrees with the raw clock by more than a second,\n+\t * the TSC was reset (suspend/resume — possibly re-inited by\n+\t * firmware to an arbitrary value, including an underflowing one\n+\t * below master_cycle_now) while nothing refreshed the snapshot.\n+\t * That can happen while the VM has no vCPUs, since both the\n+\t * resume compensation and the clocksource notifier work through\n+\t * vCPUs. Use the fallback clock rather than returning a\n+\t * discontinuity flagged KVM_CLOCK_TSC_STABLE.\n+\t */\n+\tif (unlikely(abs((s64)(clock - hv_clock.system_time) -\n+\t\t\t (get_kvmclock_base_ns() - ka-\u003emaster_kernel_ns)) \u003e\n+\t\t     NSEC_PER_SEC))\n+\t\treturn false;\n+\n+\tdata-\u003eclock = clock;\n+\tdata-\u003erealtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;\n+\tdata-\u003eflags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |\n+\t\t       KVM_CLOCK_TSC_STABLE;\n \treturn true;\n #else\n \treturn false;\n@@ -1897,7 +2132,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v)\n \n \t/* If the host uses TSC clocksource, then it is stable */\n \thv_clock.flags = 0;\n-\tif (use_master_clock)\n+\tif (use_master_clock \u0026\u0026 READ_ONCE(ka-\u003eall_vcpus_matched_tsc))\n \t\thv_clock.flags |= PVCLOCK_TSC_STABLE_BIT;\n \n \tif (vcpu-\u003epv_time.active) {\n@@ -2294,6 +2529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)\n \tcase KVM_CAP_MEMORY_FAULT_INFO:\n \tcase KVM_CAP_X86_GUEST_MODE:\n \tcase KVM_CAP_ONE_REG:\n+#ifdef CONFIG_X86_64\n+\tcase KVM_CAP_CLOCK_GUEST:\n+#endif\n \t\tr = 1;\n \t\tbreak;\n \tcase KVM_CAP_PRE_FAULT_MEMORY:\n@@ -2608,11 +2846,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)\n \t\t * On a host with synchronized TSC, there is no need to update\n \t\t * kvmclock on vcpu-\u003ecpu migration\n \t\t */\n-\t\tif (!vcpu-\u003ekvm-\u003earch.use_master_clock || vcpu-\u003ecpu == -1) {\n+\t\tif (!vcpu-\u003ekvm-\u003earch.use_master_clock) {\n \t\t\tif (__ratelimit(\u0026vcpu-\u003ekvm-\u003earch.kvmclock_update_rs))\n \t\t\t\tkvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);\n \t\t\telse\n \t\t\t\tkvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);\n+\t\t} else if (vcpu-\u003ecpu == -1) {\n+\t\t\tkvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);\n \t\t}\n \n \t\tif (vcpu-\u003ecpu != cpu)\n@@ -3276,6 +3516,9 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu,\n \tcase KVM_VCPU_TSC_OFFSET:\n \t\tr = 0;\n \t\tbreak;\n+\tcase KVM_VCPU_TSC_SCALE:\n+\t\tr = kvm_caps.has_tsc_control ? 0 : -ENXIO;\n+\t\tbreak;\n \tdefault:\n \t\tr = -ENXIO;\n \t}\n@@ -3296,6 +3539,21 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,\n \t\t\tbreak;\n \t\tr = 0;\n \t\tbreak;\n+\tcase KVM_VCPU_TSC_SCALE: {\n+\t\tstruct kvm_vcpu_tsc_scale scale;\n+\n+\t\tr = -ENXIO;\n+\t\tif (!kvm_caps.has_tsc_control)\n+\t\t\tbreak;\n+\n+\t\tscale.tsc_ratio = vcpu-\u003earch.l1_tsc_scaling_ratio;\n+\t\tscale.tsc_frac_bits = kvm_caps.tsc_scaling_ratio_frac_bits;\n+\t\tr = -EFAULT;\n+\t\tif (copy_to_user(uaddr, \u0026scale, sizeof(scale)))\n+\t\t\tbreak;\n+\t\tr = 0;\n+\t\tbreak;\n+\t}\n \tdefault:\n \t\tr = -ENXIO;\n \t}\n@@ -3323,8 +3581,8 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,\n \t\traw_spin_lock_irqsave(\u0026kvm-\u003earch.tsc_write_lock, flags);\n \n \t\tmatched = (vcpu-\u003earch.virtual_tsc_khz \u0026\u0026\n-\t\t\t   kvm-\u003earch.last_tsc_khz == vcpu-\u003earch.virtual_tsc_khz \u0026\u0026\n-\t\t\t   kvm-\u003earch.last_tsc_offset == offset);\n+\t\t\t   kvm-\u003earch.cur_tsc_khz == vcpu-\u003earch.virtual_tsc_khz \u0026\u0026\n+\t\t\t   kvm-\u003earch.cur_tsc_offset == offset);\n \n \t\ttsc = kvm_scale_tsc(rdtsc(), vcpu-\u003earch.l1_tsc_scaling_ratio) + offset;\n \t\tns = get_kvmclock_base_ns();\n@@ -3335,6 +3593,9 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,\n \t\tr = 0;\n \t\tbreak;\n \t}\n+\tcase KVM_VCPU_TSC_SCALE:\n+\t\tr = kvm_caps.has_tsc_control ? -EINVAL : -ENXIO;\n+\t\tbreak;\n \tdefault:\n \t\tr = -ENXIO;\n \t}\n@@ -3424,6 +3685,197 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,\n \t}\n }\n \n+#ifdef CONFIG_X86_64\n+static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)\n+{\n+\tstruct pvclock_vcpu_time_info hv_clock = {};\n+\tstruct kvm_arch *ka = \u0026v-\u003ekvm-\u003earch;\n+\tbool use_master_clock;\n+\tunsigned int seq;\n+\n+\t/*\n+\t * Construct the pvclock purely from the master clock state. The\n+\t * master mul/shift are computed for the guest TSC frequency, which\n+\t * in master clock mode is the frequency of every vCPU; only the\n+\t * tsc_timestamp is per-vCPU, translating the master snapshot into\n+\t * this vCPU's TSC domain via its scaling ratio and offset.\n+\t *\n+\t * Note, this deliberately does NOT invoke kvm_guest_time_update(),\n+\t * which would write the guest's pvclock pages: dirtying guest\n+\t * memory after the final KVM_RUN would break post-copy migration\n+\t * flows. The pvclock returned here describes the same clock as the\n+\t * guest-visible copy (the same linear function of the guest TSC),\n+\t * anchored at the current master clock snapshot.\n+\t *\n+\t * Translating the snapshot through the vCPU's *current* scaling\n+\t * ratio and offset is correct even if they changed after the\n+\t * snapshot was taken: the snapshot anchors a host TSC value, not\n+\t * a guest one. A frequency change whose masterclock update is\n+\t * still pending does leave stale mul/shift here, but that is the\n+\t * paused-VM migration path reading a frequency userspace itself\n+\t * has just changed — and the result fails safe, as the same-vCPU\n+\t * KVM_SET_CLOCK_GUEST on the destination rejects a mul/shift\n+\t * inconsistent with the vCPU's frequency with -ERANGE.\n+\t */\n+\tdo {\n+\t\tseq = read_seqcount_begin(\u0026ka-\u003epvclock_sc);\n+\n+\t\tuse_master_clock = ka-\u003euse_master_clock;\n+\t\tif (!use_master_clock)\n+\t\t\tcontinue;\n+\n+\t\thv_clock.tsc_timestamp = kvm_read_l1_tsc(v, ka-\u003emaster_cycle_now);\n+\t\thv_clock.system_time = ka-\u003emaster_kernel_ns + ka-\u003ekvmclock_offset;\n+\t\thv_clock.tsc_shift = ka-\u003emaster_tsc_shift;\n+\t\thv_clock.tsc_to_system_mul = ka-\u003emaster_tsc_mul;\n+\t\thv_clock.flags = READ_ONCE(ka-\u003eall_vcpus_matched_tsc) ?\n+\t\t\t\t PVCLOCK_TSC_STABLE_BIT : 0;\n+\t} while (read_seqcount_retry(\u0026ka-\u003epvclock_sc, seq));\n+\n+\tif (!use_master_clock)\n+\t\treturn -ENODATA;\n+\n+\tif (copy_to_user(argp, \u0026hv_clock, sizeof(hv_clock)))\n+\t\treturn -EFAULT;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Reverse the calculation in the hv_clock definition.\n+ *\n+ * time_ns = ( (cycles \u003c\u003c shift) * mul ) \u003e\u003e 32;\n+ * (although shift can be negative, so that's bad C)\n+ *\n+ * So for a single second,\n+ * NSEC_PER_SEC = ( ( FREQ_HZ \u003c\u003c shift) * mul ) \u003e\u003e 32\n+ * NSEC_PER_SEC \u003c\u003c 32 = ( FREQ_HZ \u003c\u003c shift ) * mul\n+ * ( NSEC_PER_SEC \u003c\u003c 32 ) / mul = FREQ_HZ \u003c\u003c shift\n+ * ( NSEC_PER_SEC \u003c\u003c 32 ) / mul ) \u003e\u003e shift = FREQ_HZ\n+ */\n+static u64 hvclock_to_hz(u32 mul, s8 shift)\n+{\n+\tu64 tm = NSEC_PER_SEC \u003c\u003c 32;\n+\n+\t/* Maximise precision. Shift left until the top bit is set */\n+\ttm \u003c\u003c= 2;\n+\tshift += 2;\n+\n+\t/* While 'mul' is even, increase the shift *after* the division */\n+\twhile (!(mul \u0026 1)) {\n+\t\tshift++;\n+\t\tmul \u003e\u003e= 1;\n+\t}\n+\n+\ttm /= mul;\n+\n+\tif (shift \u003e= 64)\n+\t\treturn 0;\n+\tif (shift \u003e 0)\n+\t\treturn tm \u003e\u003e shift;\n+\n+\t/*\n+\t * A left shift can overflow for absurd user-supplied mul/shift\n+\t * combinations; saturate (to a value which cannot itself overflow\n+\t * the rounding in the caller's kHz conversion) so the frequency\n+\t * check certainly rejects them.\n+\t */\n+\tif (shift \u003c= -64 || tm \u003e (U64_MAX \u003e\u003e 1) \u003e\u003e -shift)\n+\t\treturn U64_MAX \u003e\u003e 1;\n+\treturn tm \u003c\u003c -shift;\n+}\n+\n+static int kvm_vcpu_ioctl_set_clock_guest(struct kvm_vcpu *v, void __user *argp)\n+{\n+\tstruct pvclock_vcpu_time_info user_hv_clock;\n+\tstruct kvm *kvm = v-\u003ekvm;\n+\tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n+\tu64 curr_tsc_hz, user_tsc_hz;\n+\tu64 curr_tsc_khz, user_tsc_khz;\n+\tu64 user_clk_ns;\n+\tu64 guest_tsc;\n+\tint rc = 0;\n+\n+\tif (copy_from_user(\u0026user_hv_clock, argp, sizeof(user_hv_clock)))\n+\t\treturn -EFAULT;\n+\n+\tif (user_hv_clock.pad0 || user_hv_clock.pad[0] || user_hv_clock.pad[1])\n+\t\treturn -EINVAL;\n+\n+\tif (!user_hv_clock.tsc_to_system_mul)\n+\t\treturn -EINVAL;\n+\n+\tif (user_hv_clock.tsc_shift \u003c -31 || user_hv_clock.tsc_shift \u003e 31)\n+\t\treturn -EINVAL;\n+\n+\tuser_tsc_hz = hvclock_to_hz(user_hv_clock.tsc_to_system_mul,\n+\t\t\t\t    user_hv_clock.tsc_shift);\n+\n+\tkvm_hv_request_tsc_page_update(kvm);\n+\n+\t/*\n+\t * kvm_start_pvclock_update() takes tsc_write_lock and opens\n+\t * the pvclock seqcount; kvm_end_pvclock_update() closes both.\n+\t * All clock state modifications between them are atomic with\n+\t * respect to readers in kvm_guest_time_update().\n+\t */\n+\tkvm_start_pvclock_update(kvm);\n+\tpvclock_update_vm_gtod_copy(kvm);\n+\n+\tif (!ka-\u003euse_master_clock) {\n+\t\trc = -ENODATA;\n+\t\tgoto out;\n+\t}\n+\n+\t/*\n+\t * Nonzero, or pvclock_update_vm_gtod_copy() — which read it on\n+\t * this CPU, with interrupts still disabled — would have cleared\n+\t * use_master_clock above.\n+\t */\n+\tcurr_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;\n+\n+\tif (kvm_caps.has_tsc_control)\n+\t\tcurr_tsc_hz = kvm_scale_tsc(curr_tsc_hz,\n+\t\t\t\t\t    v-\u003earch.l1_tsc_scaling_ratio);\n+\n+\t/*\n+\t * The mul/shift in the provided pvclock structure encode the guest\n+\t * TSC frequency at which it was generated. Sanity-check that it is\n+\t * consistent with this vCPU's effective TSC frequency, allowing a\n+\t * discrepancy of 1 kHz either way since independently calibrated\n+\t * hosts will not measure precisely the same value even for the\n+\t * same nominal frequency. Compare in kHz: the reconstruction of\n+\t * each side's frequency in Hz carries a few Hz of rounding, which\n+\t * must not push two hosts calibrated exactly 1 kHz apart over the\n+\t * line.\n+\t */\n+\tuser_tsc_khz = DIV_ROUND_CLOSEST_ULL(user_tsc_hz, HZ_PER_KHZ);\n+\tcurr_tsc_khz = DIV_ROUND_CLOSEST_ULL(curr_tsc_hz, HZ_PER_KHZ);\n+\tif (user_tsc_khz + 1 \u003c curr_tsc_khz ||\n+\t    user_tsc_khz \u003e curr_tsc_khz + 1) {\n+\t\trc = -ERANGE;\n+\t\tgoto out;\n+\t}\n+\n+\t/*\n+\t * Calculate the guest TSC at the new reference point, and the\n+\t * corresponding KVM clock value according to user_hv_clock.\n+\t * Adjust kvmclock_offset so both definitions agree.\n+\t */\n+\tguest_tsc = kvm_read_l1_tsc(v, ka-\u003emaster_cycle_now);\n+\tif ((s64)(guest_tsc - user_hv_clock.tsc_timestamp) \u003c 0) {\n+\t\trc = -EINVAL;\n+\t\tgoto out;\n+\t}\n+\tuser_clk_ns = __pvclock_read_cycles(\u0026user_hv_clock, guest_tsc);\n+\tka-\u003ekvmclock_offset = user_clk_ns - ka-\u003emaster_kernel_ns;\n+\n+out:\n+\tkvm_end_pvclock_update(kvm);\n+\treturn rc;\n+}\n+#endif\n+\n long kvm_arch_vcpu_ioctl(struct file *filp,\n \t\t\t unsigned int ioctl, unsigned long arg)\n {\n@@ -3734,7 +4186,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,\n \t\tif (user_tsc_khz == 0)\n \t\t\tuser_tsc_khz = tsc_khz;\n \n-\t\tif (!kvm_set_tsc_khz(vcpu, user_tsc_khz))\n+\t\tif (!kvm_set_tsc_khz(vcpu, user_tsc_khz, false))\n \t\t\tr = 0;\n \n \t\tgoto out;\n@@ -3817,6 +4269,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,\n \t\tsrcu_read_unlock(\u0026vcpu-\u003ekvm-\u003esrcu, idx);\n \t\tbreak;\n \t}\n+#ifdef CONFIG_X86_64\n+\tcase KVM_SET_CLOCK_GUEST:\n+\t\tr = kvm_vcpu_ioctl_set_clock_guest(vcpu, argp);\n+\t\tbreak;\n+\tcase KVM_GET_CLOCK_GUEST:\n+\t\tr = kvm_vcpu_ioctl_get_clock_guest(vcpu, argp);\n+\t\tbreak;\n+#endif\n #ifdef CONFIG_KVM_HYPERV\n \tcase KVM_GET_SUPPORTED_HV_CPUID:\n \t\tr = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);\n@@ -4382,19 +4842,45 @@ static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp)\n \t * 'system_time' when 'data.clock' is very small.\n \t */\n \tif (data.flags \u0026 KVM_CLOCK_REALTIME) {\n-\t\tu64 now_real_ns = ktime_get_real_ns();\n+\t\tstruct system_time_snapshot snap = {};\n+\t\tu64 now_real_ns;\n+\n+\t\t/*\n+\t\t * Snapshot CLOCK_REALTIME and CLOCK_MONOTONIC_RAW at the\n+\t\t * same instant, so that the elapsed time applied to\n+\t\t * data.clock and the reference point the result is anchored\n+\t\t * to are coherent.\n+\t\t */\n+\t\tktime_get_snapshot_id(CLOCK_REALTIME, \u0026snap);\n+\t\tnow_real_ns = ktime_to_ns(snap.systime);\n+\t\tnow_raw_ns = ktime_to_ns(ktime_mono_to_any(snap.monoraw,\n+\t\t\t\t\t\t\t   TK_OFFS_BOOT));\n+\n+\t\t/*\n+\t\t * When the master clock is in use, anchor at its reference\n+\t\t * point instead, projecting the realtime value back to the\n+\t\t * same instant. The two clocks tick at the same rate across\n+\t\t * the few ns in between, give or take NTP slew. Skip the\n+\t\t * projection in the absurd case that it would take a\n+\t\t * CLOCK_REALTIME set to within moments of the 1970 epoch\n+\t\t * (legal with CAP_SYS_TIME) below zero and wrap.\n+\t\t */\n+\t\tif (ka-\u003euse_master_clock \u0026\u0026\n+\t\t    now_real_ns \u003e= now_raw_ns - ka-\u003emaster_kernel_ns) {\n+\t\t\tnow_real_ns -= now_raw_ns - ka-\u003emaster_kernel_ns;\n+\t\t\tnow_raw_ns = ka-\u003emaster_kernel_ns;\n+\t\t}\n \n \t\t/*\n \t\t * Avoid stepping the kvmclock backwards.\n \t\t */\n \t\tif (now_real_ns \u003e data.realtime)\n \t\t\tdata.clock += now_real_ns - data.realtime;\n-\t}\n-\n-\tif (ka-\u003euse_master_clock)\n+\t} else if (ka-\u003euse_master_clock) {\n \t\tnow_raw_ns = ka-\u003emaster_kernel_ns;\n-\telse\n+\t} else {\n \t\tnow_raw_ns = get_kvmclock_base_ns();\n+\t}\n \tka-\u003ekvmclock_offset = data.clock - now_raw_ns;\n \tkvm_end_pvclock_update(kvm);\n \treturn 0;\n@@ -6752,7 +7238,14 @@ static void kvm_hyperv_tsc_notifier(void)\n \tkvm_caps.max_guest_tsc_khz = tsc_khz;\n \n \tlist_for_each_entry(kvm, \u0026vm_list, vm_list) {\n-\t\t__kvm_start_pvclock_update(kvm);\n+\t\t/*\n+\t\t * Invalidate the Hyper-V TSC page explicitly: the update\n+\t\t * below consumes any pending KVM_REQ_MASTERCLOCK_UPDATE,\n+\t\t * which would otherwise have refreshed the page from\n+\t\t * kvm_update_masterclock().\n+\t\t */\n+\t\tkvm_hv_request_tsc_page_update(kvm);\n+\t\t__kvm_start_pvclock_update(kvm, NULL);\n \t\tpvclock_update_vm_gtod_copy(kvm);\n \t\tkvm_end_pvclock_update(kvm);\n \t}\n@@ -6926,17 +7419,21 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);\n static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,\n \t\t\t       void *priv)\n {\n-\tstruct pvclock_gtod_data *gtod = \u0026pvclock_gtod_data;\n \tstruct timekeeper *tk = priv;\n \n-\tupdate_pvclock_gtod(tk);\n+\t/*\n+\t * Pairs with the READ_ONCE() in the lockless readers; the race is\n+\t * benign by design, relying on eventual consistency (the notifier\n+\t * fires on every timekeeping update).\n+\t */\n+\tWRITE_ONCE(kvm_host_vclock_mode, tk-\u003etkr_mono.clock-\u003evdso_clock_mode);\n \n \t/*\n \t * Disable master clock if host does not trust, or does not use,\n \t * TSC based clocksource. Delegate queue_work() to irq_work as\n \t * this is invoked with tk_core.seq write held.\n \t */\n-\tif (!gtod_is_based_on_tsc(gtod-\u003eclock.vclock_mode) \u0026\u0026\n+\tif (!gtod_is_based_on_tsc(kvm_host_vclock_mode) \u0026\u0026\n \t    atomic_read(\u0026kvm_guest_has_master_clock) != 0)\n \t\tirq_work_queue(\u0026pvclock_irq_work);\n \treturn 0;\n@@ -8158,8 +8655,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)\n \t\t\tkvm_mmu_free_obsolete_roots(vcpu);\n \t\tif (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))\n \t\t\t__kvm_migrate_timers(vcpu);\n-\t\tif (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))\n-\t\t\tkvm_update_masterclock(vcpu-\u003ekvm);\n+\t\tif (kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))\n+\t\t\tkvm_update_masterclock(vcpu-\u003ekvm, vcpu);\n \t\tif (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))\n \t\t\tkvm_gen_kvmclock_update(vcpu);\n \t\tif (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {\n@@ -9502,7 +9999,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n \tkvm_xen_init_vcpu(vcpu);\n \tvcpu_load(vcpu);\n \tkvm_vcpu_after_set_cpuid(vcpu);\n-\tkvm_set_tsc_khz(vcpu, vcpu-\u003ekvm-\u003earch.default_tsc_khz);\n+\tkvm_set_tsc_khz(vcpu, vcpu-\u003ekvm-\u003earch.default_tsc_khz, true);\n \tkvm_vcpu_reset(vcpu, false);\n \tkvm_init_mmu(vcpu);\n \tvcpu_put(vcpu);\n@@ -9527,12 +10024,39 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n \n void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)\n {\n-\tif (mutex_lock_killable(\u0026vcpu-\u003emutex))\n+\tif (mutex_lock_killable(\u0026vcpu-\u003emutex)) {\n+\t\t/*\n+\t\t * The new vCPU is already counted in online_vcpus but has\n+\t\t * not been synchronized. Nothing recomputes the cached\n+\t\t * matched state against the raised count until the next\n+\t\t * synchronization, so clear it here rather than leave the\n+\t\t * clock advertised as matched while an unmatched vCPU is\n+\t\t * runnable. It heals when this vCPU first synchronizes.\n+\t\t */\n+\t\tstruct kvm_arch *ka = \u0026vcpu-\u003ekvm-\u003earch;\n+\t\tunsigned long flags;\n+\n+\t\traw_spin_lock_irqsave(\u0026ka-\u003etsc_write_lock, flags);\n+\t\tWRITE_ONCE(ka-\u003eall_vcpus_matched_tsc, false);\n+\t\tka-\u003eall_vcpus_matched_freq = false;\n+\t\traw_spin_unlock_irqrestore(\u0026ka-\u003etsc_write_lock, flags);\n \t\treturn;\n+\t}\n \tvcpu_load(vcpu);\n-\tkvm_synchronize_tsc(vcpu, NULL);\n-\tif (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))\n-\t\tkvm_update_masterclock(vcpu-\u003ekvm);\n+\tkvm_synchronize_tsc(vcpu, NULL, false);\n+\n+\t/*\n+\t * Refresh the VM-creation masterclock snapshot (see\n+\t * kvm_arch_init_vm), synchronously so that it is valid even for\n+\t * userspace which queries the clock before ever running a vCPU.\n+\t * Likewise service any masterclock update the synchronization\n+\t * above requested on this vCPU, which would otherwise languish\n+\t * until it first enters the guest.\n+\t */\n+\tif (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu) ||\n+\t    vcpu-\u003evcpu_idx == 0)\n+\t\tkvm_update_masterclock(vcpu-\u003ekvm, NULL);\n+\n \tvcpu_put(vcpu);\n \n \t/* poll control enabled by default */\n@@ -9782,7 +10306,7 @@ int kvm_arch_enable_virtualization_cpu(void)\n {\n \tstruct kvm *kvm;\n \tstruct kvm_vcpu *vcpu;\n-\tunsigned long i;\n+\tunsigned long i, flags;\n \tint ret;\n \tu64 local_tsc;\n \tu64 max_tsc = 0;\n@@ -9853,6 +10377,44 @@ int kvm_arch_enable_virtualization_cpu(void)\n \tif (backwards_tsc) {\n \t\tu64 delta_cyc = max_tsc - local_tsc;\n \t\tlist_for_each_entry(kvm, \u0026vm_list, vm_list) {\n+\t\t\t/*\n+\t\t\t * Hold tsc_write_lock across the per-vCPU adjustments\n+\t\t\t * AND the generation reference offset adjustment, so\n+\t\t\t * that a concurrent TSC synchronization cannot observe\n+\t\t\t * one without the other (it would compute an offset\n+\t\t\t * with the delta applied twice, or not at all). The\n+\t\t\t * consume of tsc_offset_adjustment in\n+\t\t\t * kvm_arch_vcpu_load() remains outside the lock, as\n+\t\t\t * it always was; its races are with vcpu_put/load\n+\t\t\t * ordering, not with the generation state.\n+\t\t\t *\n+\t\t\t * The generation's reference offset is adjusted by the\n+\t\t\t * same (guest-scaled, as adjust_tsc_offset_host()\n+\t\t\t * does for each vCPU) delta, so that future\n+\t\t\t * KVM_SET_TSC / vCPU creation still matches against\n+\t\t\t * the adjusted TSC timeline.\n+\t\t\t *\n+\t\t\t * The recorded {cur_tsc_nsec, cur_tsc_write} pair is\n+\t\t\t * left alone, and ends up stale by the sleep period:\n+\t\t\t * cur_tsc_nsec is CLOCK_BOOTTIME, which has the sleep\n+\t\t\t * injected on resume, while the guest TSC (kept\n+\t\t\t * continuous across the host TSC jump) does not\n+\t\t\t * advance during the sleep. It cannot be re-anchored\n+\t\t\t * here because, as noted above, timekeeping has not\n+\t\t\t * yet been resumed. The 1-second matching window\n+\t\t\t * therefore fails to match across a longer sleep,\n+\t\t\t * and the next nonzero TSC write opens a fresh,\n+\t\t\t * coherent generation. A forced synchronization\n+\t\t\t * (vCPU creation, or a zero write) bypasses the\n+\t\t\t * window and does extrapolate along the stale line,\n+\t\t\t * overshooting by the sleep period — but it installs\n+\t\t\t * the compensated offset, so the vCPU's actual TSC\n+\t\t\t * is correct; only last_guest_tsc overshoots, which\n+\t\t\t * matters only if the TSC turns unstable before the\n+\t\t\t * vCPU first enters the guest, exactly as it did\n+\t\t\t * before this accounting existed.\n+\t\t\t */\n+\t\t\traw_spin_lock_irqsave(\u0026kvm-\u003earch.tsc_write_lock, flags);\n \t\t\tkvm-\u003earch.backwards_tsc_observed = true;\n \t\t\tkvm_for_each_vcpu(i, vcpu, kvm) {\n \t\t\t\tvcpu-\u003earch.tsc_offset_adjustment += delta_cyc;\n@@ -9860,14 +10422,10 @@ int kvm_arch_enable_virtualization_cpu(void)\n \t\t\t\tkvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);\n \t\t\t}\n \n-\t\t\t/*\n-\t\t\t * We have to disable TSC offset matching.. if you were\n-\t\t\t * booting a VM while issuing an S4 host suspend....\n-\t\t\t * you may have some problem.  Solving this issue is\n-\t\t\t * left as an exercise to the reader.\n-\t\t\t */\n-\t\t\tkvm-\u003earch.last_tsc_nsec = 0;\n-\t\t\tkvm-\u003earch.last_tsc_write = 0;\n+\t\t\tkvm-\u003earch.cur_tsc_offset +=\n+\t\t\t\tkvm_scale_tsc(delta_cyc,\n+\t\t\t\t\t      kvm-\u003earch.cur_tsc_scaling_ratio);\n+\t\t\traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n \t\t}\n \n \t}\n@@ -9937,6 +10495,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n {\n \tint ret;\n \tunsigned long flags;\n+\tu64 kvmclock_host_tsc;\n+\ts64 kvmclock_ns;\n \n \tif (!kvm_is_vm_type_supported(type))\n \t\treturn -EINVAL;\n@@ -9968,17 +10528,68 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n \tseqcount_raw_spinlock_init(\u0026kvm-\u003earch.pvclock_sc, \u0026kvm-\u003earch.tsc_write_lock);\n \tratelimit_state_init(\u0026kvm-\u003earch.kvmclock_update_rs, HZ, 10);\n \tratelimit_set_flags(\u0026kvm-\u003earch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEASE);\n-\tkvm-\u003earch.kvmclock_offset = -get_kvmclock_base_ns();\n-\n-\traw_spin_lock_irqsave(\u0026kvm-\u003earch.tsc_write_lock, flags);\n-\tpvclock_update_vm_gtod_copy(kvm);\n-\traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n \n \tkvm-\u003earch.default_tsc_khz = max_tsc_khz ? : tsc_khz;\n \tkvm-\u003earch.apic_bus_cycle_ns = APIC_BUS_CYCLE_NS_DEFAULT;\n \tkvm-\u003earch.guest_can_read_msr_platform_info = true;\n \tkvm-\u003earch.enable_pmu = enable_pmu \u0026\u0026 !kvm-\u003earch.has_protected_pmu;\n \n+\tkvm-\u003earch.all_vcpus_matched_freq = true;\n+\t/*\n+\t * Start with all (zero) vCPUs considered matched, so that a VM whose\n+\t * vCPUs never reach kvm_track_tsc_matching() — notably when the guest\n+\t * TSC is protected (TDX, SNP Secure TSC) and __kvm_synchronize_tsc()\n+\t * returns early — is still eligible for PVCLOCK_TSC_STABLE_BIT. The\n+\t * scaling ratio must then also be initialized: with vcpus_matched\n+\t * now true here, pvclock_update_vm_gtod_copy() reaches the scaling\n+\t * path, and a zero ratio would zero tsc_hz and turn the master\n+\t * clock straight back off (permanently so for protected-TSC guests,\n+\t * which never write the ratio in __kvm_synchronize_tsc()).\n+\t */\n+\tkvm-\u003earch.all_vcpus_matched_tsc = true;\n+\tkvm-\u003earch.cur_tsc_scaling_ratio = kvm_caps.default_tsc_scaling_ratio;\n+\n+\traw_spin_lock_irqsave(\u0026kvm-\u003earch.tsc_write_lock, flags);\n+\n+\t/*\n+\t * Establish an initial TSC generation so that the master clock\n+\t * snapshot taken below is immediately valid and KVM_GET_CLOCK\n+\t * works before any vCPU exists. The snapshot is refreshed again\n+\t * when the first vCPU is created, in case the host clocksource\n+\t * changed (and changed back) in between: pvclock_gtod_update_fn()\n+\t * does not notify a VM with no vCPUs.\n+\t *\n+\t * This generation is deliberately not matchable: cur_tsc_khz is\n+\t * left at zero, which no vCPU frequency ever equals, so the first\n+\t * vCPU opens its own generation with its TSC starting at zero,\n+\t * exactly as it always has. Letting it match would make the first\n+\t * vCPU's TSC start at the cycles elapsed since KVM_CREATE_VM — a\n+\t * silent guest-visible change over an unbounded window — and\n+\t * would hand it this offset verbatim even when a host suspend\n+\t * reset the TSC in between, since the backwards-TSC compensation\n+\t * in kvm_arch_enable_virtualization_cpu() detects the jump only\n+\t * through existing vCPUs.\n+\t */\n+#ifdef CONFIG_X86_64\n+\tif (!kvm_get_time_and_clockread(\u0026kvmclock_ns, \u0026kvmclock_host_tsc))\n+#endif\n+\t{\n+\t\t/*\n+\t\t * If not simultaneous, we want the TSC to be zero slightly\n+\t\t * *after* the kvmclock is zero.\n+\t\t */\n+\t\tkvmclock_ns = get_kvmclock_base_ns();\n+\t\tkvmclock_host_tsc = rdtsc();\n+\t}\n+\tkvm-\u003earch.cur_tsc_write = 0;\n+\tkvm-\u003earch.cur_tsc_offset = -(s64)kvmclock_host_tsc;\n+\tkvm-\u003earch.cur_tsc_nsec = kvmclock_ns;\n+\tkvm-\u003earch.cur_tsc_generation = 1;\n+\tkvm-\u003earch.kvmclock_offset = -kvmclock_ns;\n+\n+\tpvclock_update_vm_gtod_copy(kvm);\n+\traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n+\n #if IS_ENABLED(CONFIG_HYPERV)\n \tspin_lock_init(\u0026kvm-\u003earch.hv_root_tdp_lock);\n \tkvm-\u003earch.hv_root_tdp = INVALID_PAGE;\ndiff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h\nindex 436e2fb1396c46..de4c86ea5a7de6 100644\n--- a/arch/x86/kvm/x86.h\n+++ b/arch/x86/kvm/x86.h\n@@ -330,7 +330,7 @@ uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm);\n bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);\n int kvm_guest_time_update(struct kvm_vcpu *v);\n \n-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value);\n+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated);\n u64 kvm_scale_tsc(u64 tsc, u64 ratio);\n u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);\n u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier);\ndiff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c\nindex 6aa00f746cba39..dae43acb3cc37d 100644\n--- a/arch/x86/kvm/xen.c\n+++ b/arch/x86/kvm/xen.c\n@@ -188,7 +188,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,\n \tstruct kvm_vcpu_xen *xen = \u0026vcpu-\u003earch.xen;\n \tint64_t kernel_now, delta;\n \tuint64_t guest_now;\n-\tint r = -EOPNOTSUPP;\n+\tbool fallback = true;\n \n \t/*\n \t * The guest provides the requested timeout in absolute nanoseconds\n@@ -210,6 +210,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,\n \tdo {\n \t\tstruct pvclock_vcpu_time_info hv_clock;\n \t\tuint64_t host_tsc, guest_tsc;\n+\t\tint r = -EOPNOTSUPP;\n \n \t\tif (!cpu_feature_enabled(X86_FEATURE_CONSTANT_TSC) ||\n \t\t    !vcpu-\u003ekvm-\u003earch.use_master_clock)\n@@ -230,43 +231,40 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,\n \t\tif (r)\n \t\t\tbreak;\n \n+\t\t/*\n+\t\t * With use_master_clock set, the clocksource was TSC-based\n+\t\t * when the master clock was last updated. The clockread can\n+\t\t * only fail here if the clocksource has changed since, in\n+\t\t * which case a masterclock update is already pending and\n+\t\t * get_kvmclock_ns() returns the raw-clock fallback value —\n+\t\t * continuous with the last valid snapshot, which is as good\n+\t\t * as it gets in that transient window.\n+\t\t */\n \t\tif (!IS_ENABLED(CONFIG_64BIT) ||\n-\t\t    !kvm_get_monotonic_and_clockread(\u0026kernel_now, \u0026host_tsc)) {\n-\t\t\t/*\n-\t\t\t * Don't fall back to get_kvmclock_ns() because it's\n-\t\t\t * broken; it has a systemic error in its results\n-\t\t\t * because it scales directly from host TSC to\n-\t\t\t * nanoseconds, and doesn't scale first to guest TSC\n-\t\t\t * and *then* to nanoseconds as the guest does.\n-\t\t\t *\n-\t\t\t * There is a small error introduced here because time\n-\t\t\t * continues to elapse between the ktime_get() and the\n-\t\t\t * subsequent rdtsc(). But not the systemic drift due\n-\t\t\t * to get_kvmclock_ns().\n-\t\t\t */\n-\t\t\tkernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */\n-\t\t\thost_tsc = rdtsc();\n-\t\t}\n+\t\t    !kvm_get_monotonic_and_clockread(\u0026kernel_now, \u0026host_tsc))\n+\t\t\tbreak;\n \n \t\t/* Calculate the guest kvmclock as the guest would do it. */\n \t\tguest_tsc = kvm_read_l1_tsc(vcpu, host_tsc);\n \t\tguest_now = __pvclock_read_cycles(\u0026hv_clock, guest_tsc);\n+\t\tfallback = false;\n \t} while (0);\n \n-\tif (r) {\n+\tif (fallback) {\n \t\t/*\n-\t\t * Without CONSTANT_TSC, get_kvmclock_ns() is the only option.\n+\t\t * Without CONSTANT_TSC and the master clock,\n+\t\t * get_kvmclock_ns() is the only option.\n \t\t *\n \t\t * Also if the guest PV clock hasn't been set up yet, as is\n \t\t * likely to be the case during migration when the vCPU has\n \t\t * not been run yet. It would be possible to calculate the\n \t\t * scaling factors properly in that case but there's not much\n-\t\t * point in doing so. The get_kvmclock_ns() drift accumulates\n-\t\t * over time, so it's OK to use it at startup. Besides, on\n-\t\t * migration there's going to be a little bit of skew in the\n-\t\t * precise moment at which timers fire anyway. Often they'll\n-\t\t * be in the \"past\" by the time the VM is running again after\n-\t\t * migration.\n+\t\t * point in doing so. Without the master clock, the\n+\t\t * get_kvmclock_ns() drift accumulates over time, so it's OK\n+\t\t * to use it at startup. Besides, on migration there's going\n+\t\t * to be a little bit of skew in the precise moment at which\n+\t\t * timers fire anyway. Often they'll be in the \"past\" by the\n+\t\t * time the VM is running again after migration.\n \t\t */\n \t\tguest_now = get_kvmclock_ns(vcpu-\u003ekvm);\n \t\tkernel_now = ktime_get();\ndiff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h\nindex 8dff2fc1972e97..1349387cceb040 100644\n--- a/include/uapi/linux/kvm.h\n+++ b/include/uapi/linux/kvm.h\n@@ -1000,6 +1000,7 @@ struct kvm_enable_cap {\n #define KVM_CAP_PPC_COMPAT_CAPS 250\n #define KVM_CAP_ARM_PMU_V3_STRICT 251\n #define KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES 252\n+#define KVM_CAP_CLOCK_GUEST 253\n \n struct kvm_irq_routing_irqchip {\n \t__u32 irqchip;\n@@ -1690,4 +1691,7 @@ struct kvm_pre_fault_memory {\n \t__u64 padding[5];\n };\n \n+#define KVM_SET_CLOCK_GUEST\t_IOW(KVMIO, 0xd6, struct pvclock_vcpu_time_info)\n+#define KVM_GET_CLOCK_GUEST\t_IOR(KVMIO, 0xd7, struct pvclock_vcpu_time_info)\n+\n #endif /* __LINUX_KVM_H */\ndiff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh\nindex f18b00843df3ff..51a722198997da 100755\n--- a/scripts/xen-hypercalls.sh\n+++ b/scripts/xen-hypercalls.sh\n@@ -5,7 +5,7 @@ shift\n in=\"$@\"\n \n for i in $in; do\n-\teval $CPP $LINUXINCLUDE -dD -imacros \"$i\" -x c /dev/null\n+\teval $CPP -D__KERNEL__ $LINUXINCLUDE -dD -imacros \"$i\" -x c /dev/null\n done | \\\n awk '$1 == \"#define\" \u0026\u0026 $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 }\n \tEND {   print \"/* auto-generated by scripts/xen-hypercall.sh */\"\ndiff --git a/tools/arch/x86/include/asm/pvclock-abi.h b/tools/arch/x86/include/asm/pvclock-abi.h\nindex b9fece5fc96d6f..6d70cf64036293 100644\n--- a/tools/arch/x86/include/asm/pvclock-abi.h\n+++ b/tools/arch/x86/include/asm/pvclock-abi.h\n@@ -1,6 +1,9 @@\n-/* SPDX-License-Identifier: GPL-2.0 */\n+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */\n #ifndef _ASM_X86_PVCLOCK_ABI_H\n #define _ASM_X86_PVCLOCK_ABI_H\n+\n+#include \u003clinux/types.h\u003e\n+\n #ifndef __ASSEMBLER__\n \n /*\n@@ -24,20 +27,20 @@\n  */\n \n struct pvclock_vcpu_time_info {\n-\tu32   version;\n-\tu32   pad0;\n-\tu64   tsc_timestamp;\n-\tu64   system_time;\n-\tu32   tsc_to_system_mul;\n-\ts8    tsc_shift;\n-\tu8    flags;\n-\tu8    pad[2];\n+\t__u32   version;\n+\t__u32   pad0;\n+\t__u64   tsc_timestamp;\n+\t__u64   system_time;\n+\t__u32   tsc_to_system_mul;\n+\t__s8    tsc_shift;\n+\t__u8    flags;\n+\t__u8    pad[2];\n } __attribute__((__packed__)); /* 32 bytes */\n \n struct pvclock_wall_clock {\n-\tu32   version;\n-\tu32   sec;\n-\tu32   nsec;\n+\t__u32   version;\n+\t__u32   sec;\n+\t__u32   nsec;\n } __attribute__((__packed__));\n \n #define PVCLOCK_TSC_STABLE_BIT\t(1 \u003c\u003c 0)\ndiff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h\nindex 1585ec8040666e..7b3afccb6cb237 100644\n--- a/tools/arch/x86/include/uapi/asm/kvm.h\n+++ b/tools/arch/x86/include/uapi/asm/kvm.h\n@@ -963,6 +963,12 @@ struct kvm_hyperv_eventfd {\n /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */\n #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */\n #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */\n+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */\n+\n+struct kvm_vcpu_tsc_scale {\n+\t__u64 tsc_ratio;\n+\t__u64 tsc_frac_bits;\n+};\n \n /* x86-specific KVM_EXIT_HYPERCALL flags. */\n #define KVM_EXIT_HYPERCALL_LONG_MODE\t_BITULL(0)\ndiff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm\nindex 888a7530a2808f..fd063806a7fb96 100644\n--- a/tools/testing/selftests/kvm/Makefile.kvm\n+++ b/tools/testing/selftests/kvm/Makefile.kvm\n@@ -95,6 +95,7 @@ TEST_GEN_PROGS_x86 += x86/hyperv_tlb_flush\n TEST_GEN_PROGS_x86 += x86/kvm_clock_test\n TEST_GEN_PROGS_x86 += x86/kvm_pv_test\n TEST_GEN_PROGS_x86 += x86/kvm_buslock_test\n+TEST_GEN_PROGS_x86 += x86/masterclock_offset_test\n TEST_GEN_PROGS_x86 += x86/monitor_mwait_test\n TEST_GEN_PROGS_x86 += x86/msrs_test\n TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test\n@@ -113,6 +114,8 @@ TEST_GEN_PROGS_x86 += x86/pmu_counters_test\n TEST_GEN_PROGS_x86 += x86/pmu_event_filter_test\n TEST_GEN_PROGS_x86 += x86/private_mem_conversions_test\n TEST_GEN_PROGS_x86 += x86/private_mem_kvm_exits_test\n+TEST_GEN_PROGS_x86 += x86/pvclock_migration_test\n+TEST_GEN_PROGS_x86 += x86/pvclock_test\n TEST_GEN_PROGS_x86 += x86/save_restore_pf_stress_test\n TEST_GEN_PROGS_x86 += x86/set_boot_cpu_id\n TEST_GEN_PROGS_x86 += x86/set_sregs_test\n@@ -148,7 +151,10 @@ TEST_GEN_PROGS_x86 += x86/xcr0_cpuid_test\n TEST_GEN_PROGS_x86 += x86/xss_msr_test\n TEST_GEN_PROGS_x86 += x86/debug_regs\n TEST_GEN_PROGS_x86 += x86/tsc_msrs_test\n+TEST_GEN_PROGS_x86 += x86/tsc_user_set_test\n TEST_GEN_PROGS_x86 += x86/vmx_pmu_caps_test\n+TEST_GEN_PROGS_x86 += x86/xen_cpuid_timing_test\n+TEST_GEN_PROGS_x86 += x86/xen_migration_test\n TEST_GEN_PROGS_x86 += x86/xen_shinfo_test\n TEST_GEN_PROGS_x86 += x86/xen_vmcall_test\n TEST_GEN_PROGS_x86 += x86/sev_dbg_test\ndiff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h\nindex 5898a277a2e01c..4062bdb3271604 100644\n--- a/tools/testing/selftests/kvm/include/x86/processor.h\n+++ b/tools/testing/selftests/kvm/include/x86/processor.h\n@@ -12,6 +12,7 @@\n \n #include \u003casm/msr-index.h\u003e\n #include \u003casm/prctl.h\u003e\n+#include \u003casm/pvclock-abi.h\u003e\n \n #include \u003clinux/kvm_para.h\u003e\n #include \u003clinux/stringify.h\u003e\n@@ -1029,6 +1030,55 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)\n \tvcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs);\n }\n \n+static inline int __vcpu_get_clock_guest(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t struct pvclock_vcpu_time_info *pvti)\n+{\n+\treturn __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);\n+}\n+\n+static inline void vcpu_get_clock_guest(struct kvm_vcpu *vcpu,\n+\t\t\t\t\tstruct pvclock_vcpu_time_info *pvti)\n+{\n+\tvcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);\n+}\n+\n+static inline int __vcpu_set_clock_guest(struct kvm_vcpu *vcpu,\n+\t\t\t\t\t struct pvclock_vcpu_time_info *pvti)\n+{\n+\treturn __vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);\n+}\n+\n+static inline void vcpu_set_clock_guest(struct kvm_vcpu *vcpu,\n+\t\t\t\t\tstruct pvclock_vcpu_time_info *pvti)\n+{\n+\tvcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);\n+}\n+\n+static inline u64 vcpu_get_tsc_offset(struct kvm_vcpu *vcpu)\n+{\n+\tu64 offset;\n+\n+\tvcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,\n+\t\t\t     \u0026offset);\n+\treturn offset;\n+}\n+\n+static inline void vcpu_set_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)\n+{\n+\tvcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,\n+\t\t\t     \u0026offset);\n+}\n+\n+static inline void vm_get_clock(struct kvm_vm *vm, struct kvm_clock_data *data)\n+{\n+\tvm_ioctl(vm, KVM_GET_CLOCK, data);\n+}\n+\n+static inline void vm_set_clock(struct kvm_vm *vm, struct kvm_clock_data *data)\n+{\n+\tvm_ioctl(vm, KVM_SET_CLOCK, data);\n+}\n+\n const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,\n \t\t\t\t\t       u32 function, u32 index);\n const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);\ndiff --git a/tools/testing/selftests/kvm/x86/masterclock_offset_test.c b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c\nnew file mode 100644\nindex 00000000000000..faf81872538ebb\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c\n@@ -0,0 +1,203 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Test that KVM master clock mode works with different TSC offsets\n+ * as long as all vCPUs have the same TSC frequency.\n+ */\n+#include \u003cstring.h\u003e\n+\n+#include \"test_util.h\"\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+#include \u003casm/pvclock.h\u003e\n+#include \u003casm/pvclock-abi.h\u003e\n+\n+#define KVMCLOCK_GPA\t0xc0000000ull\n+#define TSC_OFFSET\t(1000000000ULL)\n+\n+#define NR_VCPUS\t3\n+\n+/* Read the per-vCPU pvclocks in an order other than creation order. */\n+static const int vcpu_order[NR_VCPUS] = {0, 2, 1};\n+\n+static void guest_code(u64 pvti_gpa)\n+{\n+\twrmsr(MSR_KVM_SYSTEM_TIME_NEW, pvti_gpa | KVM_MSR_ENABLED);\n+\tfor (;;)\n+\t\tGUEST_SYNC(0);\n+}\n+\n+static void get_pvtis(struct kvm_vcpu **vcpus,\n+\t\t      struct pvclock_vcpu_time_info *pvti)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tint idx = vcpu_order[i];\n+\n+\t\tvcpu_get_clock_guest(vcpus[idx], \u0026pvti[idx]);\n+\t\tpr_info(\"vCPU %d: tsc_timestamp=%lu system_time=%lu \"\n+\t\t\t\"mul=%u shift=%d flags=0x%x\\n\",\n+\t\t\tidx, (unsigned long)pvti[idx].tsc_timestamp,\n+\t\t\t(unsigned long)pvti[idx].system_time,\n+\t\t\tpvti[idx].tsc_to_system_mul, pvti[idx].tsc_shift,\n+\t\t\tpvti[idx].flags);\n+\t}\n+}\n+\n+/*\n+ * Read the host TSC once and feed it through each vCPU's pvclock\n+ * (adding each vCPU's TSC offset). All must compute exactly the same\n+ * kvmclock value.\n+ */\n+static void assert_pvclocks_match(struct pvclock_vcpu_time_info *pvti,\n+\t\t\t\t  u64 offset0, const char *what)\n+{\n+\tu64 host_tsc, clk0, clk1, clk2;\n+\n+\thost_tsc = rdtsc();\n+\tclk0 = __pvclock_read_cycles(\u0026pvti[0], host_tsc + offset0);\n+\tclk1 = __pvclock_read_cycles(\u0026pvti[1], host_tsc + offset0);\n+\tclk2 = __pvclock_read_cycles(\u0026pvti[2], host_tsc + offset0 + TSC_OFFSET);\n+\n+\tpr_info(\"%s: kvmclock via vCPU 0: %lu ns, vCPU 1: %lu ns, vCPU 2: %lu ns\\n\",\n+\t\twhat, (unsigned long)clk0, (unsigned long)clk1,\n+\t\t(unsigned long)clk2);\n+\tTEST_ASSERT(clk0 == clk1 \u0026\u0026 clk0 == clk2,\n+\t\t    \"%s: kvmclock from all vCPUs should match exactly \"\n+\t\t    \"(0: %lu, 1: %lu, 2: %lu)\", what, (unsigned long)clk0,\n+\t\t    (unsigned long)clk1, (unsigned long)clk2);\n+}\n+\n+static void test_masterclock_active(struct kvm_vm *vm,\n+\t\t\t\t    struct kvm_clock_data *clock)\n+{\n+\tmemset(clock, 0, sizeof(*clock));\n+\tvm_get_clock(vm, clock);\n+\tpr_info(\"KVM_GET_CLOCK flags: 0x%x\\n\", clock-\u003eflags);\n+\tTEST_ASSERT(clock-\u003eflags \u0026 KVM_CLOCK_HOST_TSC,\n+\t\t    \"Master clock should be active, flags=0x%x\", clock-\u003eflags);\n+\tTEST_ASSERT(clock-\u003eflags \u0026 KVM_CLOCK_TSC_STABLE,\n+\t\t    \"KVM_CLOCK_TSC_STABLE should be set, flags=0x%x\",\n+\t\t    clock-\u003eflags);\n+}\n+\n+static void test_offset_consistency(struct kvm_vcpu **vcpus,\n+\t\t\t\t    struct pvclock_vcpu_time_info *pvti,\n+\t\t\t\t    u64 offset0)\n+{\n+\tu64 gtsc0, gtsc1, gtsc2;\n+\n+\tget_pvtis(vcpus, pvti);\n+\n+\t/* Read guest TSCs: should see (0+OFF) \u003c 2 \u003c (1+OFF) */\n+\tgtsc0 = vcpu_get_msr(vcpus[0], MSR_IA32_TSC);\n+\tgtsc2 = vcpu_get_msr(vcpus[2], MSR_IA32_TSC);\n+\tgtsc1 = vcpu_get_msr(vcpus[1], MSR_IA32_TSC);\n+\tpr_info(\"Guest TSCs: vcpu0=%lu vcpu2=%lu vcpu1=%lu\\n\",\n+\t\t(unsigned long)gtsc0, (unsigned long)gtsc2,\n+\t\t(unsigned long)gtsc1);\n+\tTEST_ASSERT(gtsc0 + TSC_OFFSET \u003c gtsc2 \u0026\u0026 gtsc2 \u003c gtsc1 + TSC_OFFSET,\n+\t\t    \"Expected (vcpu0+OFF) \u003c vcpu2 \u003c (vcpu1+OFF)\");\n+\n+\t/* PVCLOCK_TSC_STABLE_BIT should NOT be set (offsets differ) */\n+\tTEST_ASSERT(!(pvti[2].flags \u0026 PVCLOCK_TSC_STABLE_BIT),\n+\t\t    \"PVCLOCK_TSC_STABLE_BIT should NOT be set, flags=0x%x\",\n+\t\t    pvti[2].flags);\n+\n+\t/* Same mul/shift */\n+\tTEST_ASSERT(pvti[0].tsc_to_system_mul == pvti[1].tsc_to_system_mul \u0026\u0026\n+\t\t    pvti[0].tsc_to_system_mul == pvti[2].tsc_to_system_mul \u0026\u0026\n+\t\t    pvti[0].tsc_shift == pvti[1].tsc_shift \u0026\u0026\n+\t\t    pvti[0].tsc_shift == pvti[2].tsc_shift,\n+\t\t    \"All vCPUs should have same mul/shift\");\n+\n+\tassert_pvclocks_match(pvti, offset0, \"Initial\");\n+}\n+\n+#define ONE_HOUR_NS (3600ULL * NSEC_PER_SEC)\n+\n+static void test_set_clock_consistency(struct kvm_vm *vm,\n+\t\t\t\t       struct kvm_vcpu **vcpus,\n+\t\t\t\t       struct pvclock_vcpu_time_info *pvti,\n+\t\t\t\t       struct kvm_clock_data *clock,\n+\t\t\t\t       u64 offset0)\n+{\n+\tstruct kvm_clock_data setclk = { .clock = clock-\u003eclock + ONE_HOUR_NS };\n+\tu64 clk0;\n+\tint i;\n+\n+\t/*\n+\t * Add an hour to the VM kvmclock via KVM_SET_CLOCK, run each\n+\t * vCPU to pick up the update, and check they're still in sync.\n+\t */\n+\tvm_set_clock(vm, \u0026setclk);\n+\n+\t/* Guest code does GUEST_SYNC then exits — run each to see update */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tvcpu_run(vcpus[vcpu_order[i]]);\n+\t\tTEST_ASSERT_KVM_EXIT_REASON(vcpus[vcpu_order[i]], KVM_EXIT_IO);\n+\t}\n+\n+\tget_pvtis(vcpus, pvti);\n+\n+\tTEST_ASSERT(pvti[0].system_time == pvti[1].system_time \u0026\u0026\n+\t\t    pvti[0].system_time == pvti[2].system_time,\n+\t\t    \"system_time should still match after KVM_SET_CLOCK\");\n+\n+\tassert_pvclocks_match(pvti, offset0, \"After +1h\");\n+\n+\t/* Verify the clock actually moved by ~1 hour */\n+\tclk0 = __pvclock_read_cycles(\u0026pvti[0], rdtsc() + offset0);\n+\tTEST_ASSERT(clk0 \u003e ONE_HOUR_NS,\n+\t\t    \"Clock should be \u003e 1 hour after set, got %lu ns\",\n+\t\t    (unsigned long)clk0);\n+}\n+\n+int main(void)\n+{\n+\tstruct pvclock_vcpu_time_info pvti[NR_VCPUS];\n+\tstruct kvm_vcpu *vcpus[NR_VCPUS];\n+\tstruct kvm_clock_data clock;\n+\tstruct kvm_vm *vm;\n+\tu64 offset0;\n+\tint nr_pages;\n+\tint i;\n+\n+\tTEST_REQUIRE(sys_clocksource_is_based_on_tsc());\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));\n+\n+\tvm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);\n+\n+\tTEST_REQUIRE(!__vcpu_has_device_attr(vcpus[0], KVM_VCPU_TSC_CTRL,\n+\t\t\t\t\t     KVM_VCPU_TSC_OFFSET));\n+\n+\tnr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t\t    KVMCLOCK_GPA, 1, nr_pages, 0);\n+\n+\t/* Give each vCPU its own pvclock structure within the page */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\tvcpu_args_set(vcpus[i], 1, KVMCLOCK_GPA +\n+\t\t\t      i * sizeof(struct pvclock_vcpu_time_info) * 2);\n+\n+\t/* Get vCPU 0's default offset and set vCPU 2's offset higher */\n+\toffset0 = vcpu_get_tsc_offset(vcpus[0]);\n+\tvcpu_set_tsc_offset(vcpus[2], offset0 + TSC_OFFSET);\n+\n+\t/* Run each vCPU to enable kvmclock (with offset already set) */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tvcpu_run(vcpus[i]);\n+\t\tTEST_ASSERT_KVM_EXIT_REASON(vcpus[i], KVM_EXIT_IO);\n+\t}\n+\n+\ttest_masterclock_active(vm, \u0026clock);\n+\ttest_offset_consistency(vcpus, pvti, offset0);\n+\tpr_info(\"PASSED: pvclock consistent across offset vCPUs\\n\");\n+\n+\ttest_set_clock_consistency(vm, vcpus, pvti, \u0026clock, offset0);\n+\tpr_info(\"PASSED: pvclock still consistent after KVM_SET_CLOCK +1h\\n\");\n+\n+\tkvm_vm_free(vm);\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/pvclock_migration_test.c b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c\nnew file mode 100644\nindex 00000000000000..c18c9132308d6c\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c\n@@ -0,0 +1,521 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Test KVM clock precision across simulated live migration.\n+ *\n+ * Verifies that the documented TSC migration procedure (using\n+ * KVM_VCPU_TSC_OFFSET, KVM_VCPU_TSC_SCALE, KVM_GET_CLOCK, and\n+ * KVM_SET_CLOCK_GUEST) preserves the kvmclock's relationship to\n+ * CLOCK_MONOTONIC_RAW — including for vCPUs whose TSCs are offset\n+ * from one another (same frequency), which no longer disables the\n+ * master clock.\n+ *\n+ * The test:\n+ * 1. Creates a VM with 3 vCPUs, runs each guest to enable kvmclock\n+ * 2. Applies divergent TSC offsets to vCPUs 1 and 2\n+ * 3. Verifies the master clock remains active (KVM_CLOCK_HOST_TSC),\n+ *    that the guests see PVCLOCK_TSC_STABLE_BIT clear, and that all\n+ *    vCPUs' pvclocks agree on \"now\" despite the divergent offsets\n+ * 4. Does a PTP-like ABA measurement of kvmclock vs CLOCK_MONOTONIC_RAW\n+ * 5. Follows the documented migration procedure (same host, 1s pause),\n+ *    migrating each vCPU's TSC individually but setting the KVM clock\n+ *    only once, via KVM_SET_CLOCK_GUEST on vCPU0\n+ * 6. Does the same ABA measurement on the destination VM\n+ * 7. Verifies the kvmclock-vs-monotonic delta is preserved, the\n+ *    cross-vCPU TSC deltas are preserved, and all destination vCPUs'\n+ *    pvclocks again agree on \"now\"\n+ */\n+#include \u003cinttypes.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u003cstdio.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003ctime.h\u003e\n+#include \u003cunistd.h\u003e\n+\n+#include \"test_util.h\"\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+#include \u003casm/pvclock-abi.h\u003e\n+\n+#define KVMCLOCK_GPA\t0xc0000000ULL\n+#define NR_VCPUS\t3\n+\n+/*\n+ * Divergent TSC offsets applied to vCPUs 1 and 2, in guest cycles.\n+ * Roughly +1s and -0.5s at 1.5 GHz — large enough that any failure\n+ * to account for them is orders of magnitude outside the ABA bounds.\n+ */\n+static const s64 tsc_deltas[NR_VCPUS] = { 0, 1500000000LL, -750000000LL };\n+\n+static void guest_code(int idx)\n+{\n+\twrmsr(MSR_KVM_SYSTEM_TIME_NEW, (KVMCLOCK_GPA + idx * PAGE_SIZE) | 1);\n+\n+\tfor (;;)\n+\t\tGUEST_SYNC(0);\n+}\n+\n+static u64 read_kvmclock_ns(struct kvm_vm *vm)\n+{\n+\tstruct kvm_clock_data data = {};\n+\n+\tvm_get_clock(vm, \u0026data);\n+\treturn data.clock;\n+}\n+\n+static u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,\n+\t\t\t\t    u64 tsc)\n+{\n+\tu64 delta = tsc - src-\u003etsc_timestamp;\n+\tu64 ns;\n+\n+\tif (src-\u003etsc_shift \u003e= 0)\n+\t\tdelta \u003c\u003c= src-\u003etsc_shift;\n+\telse\n+\t\tdelta \u003e\u003e= -(s32)src-\u003etsc_shift;\n+\n+\tns = (unsigned __int128)delta * src-\u003etsc_to_system_mul \u003e\u003e 32;\n+\treturn src-\u003esystem_time + ns;\n+}\n+\n+/*\n+ * ABA measurement: read CLOCK_MONOTONIC_RAW, kvmclock, CLOCK_MONOTONIC_RAW.\n+ * Repeat 3 times, keep the reading with the smallest spread.\n+ */\n+static void aba_reading(struct kvm_vm *vm, u64 *lo, u64 *kvm_ns,\n+\t\t\tu64 *hi)\n+{\n+\tu64 best_spread = UINT64_MAX;\n+\tint i;\n+\n+\tfor (i = 0; i \u003c 3; i++) {\n+\t\tstruct timespec ts1, ts2;\n+\t\tu64 m1, m2, clk;\n+\n+\t\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts1);\n+\t\tclk = read_kvmclock_ns(vm);\n+\t\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts2);\n+\n+\t\tm1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;\n+\t\tm2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;\n+\n+\t\tif (m2 - m1 \u003c best_spread) {\n+\t\t\tbest_spread = m2 - m1;\n+\t\t\t*lo = m1;\n+\t\t\t*kvm_ns = clk;\n+\t\t\t*hi = m2;\n+\t\t}\n+\t}\n+}\n+\n+static struct kvm_vm *create_vm(struct kvm_vcpu **vcpus, u32 freq_khz)\n+{\n+\tstruct kvm_vm *vm;\n+\tint i;\n+\n+\tvm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);\n+\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t\t    KVMCLOCK_GPA, 1, NR_VCPUS, 0);\n+\tvirt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, NR_VCPUS);\n+\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tvcpu_args_set(vcpus[i], 1, i);\n+\t\t/* Set guest TSC frequency (may trigger scaling) */\n+\t\tvcpu_ioctl(vcpus[i], KVM_SET_TSC_KHZ,\n+\t\t\t   (void *)(unsigned long)freq_khz);\n+\t}\n+\treturn vm;\n+}\n+\n+static void run_to_sync(struct kvm_vcpu *vcpu)\n+{\n+\tstruct ucall uc;\n+\n+\tvcpu_run(vcpu);\n+\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\tTEST_ASSERT_EQ(get_ucall(vcpu, \u0026uc), UCALL_SYNC);\n+}\n+\n+/*\n+ * Compute a vCPU's guest TSC for a given host TSC value, using the\n+ * vCPU's scale and offset as saved from KVM_VCPU_TSC_SCALE/OFFSET.\n+ */\n+static u64 host_to_guest_tsc(struct kvm_vcpu_tsc_scale *scale, u64 ofs,\n+\t\t\t     u64 host_tsc)\n+{\n+\tif (scale-\u003etsc_frac_bits)\n+\t\treturn ((unsigned __int128)host_tsc * scale-\u003etsc_ratio\n+\t\t\t\u003e\u003e scale-\u003etsc_frac_bits) + ofs;\n+\treturn host_tsc + ofs;\n+}\n+\n+/*\n+ * Verify that all vCPUs agree on the KVM clock, despite having\n+ * different TSC offsets. Take one atomic {host_tsc, kvmclock} pair\n+ * for the whole VM, derive each vCPU's guest TSC at that instant,\n+ * and evaluate each vCPU's pvti at its own guest TSC. All must give\n+ * the same nanosecond value (same instant, same clock), and must\n+ * match what KVM_GET_CLOCK itself said.\n+ */\n+static void check_cross_vcpu_coherence(struct kvm_vm *vm,\n+\t\t\t\t       struct kvm_vcpu **vcpus,\n+\t\t\t\t       struct pvclock_vcpu_time_info *pvtis,\n+\t\t\t\t       const char *what)\n+{\n+\tstruct kvm_clock_data now = {};\n+\tu64 clk[NR_VCPUS];\n+\tint i;\n+\n+\tvm_get_clock(vm, \u0026now);\n+\tTEST_ASSERT(now.flags \u0026 KVM_CLOCK_HOST_TSC,\n+\t\t    \"%s: master clock inactive with divergent TSC offsets\",\n+\t\t    what);\n+\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tstruct kvm_vcpu_tsc_scale scale = {};\n+\t\tu64 ofs = vcpu_get_tsc_offset(vcpus[i]);\n+\t\tu64 guest_tsc;\n+\n+\t\tvcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,\n+\t\t\t\t     KVM_VCPU_TSC_SCALE, \u0026scale);\n+\t\tguest_tsc = host_to_guest_tsc(\u0026scale, ofs, now.host_tsc);\n+\t\tclk[i] = pvclock_read_cycles(\u0026pvtis[i], guest_tsc);\n+\n+\t\tTEST_ASSERT(!(pvtis[i].flags \u0026 PVCLOCK_TSC_STABLE_BIT),\n+\t\t\t    \"%s: vCPU%d still advertises TSC_STABLE with divergent offsets\",\n+\t\t\t    what, i);\n+\t}\n+\n+\tfor (i = 1; i \u003c NR_VCPUS; i++) {\n+\t\ts64 d = (s64)(clk[i] - clk[0]);\n+\n+\t\tpr_info(\"  %s: vCPU%d vs vCPU0 kvmclock delta %\" PRId64 \" ns\\n\",\n+\t\t\twhat, i, d);\n+\t\tTEST_ASSERT(d \u003e= -2 \u0026\u0026 d \u003c= 2,\n+\t\t\t    \"%s: vCPU%d kvmclock disagrees with vCPU0 by %\" PRId64 \" ns\",\n+\t\t\t    what, i, d);\n+\t}\n+\n+\t/* And all of them must agree with KVM_GET_CLOCK itself */\n+\ts64 d0 = (s64)(clk[0] - now.clock);\n+\tpr_info(\"  %s: vCPU0 pvclock vs KVM_GET_CLOCK delta %\" PRId64 \" ns\\n\",\n+\t\twhat, d0);\n+\tTEST_ASSERT(d0 \u003e= -2 \u0026\u0026 d0 \u003c= 2,\n+\t\t    \"%s: vCPU0 pvclock disagrees with KVM_GET_CLOCK by %\" PRId64 \" ns\",\n+\t\t    what, d0);\n+}\n+\n+int main(void)\n+{\n+\tstruct pvclock_vcpu_time_info pvti_src[NR_VCPUS];\n+\tstruct pvclock_vcpu_time_info pvti_dst_ioctl[NR_VCPUS];\n+\tstruct kvm_clock_data clock_src, clock_dst;\n+\tstruct kvm_vcpu_tsc_scale scale_src[NR_VCPUS], scale_dst;\n+\tstruct kvm_vcpu *vcpus[NR_VCPUS];\n+\tstruct kvm_vm *vm;\n+\tu64 mono_before, kvm_before, kvm_after;\n+\ts64 delta_before;\n+\tu64 ofs_src[NR_VCPUS], tsc_src[NR_VCPUS], tsc_dst, raw_dst;\n+\tu64 ofs_dst[NR_VCPUS];\n+\tu64 host_tsc_src, host_tsc_dst;\n+\tu64 time_src, time_dst;\n+\ts64 delta_t;\n+\tu32 freq_khz = 1500000; /* 1.5 GHz — forces TSC scaling */\n+\tint i, pass;\n+\n+\tTEST_REQUIRE(sys_clocksource_is_based_on_tsc());\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));\n+\n+\t/* === SOURCE SIDE === */\n+\tpr_info(\"=== Source VM ===\\n\");\n+\tvm = create_vm(vcpus, freq_khz);\n+\n+\t/* Run each guest to enable its kvmclock */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\trun_to_sync(vcpus[i]);\n+\n+\t/*\n+\t * Apply divergent TSC offsets. Same frequency, different offsets:\n+\t * this must no longer disable the master clock, but must clear\n+\t * PVCLOCK_TSC_STABLE_BIT.\n+\t */\n+\tfor (i = 1; i \u003c NR_VCPUS; i++)\n+\t\tvcpu_set_tsc_offset(vcpus[i],\n+\t\t\t\t    vcpu_get_tsc_offset(vcpus[i]) + tsc_deltas[i]);\n+\n+\t/*\n+\t * Re-run each vCPU twice. The offset writes leave a masterclock\n+\t * update pending on vCPUs 1 and 2; the first pass processes it and\n+\t * broadcasts KVM_REQ_CLOCK_UPDATE to every vCPU, and the second\n+\t * pass has each vCPU rewrite its guest-visible pvclock page with\n+\t * PVCLOCK_TSC_STABLE_BIT now clear. A single pass would leave\n+\t * vCPU0's page stale: its rewrite happens before the broadcast.\n+\t */\n+\tfor (pass = 0; pass \u003c 2; pass++)\n+\t\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\t\trun_to_sync(vcpus[i]);\n+\n+\t/* Fetch each vCPU's pvti and verify cross-vCPU coherence */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\tvcpu_get_clock_guest(vcpus[i], \u0026pvti_src[i]);\n+\tcheck_cross_vcpu_coherence(vm, vcpus, pvti_src, \"source\");\n+\n+\t/* The guest-visible pvti pages must also show TSC_STABLE clear */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tstruct pvclock_vcpu_time_info *pvti =\n+\t\t\taddr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());\n+\n+\t\tTEST_ASSERT(!(pvti-\u003eflags \u0026 PVCLOCK_TSC_STABLE_BIT),\n+\t\t\t    \"vCPU%d guest pvti advertises TSC_STABLE with divergent offsets\", i);\n+\t}\n+\n+\t/* ABA measurement: kvmclock vs CLOCK_MONOTONIC_RAW */\n+\tu64 src_mono_lo, src_mono_hi;\n+\taba_reading(vm, \u0026src_mono_lo, \u0026kvm_before, \u0026src_mono_hi);\n+\tmono_before = (src_mono_lo + src_mono_hi) / 2;\n+\tdelta_before = (s64)(kvm_before - mono_before);\n+\tpr_info(\"  kvmclock - MONOTONIC_RAW = %\" PRId64 \" ns (±%\" PRIu64 \" ns)\\n\",\n+\t\tdelta_before, (src_mono_hi - src_mono_lo) / 2);\n+\n+\t/* Step 1: KVM_GET_CLOCK for atomic {host_tsc, realtime} */\n+\tmemset(\u0026clock_src, 0, sizeof(clock_src));\n+\tclock_src.flags = KVM_CLOCK_REALTIME;\n+\tvm_get_clock(vm, \u0026clock_src);\n+\tTEST_ASSERT(clock_src.flags \u0026 KVM_CLOCK_HOST_TSC,\n+\t\t    \"KVM_GET_CLOCK did not provide host_tsc (no master clock?)\");\n+\thost_tsc_src = clock_src.host_tsc;\n+\ttime_src = clock_src.realtime;\n+\n+\t/* Step 2: Save each vCPU's TSC offset and scale */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tofs_src[i] = vcpu_get_tsc_offset(vcpus[i]);\n+\t\tmemset(\u0026scale_src[i], 0, sizeof(scale_src[i]));\n+\t\tvcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,\n+\t\t\t\t     KVM_VCPU_TSC_SCALE, \u0026scale_src[i]);\n+\n+\t\t/* Compute this vCPU's guest TSC at Tsrc */\n+\t\ttsc_src[i] = host_to_guest_tsc(\u0026scale_src[i], ofs_src[i],\n+\t\t\t\t\t       host_tsc_src);\n+\t\tpr_info(\"  vCPU%d: TSC freq=%u kHz, offset=%\" PRId64 \"\\n\",\n+\t\t\ti, freq_khz, (s64)ofs_src[i]);\n+\t}\n+\n+\t/* Step 3: KVM_GET_CLOCK_GUEST (already fetched above as pvti_src[]) */\n+\n+\tkvm_vm_free(vm);\n+\n+\t/* === PAUSE (simulate migration) === */\n+\tpr_info(\"=== Pausing 1 second ===\\n\");\n+\tsleep(1);\n+\n+\t/* === DESTINATION SIDE === */\n+\tpr_info(\"=== Destination VM ===\\n\");\n+\t/* Step 4: create + KVM_SET_TSC_KHZ (in create_vm) */\n+\tvm = create_vm(vcpus, freq_khz);\n+\n+\t/* Step 5: KVM_GET_CLOCK for atomic {host_tsc, realtime} pair.\n+\t * Master clock is active from VM creation.\n+\t */\n+\tmemset(\u0026clock_dst, 0, sizeof(clock_dst));\n+\tvm_get_clock(vm, \u0026clock_dst);\n+\tTEST_ASSERT(clock_dst.flags \u0026 KVM_CLOCK_HOST_TSC,\n+\t\t    \"KVM_GET_CLOCK did not provide host_tsc (no master clock?)\");\n+\thost_tsc_dst = clock_dst.host_tsc;\n+\ttime_dst = clock_dst.realtime;\n+\n+\t/* Step 6: ΔT */\n+\tdelta_t = (s64)(time_dst - time_src);\n+\n+\t/* Step 7: Compute and set each vCPU's destination offset */\n+\tmemset(\u0026scale_dst, 0, sizeof(scale_dst));\n+\tvcpu_device_attr_get(vcpus[0], KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_SCALE,\n+\t\t\t     \u0026scale_dst);\n+\n+\tif (scale_dst.tsc_frac_bits)\n+\t\traw_dst = (unsigned __int128)host_tsc_dst * scale_dst.tsc_ratio\n+\t\t\t  \u003e\u003e scale_dst.tsc_frac_bits;\n+\telse\n+\t\traw_dst = host_tsc_dst;\n+\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\ttsc_dst = tsc_src[i] + (u64)((s64)freq_khz * delta_t / 1000000LL);\n+\t\tofs_dst[i] = tsc_dst - raw_dst;\n+\t\tvcpu_set_tsc_offset(vcpus[i], ofs_dst[i]);\n+\t}\n+\n+\t/*\n+\t * The cross-vCPU TSC relationships must be preserved exactly:\n+\t * every vCPU's offset moved by the same amount, so the deltas\n+\t * between them are untouched by the CLOCK_REALTIME imprecision.\n+\t */\n+\tfor (i = 1; i \u003c NR_VCPUS; i++) {\n+\t\ts64 src_delta = (s64)(ofs_src[i] - ofs_src[0]);\n+\t\ts64 dst_delta = (s64)(ofs_dst[i] - ofs_dst[0]);\n+\n+\t\tpr_info(\"  vCPU%d-vCPU0 TSC delta: src %\" PRId64\n+\t\t\t\", dst %\" PRId64 \" cycles\\n\", i, src_delta, dst_delta);\n+\t\tTEST_ASSERT(src_delta == dst_delta,\n+\t\t\t    \"vCPU%d TSC delta not preserved: %\" PRId64 \" -\u003e %\" PRId64,\n+\t\t\t    i, src_delta, dst_delta);\n+\t}\n+\n+\t/*\n+\t * The TSC offset delta introduced by using CLOCK_REALTIME to\n+\t * estimate elapsed time. On same host, the correct offset is\n+\t * ofs_src; the difference is the CLOCK_REALTIME-vs-TSC error.\n+\t */\n+\ts64 tsc_ofs_delta = (s64)(ofs_dst[0] - ofs_src[0]);\n+\ts64 tsc_ofs_delta_ns = tsc_ofs_delta * 1000000LL / freq_khz;\n+\tpr_info(\"  Destination TSC offset=%\" PRId64\n+\t\t\", imprecision from CLOCK_REALTIME: %\" PRId64 \" cycles = %\"\n+\t\tPRId64 \" ns\\n\", (s64)ofs_dst[0], tsc_ofs_delta, tsc_ofs_delta_ns);\n+\n+\t/*\n+\t * Step 8: KVM_SET_CLOCK_GUEST — once, via vCPU0. The other\n+\t * vCPUs' clocks must come out right too: the KVM clock is\n+\t * VM-wide, and each vCPU's pvti relates it to that vCPU's\n+\t * own TSC.\n+\t */\n+\tvcpu_set_clock_guest(vcpus[0], \u0026pvti_src[0]);\n+\n+\t/* Run each guest to write its pvclock page on the destination */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\trun_to_sync(vcpus[i]);\n+\n+\t/* Verify cross-vCPU coherence on the destination */\n+\tfor (i = 0; i \u003c NR_VCPUS; i++)\n+\t\tvcpu_get_clock_guest(vcpus[i], \u0026pvti_dst_ioctl[i]);\n+\tcheck_cross_vcpu_coherence(vm, vcpus, pvti_dst_ioctl, \"dest\");\n+\n+\t/* ABA measurement on destination */\n+\tu64 mono_lo, mono_hi;\n+\taba_reading(vm, \u0026mono_lo, \u0026kvm_after, \u0026mono_hi);\n+\n+\t/*\n+\t * The kvmclock is tied to the guest TSC via SET_CLOCK_GUEST.\n+\t * The guest TSC is offset from the correct value by tsc_ofs_delta_ns\n+\t * (due to CLOCK_REALTIME imprecision). So the kvmclock should be\n+\t * offset from CLOCK_MONOTONIC_RAW by exactly:\n+\t *   (original delta) + tsc_ofs_delta_ns\n+\t *\n+\t * The \"original delta\" has uncertainty from the source ABA spread,\n+\t * and the measurement has uncertainty from the destination ABA spread.\n+\t * Verify the expected value falls within the combined bounds.\n+\t */\n+\ts64 delta_before_lo = (s64)(kvm_before - src_mono_hi);\n+\ts64 delta_before_hi = (s64)(kvm_before - src_mono_lo);\n+\ts64 expected_lo = delta_before_lo + tsc_ofs_delta_ns;\n+\ts64 expected_hi = delta_before_hi + tsc_ofs_delta_ns;\n+\ts64 actual_lo = (s64)(kvm_after - mono_hi);\n+\ts64 actual_hi = (s64)(kvm_after - mono_lo);\n+\n+\t/* Show the shift relative to the source measurement */\n+\ts64 expected_mid = tsc_ofs_delta_ns;\n+\ts64 expected_err = (s64)(src_mono_hi - src_mono_lo) / 2;\n+\ts64 actual_mid = ((actual_lo + actual_hi) / 2) - delta_before;\n+\ts64 actual_err = (s64)(mono_hi - mono_lo) / 2;\n+\tpr_info(\"  kvmclock-mono shift: expected %\" PRId64 \" ns (±%\" PRId64\n+\t\t\"), measured %\" PRId64 \" ns (±%\" PRId64 \")\\n\",\n+\t\texpected_mid, expected_err, actual_mid, actual_err);\n+\n+\t/* The ranges must overlap */\n+\tTEST_ASSERT(expected_hi \u003e= actual_lo \u0026\u0026 expected_lo \u003c= actual_hi,\n+\t\t    \"Ranges don't overlap: expected [%\" PRId64 \", %\" PRId64\n+\t\t    \"] measured [%\" PRId64 \", %\" PRId64 \"]\",\n+\t\t    expected_lo, expected_hi, actual_lo, actual_hi);\n+\n+\t/*\n+\t * Direct pvclock verification: read each destination pvclock page\n+\t * (as written for the guest) and verify that computing kvmclock\n+\t * from the source pvti and the destination pvti at the same\n+\t * instant gives the same result, for every vCPU.\n+\t *\n+\t * Get one atomic {host_tsc, kvmclock} pair, derive each vCPU's\n+\t * guest TSC at that instant, then compute kvmclock from both\n+\t * pvclock structs. The source pvti evaluates at the *migrated*\n+\t * guest TSC, i.e. shifted by the CLOCK_REALTIME imprecision that\n+\t * was baked into the offsets — which is exactly what \"the clock\n+\t * follows the TSC\" means.\n+\t */\n+\tstruct kvm_clock_data clock_now = {};\n+\tvm_get_clock(vm, \u0026clock_now);\n+\tpr_info(\"  KVM_GET_CLOCK:  %\" PRIu64 \" ns\\n\", (u64)clock_now.clock);\n+\n+\tu64 host_tsc_now = clock_now.host_tsc;\n+\n+\tfor (i = 0; i \u003c NR_VCPUS; i++) {\n+\t\tstruct pvclock_vcpu_time_info *pvti_page =\n+\t\t\taddr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());\n+\t\tu64 guest_tsc_now = host_to_guest_tsc(\u0026scale_dst, ofs_dst[i],\n+\t\t\t\t\t\t      host_tsc_now);\n+\t\tu64 clk_from_src = pvclock_read_cycles(\u0026pvti_src[i],\n+\t\t\t\t\t\t       guest_tsc_now);\n+\t\tu64 clk_from_dst = pvclock_read_cycles(pvti_page,\n+\t\t\t\t\t\t       guest_tsc_now);\n+\t\ts64 pvclock_delta = (s64)(clk_from_src - clk_from_dst);\n+\n+\t\tpr_info(\"  vCPU%d pvclock direct: src=%\" PRIu64 \" dst=%\" PRIu64\n+\t\t\t\" delta=%\" PRId64 \" ns\\n\", i, clk_from_src,\n+\t\t\tclk_from_dst, pvclock_delta);\n+\n+\t\tTEST_ASSERT(pvclock_delta \u003e= -2 \u0026\u0026 pvclock_delta \u003c= 2,\n+\t\t\t    \"vCPU%d pvclock src vs dst disagree by %\" PRId64 \" ns\",\n+\t\t\t    i, pvclock_delta);\n+\t}\n+\n+\t/*\n+\t * Tight ABA: compare pvclock_read() directly (no ioctl) against\n+\t * CLOCK_MONOTONIC_RAW. The spread should be much smaller since\n+\t * there's no syscall between the two clock_gettime calls — just\n+\t * rdtsc + userspace mul/shift.\n+\t */\n+\tstruct pvclock_vcpu_time_info *pvti0 = addr_gpa2hva(vm, KVMCLOCK_GPA);\n+\tu64 tight_mono_lo = 0, tight_mono_hi = 0, tight_kvm = 0;\n+\tu64 tight_best_spread = UINT64_MAX;\n+\tfor (i = 0; i \u003c 3; i++) {\n+\t\tstruct timespec ts1, ts2;\n+\t\tu64 m1, m2, tsc, clk;\n+\n+\t\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts1);\n+\t\ttsc = rdtsc();\n+\t\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts2);\n+\n+\t\tm1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;\n+\t\tm2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;\n+\n+\t\t/* Scale host TSC to vCPU0's guest TSC */\n+\t\ttsc = host_to_guest_tsc(\u0026scale_dst, ofs_dst[0], tsc);\n+\n+\t\tclk = pvclock_read_cycles(pvti0, tsc);\n+\n+\t\tif (m2 - m1 \u003c tight_best_spread) {\n+\t\t\ttight_best_spread = m2 - m1;\n+\t\t\ttight_mono_lo = m1;\n+\t\t\ttight_mono_hi = m2;\n+\t\t\ttight_kvm = clk;\n+\t\t}\n+\t}\n+\tpr_info(\"  Tight ABA spread: %\" PRIu64 \" ns (best of 3)\\n\", tight_best_spread);\n+\n+\ts64 tight_expected_lo = delta_before_lo + tsc_ofs_delta_ns;\n+\ts64 tight_expected_hi = delta_before_hi + tsc_ofs_delta_ns;\n+\ts64 tight_actual_lo = (s64)(tight_kvm - tight_mono_hi);\n+\ts64 tight_actual_hi = (s64)(tight_kvm - tight_mono_lo);\n+\ts64 tight_actual_mid = ((tight_actual_lo + tight_actual_hi) / 2) - delta_before;\n+\ts64 tight_actual_err = (s64)(tight_mono_hi - tight_mono_lo) / 2;\n+\n+\tpr_info(\"  Tight kvmclock-mono shift: expected %\" PRId64\n+\t\t\" ns (±%\" PRId64 \"), measured %\" PRId64 \" ns (±%\" PRId64 \")\\n\",\n+\t\texpected_mid, expected_err, tight_actual_mid, tight_actual_err);\n+\n+\tTEST_ASSERT(tight_expected_hi \u003e= tight_actual_lo \u0026\u0026\n+\t\t    tight_expected_lo \u003c= tight_actual_hi,\n+\t\t    \"Tight ABA ranges don't overlap\");\n+\n+\tkvm_vm_free(vm);\n+\tpr_info(\"PASS: kvmclock offset matches TSC delta from CLOCK_REALTIME\"\n+\t\t\" (%\" PRId64 \" ns) within ABA bounds\\n\", tsc_ofs_delta_ns);\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/pvclock_test.c b/tools/testing/selftests/kvm/x86/pvclock_test.c\nnew file mode 100644\nindex 00000000000000..1599fb0c727536\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/pvclock_test.c\n@@ -0,0 +1,518 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Copyright © Amazon.com, Inc. or its affiliates.\n+ *\n+ * Tests for pvclock API\n+ * KVM_SET_CLOCK_GUEST/KVM_GET_CLOCK_GUEST\n+ */\n+#include \u003cgetopt.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003ctime.h\u003e\n+#include \u003cunistd.h\u003e\n+\n+#include \"test_util.h\"\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+#include \u003casm/pvclock-abi.h\u003e\n+\n+/*\n+ * Reproduce the pvclock calculation the guest uses to convert TSC to\n+ * nanoseconds. This must match the kernel's __pvclock_read_cycles().\n+ */\n+static inline u64 pvclock_scale_delta(u64 delta, u32 mul,\n+\t\t\t\t\t   s8 shift)\n+{\n+\tif (shift \u003c 0)\n+\t\tdelta \u003e\u003e= -shift;\n+\telse\n+\t\tdelta \u003c\u003c= shift;\n+\treturn ((__uint128_t)delta * mul) \u003e\u003e 32;\n+}\n+\n+static inline u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,\n+\t\t\t\t\t   u64 tsc)\n+{\n+\tu64 delta = tsc - src-\u003etsc_timestamp;\n+\n+\treturn src-\u003esystem_time + pvclock_scale_delta(delta,\n+\t\t\t\t\t\t      src-\u003etsc_to_system_mul,\n+\t\t\t\t\t\t      src-\u003etsc_shift);\n+}\n+\n+static inline void pvti_snapshot(struct pvclock_vcpu_time_info *dst,\n+\t\t\t\t volatile struct pvclock_vcpu_time_info *src)\n+{\n+\tu32 version;\n+\n+\tdo {\n+\t\tversion = src-\u003eversion;\n+\t\t__asm__ __volatile__(\"\" ::: \"memory\");\n+\t\t*dst = *src;\n+\t\t__asm__ __volatile__(\"\" ::: \"memory\");\n+\t} while ((src-\u003eversion \u0026 1) || src-\u003eversion != version);\n+}\n+\n+enum {\n+\tSTAGE_FIRST_BOOT,\n+\tSTAGE_UNCORRECTED,\n+\tSTAGE_CORRECTED\n+};\n+\n+#define KVMCLOCK_GPA\t0xc0000000ull\n+#define KVMCLOCK_SIZE\tsizeof(struct pvclock_vcpu_time_info)\n+\n+static void trigger_pvti_update(void)\n+{\n+\t/*\n+\t * Toggle between KVM's old and new system time methods to coerce KVM\n+\t * into updating the fields in the PV time info struct.\n+\t */\n+\twrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);\n+\twrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);\n+}\n+\n+static void guest_code(void)\n+{\n+\tstruct pvclock_vcpu_time_info *pvti =\n+\t\t(void *)(unsigned long)KVMCLOCK_GPA;\n+\tstruct pvclock_vcpu_time_info pvti_boot;\n+\tstruct pvclock_vcpu_time_info pvti_uncorrected;\n+\tstruct pvclock_vcpu_time_info pvti_corrected;\n+\tu64 tsc_guest;\n+\tu64 clk_boot, clk_uncorrected, clk_corrected;\n+\ts64 delta_corrected;\n+\n+\t/* Set up kvmclock and snapshot the initial pvclock parameters. */\n+\twrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);\n+\tpvti_snapshot(\u0026pvti_boot, pvti);\n+\tGUEST_SYNC(STAGE_FIRST_BOOT);\n+\n+\t/*\n+\t * Trigger an update of the PVTI. Calculating the KVM clock using this\n+\t * updated structure will show a delta from the original.\n+\t */\n+\ttrigger_pvti_update();\n+\tpvti_snapshot(\u0026pvti_uncorrected, pvti);\n+\tGUEST_SYNC(STAGE_UNCORRECTED);\n+\n+\t/*\n+\t * Snapshot the corrected time (the host does KVM_SET_CLOCK_GUEST when\n+\t * handling STAGE_UNCORRECTED).\n+\t */\n+\tpvti_snapshot(\u0026pvti_corrected, pvti);\n+\n+\t/*\n+\t * Sample the TSC at a single point in time, then calculate the\n+\t * effective KVM clock using the PVTI from each stage. Verify that the\n+\t * corrected clock matches the boot clock to within ±2ns.\n+\t */\n+\ttsc_guest = rdtsc();\n+\n+\tclk_boot = pvclock_read_cycles(\u0026pvti_boot, tsc_guest);\n+\tclk_uncorrected = pvclock_read_cycles(\u0026pvti_uncorrected, tsc_guest);\n+\tclk_corrected = pvclock_read_cycles(\u0026pvti_corrected, tsc_guest);\n+\n+\t/*\n+\t * The host stepped the KVM clock forward by 10 seconds at\n+\t * STAGE_FIRST_BOOT, so the uncorrected clock must diverge; without\n+\t * this, a no-op KVM_SET_CLOCK_GUEST would pass the test below.\n+\t */\n+\t__GUEST_ASSERT((s64)(clk_uncorrected - clk_boot) \u003e NSEC_PER_SEC,\n+\t\t       \"uncorrected clock did not diverge (boot=%lu uncorrected=%lu)\",\n+\t\t       clk_boot, clk_uncorrected);\n+\n+\tdelta_corrected = clk_boot - clk_corrected;\n+\n+\t__GUEST_ASSERT(delta_corrected \u003e= -2 \u0026\u0026 delta_corrected \u003c= 2,\n+\t\t       \"corrected delta %ld out of range (boot=%lu uncorrected=%lu corrected=%lu)\",\n+\t\t       delta_corrected, clk_boot, clk_uncorrected, clk_corrected);\n+\n+\tGUEST_SYNC(STAGE_CORRECTED);\n+}\n+\n+static void run_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu,\n+\t\t     unsigned int sleep_sec)\n+{\n+\tstruct pvclock_vcpu_time_info pvti_before;\n+\tstruct kvm_clock_data clock_step;\n+\tstruct ucall uc;\n+\n+\tfor (;;) {\n+\t\tvcpu_run(vcpu);\n+\t\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\n+\t\tswitch (get_ucall(vcpu, \u0026uc)) {\n+\t\tcase UCALL_ABORT:\n+\t\t\tREPORT_GUEST_ASSERT(uc);\n+\t\t\tbreak;\n+\t\tcase UCALL_SYNC:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tTEST_FAIL(\"Unexpected ucall\");\n+\t\t}\n+\n+\t\tswitch (uc.args[1]) {\n+\t\tcase STAGE_FIRST_BOOT:\n+\t\t\t/* Save the pvclock parameters before the update. */\n+\t\t\tvcpu_get_clock_guest(vcpu, \u0026pvti_before);\n+\n+\t\t\t/* Sleep to let the clocks diverge. */\n+\t\t\tsleep(sleep_sec);\n+\n+\t\t\t/*\n+\t\t\t * Step the KVM clock forward 10 seconds so that the\n+\t\t\t * divergence the correction must eliminate is\n+\t\t\t * deterministic, not at the mercy of accumulated\n+\t\t\t * drift during the sleep.\n+\t\t\t */\n+\t\t\tvm_get_clock(vm, \u0026clock_step);\n+\t\t\tclock_step.clock += 10ull * NSEC_PER_SEC;\n+\t\t\tclock_step.flags = 0;\n+\t\t\tvm_set_clock(vm, \u0026clock_step);\n+\t\t\tbreak;\n+\n+\t\tcase STAGE_UNCORRECTED:\n+\t\t\t/* Restore the original pvclock parameters. */\n+\t\t\tvcpu_set_clock_guest(vcpu, \u0026pvti_before);\n+\t\t\tbreak;\n+\n+\t\tcase STAGE_CORRECTED:\n+\t\t\t/* Guest verified the delta in-guest. */\n+\t\t\treturn;\n+\n+\t\tdefault:\n+\t\t\tTEST_FAIL(\"Unknown stage %lu\", uc.args[1]);\n+\t\t}\n+\t}\n+}\n+\n+static void configure_pvclock(struct kvm_vm *vm)\n+{\n+\tunsigned int nr_pages;\n+\n+\tnr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t\t    KVMCLOCK_GPA, 1, nr_pages, 0);\n+\tvirt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, nr_pages);\n+}\n+\n+static void run_at_frequency(u64 tsc_khz, unsigned int sleep_sec)\n+{\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\n+\tpr_info(\"Testing at TSC frequency %lu kHz\\n\", tsc_khz);\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\tconfigure_pvclock(vm);\n+\tvcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)tsc_khz);\n+\trun_test(vm, vcpu, sleep_sec);\n+\tkvm_vm_free(vm);\n+}\n+\n+static void test_tsc_stable_bit(void);\n+static void test_clock_guest_with_offsets(void);\n+static void test_legacy_msr(void);\n+static void run_vcpu_once(struct kvm_vcpu *vcpu);\n+\n+static void usage(const char *name)\n+{\n+\tprintf(\"Usage: %s [options]\\n\"\n+\t       \"  -s, --sleep SEC     sleep duration between snapshots (default: 2)\\n\"\n+\t       \"  -h, --help          show this help\\n\", name);\n+}\n+\n+int main(int argc, char *argv[])\n+{\n+\tstatic const struct option long_opts[] = {\n+\t\t{ \"sleep\", required_argument, NULL, 's' },\n+\t\t{ \"help\",  no_argument,       NULL, 'h' },\n+\t\t{ NULL,    0,                  NULL,  0  },\n+\t};\n+\tunsigned int sleep_sec = 2;\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tu64 host_khz;\n+\tu64 freq;\n+\tint opt;\n+\n+\twhile ((opt = getopt_long(argc, argv, \"s:h\", long_opts, NULL)) != -1) {\n+\t\tswitch (opt) {\n+\t\tcase 's':\n+\t\t\tsleep_sec = atoi_non_negative(\"sleep\", optarg);\n+\t\t\tbreak;\n+\t\tcase 'h':\n+\t\tdefault:\n+\t\t\tusage(argv[0]);\n+\t\t\treturn opt == 'h' ? 0 : 1;\n+\t\t}\n+\t}\n+\n+\tTEST_REQUIRE(sys_clocksource_is_based_on_tsc());\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));\n+\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\tconfigure_pvclock(vm);\n+\n+\t/* First run at native frequency (no scaling). */\n+\trun_test(vm, vcpu, sleep_sec);\n+\n+\t/*\n+\t * Then enumerate a range of TSC frequencies crossing the 32-bit\n+\t * boundary, to exercise the scaling path at various ratios.\n+\t */\n+\thost_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);\n+\tkvm_vm_free(vm);\n+\n+\tfor (freq = 1000000; freq \u003c= 5000000; freq += 500000) {\n+\t\tif (freq == host_khz)\n+\t\t\tcontinue;\n+\t\trun_at_frequency(freq, sleep_sec);\n+\t}\n+\n+\ttest_tsc_stable_bit();\n+\ttest_clock_guest_with_offsets();\n+\ttest_legacy_msr();\n+\n+\treturn 0;\n+}\n+\n+static void guest_code_legacy_msr(void)\n+{\n+\twrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);\n+\tGUEST_SYNC(0);\n+\t/* Re-request the time, as SUSE's 2.6.16 kernel would. */\n+\twrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);\n+\tGUEST_SYNC(1);\n+}\n+\n+/*\n+ * A guest using the legacy MSR_KVM_SYSTEM_TIME must no longer lose the\n+ * master clock, and rewriting the MSR must slide the reference point\n+ * forward so the pvclock's tsc_timestamp is recent — that freshness is\n+ * what SUSE's 2.6.16 kernel demands instead of tolerating a fixed\n+ * reference point.\n+ */\n+static void test_legacy_msr(void)\n+{\n+\tstruct pvclock_vcpu_time_info *pvti;\n+\tstruct kvm_clock_data clock;\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tu64 tsc_now, age_limit;\n+\n+\tpr_info(\"Testing the legacy MSR_KVM_SYSTEM_TIME\\n\");\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code_legacy_msr);\n+\tconfigure_pvclock(vm);\n+\n+\trun_vcpu_once(vcpu);\n+\tvm_ioctl(vm, KVM_GET_CLOCK, \u0026clock);\n+\tTEST_ASSERT(clock.flags \u0026 KVM_CLOCK_TSC_STABLE,\n+\t\t    \"Legacy MSR_KVM_SYSTEM_TIME should not disable the master clock\");\n+\n+\t/* Age the master clock reference point, then re-request. */\n+\tusleep(300 * 1000);\n+\trun_vcpu_once(vcpu);\n+\n+\tpvti = addr_gpa2hva(vm, KVMCLOCK_GPA);\n+\ttsc_now = vcpu_get_msr(vcpu, MSR_IA32_TSC);\n+\n+\t/*\n+\t * The rewrite slid the reference point, so the pvclock must be\n+\t * anchored after the 300ms sleep: allow 250ms of slack for the\n+\t * ioctls around it. SUSE's real threshold was 1/5 jiffie, but\n+\t * asserting that tightly would flake on a loaded host.\n+\t */\n+\tage_limit = (u64)__vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL) * 250;\n+\tTEST_ASSERT(tsc_now - pvti-\u003etsc_timestamp \u003c age_limit,\n+\t\t    \"pvclock tsc_timestamp should be fresh after legacy MSR rewrite (age %llu cycles, limit %llu)\",\n+\t\t    (unsigned long long)(tsc_now - pvti-\u003etsc_timestamp),\n+\t\t    (unsigned long long)age_limit);\n+\n+\tvm_ioctl(vm, KVM_GET_CLOCK, \u0026clock);\n+\tTEST_ASSERT(clock.flags \u0026 KVM_CLOCK_TSC_STABLE,\n+\t\t    \"Master clock should survive a legacy MSR rewrite\");\n+\n+\tkvm_vm_free(vm);\n+}\n+\n+static volatile u32 vcpu_counter;\n+static void guest_code_stable_bit(void)\n+{\n+\tu32 idx = __atomic_fetch_add(\u0026vcpu_counter, 1, __ATOMIC_SEQ_CST);\n+\tu64 gpa = KVMCLOCK_GPA + idx * KVMCLOCK_SIZE;\n+\n+\twrmsr(MSR_KVM_SYSTEM_TIME_NEW, gpa | KVM_MSR_ENABLED);\n+\tGUEST_SYNC(0);\n+\tGUEST_SYNC(0);\n+\tGUEST_SYNC(0);\n+}\n+\n+static void run_vcpu_once(struct kvm_vcpu *vcpu)\n+{\n+\tstruct ucall uc;\n+\n+\tvcpu_run(vcpu);\n+\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\tswitch (get_ucall(vcpu, \u0026uc)) {\n+\tcase UCALL_ABORT:\n+\t\tREPORT_GUEST_ASSERT(uc);\n+\t\tbreak;\n+\tcase UCALL_SYNC:\n+\t\tbreak;\n+\tdefault:\n+\t\tTEST_FAIL(\"Unexpected ucall\");\n+\t}\n+}\n+\n+static void test_tsc_stable_bit(void)\n+{\n+\tstruct pvclock_vcpu_time_info pvti;\n+\tstruct kvm_vcpu *vcpus[2];\n+\tstruct kvm_vm *vm;\n+\tint ret;\n+\n+\tpr_info(\"Testing PVCLOCK_TSC_STABLE_BIT with matched/unmatched TSCs\\n\");\n+\n+\tvm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);\n+\tconfigure_pvclock(vm);\n+\n+\t/*\n+\t * Case 1: All TSCs matched (same frequency and offset).\n+\t * Master clock should be active, PVCLOCK_TSC_STABLE_BIT set.\n+\t */\n+\trun_vcpu_once(vcpus[0]);\n+\n+\tvcpu_get_clock_guest(vcpus[0], \u0026pvti);\n+\tTEST_ASSERT(pvti.flags \u0026 PVCLOCK_TSC_STABLE_BIT,\n+\t\t    \"PVCLOCK_TSC_STABLE_BIT should be set with matched TSCs\");\n+\n+\t/*\n+\t * Case 2: Different TSC offset, same frequency.\n+\t * Master clock should still be active (frequency matches), but\n+\t * PVCLOCK_TSC_STABLE_BIT should be cleared (offsets differ).\n+\t */\n+\tif (__vcpu_has_device_attr(vcpus[1], KVM_VCPU_TSC_CTRL,\n+\t\t\t\t   KVM_VCPU_TSC_OFFSET)) {\n+\t\tpr_info(\"  Skipping offset test (KVM_VCPU_TSC_OFFSET not supported)\\n\");\n+\t\tgoto case_freq;\n+\t}\n+\tvcpu_set_tsc_offset(vcpus[1], 12345678);\n+\trun_vcpu_once(vcpus[1]);\n+\trun_vcpu_once(vcpus[0]);\n+\n+\tret = __vcpu_get_clock_guest(vcpus[0], \u0026pvti);\n+\tif (ret) {\n+\t\t/*\n+\t\t * Master clock disabled by offset mismatch — old kernel.\n+\t\t * -ENODATA is the only legitimate reason to skip; anything\n+\t\t * else is a regression, not an old kernel.\n+\t\t */\n+\t\tTEST_ASSERT(errno == ENODATA,\n+\t\t\t    \"GET_CLOCK_GUEST failed with unexpected errno %d\", errno);\n+\t\tpr_info(\"  Skipping offset test (master clock requires matched offsets)\\n\");\n+\t\tgoto case_freq;\n+\t}\n+\tTEST_ASSERT(!(pvti.flags \u0026 PVCLOCK_TSC_STABLE_BIT),\n+\t\t    \"PVCLOCK_TSC_STABLE_BIT should be clear with offset-mismatched TSCs\");\n+\n+case_freq:\n+\t/*\n+\t * Case 3: Different TSC frequency.\n+\t * Master clock should be disabled entirely.\n+\t */\n+\tvcpu_ioctl(vcpus[1], KVM_SET_TSC_KHZ,\n+\t\t   (void *)(unsigned long)(__vcpu_ioctl(vcpus[1], KVM_GET_TSC_KHZ, NULL) / 2));\n+\t/* Write TSC to trigger kvm_synchronize_tsc / kvm_track_tsc_matching */\n+\tvcpu_set_msr(vcpus[1], MSR_IA32_TSC, 0);\n+\trun_vcpu_once(vcpus[1]);\n+\n+\tret = __vcpu_get_clock_guest(vcpus[0], \u0026pvti);\n+\tTEST_ASSERT(ret \u0026\u0026 errno == ENODATA,\n+\t\t    \"GET_CLOCK_GUEST should fail with frequency-mismatched TSCs, got %d (errno %d)\",\n+\t\t    ret, errno);\n+\n+\tkvm_vm_free(vm);\n+}\n+\n+static void test_clock_guest_with_offsets(void)\n+{\n+\tstruct pvclock_vcpu_time_info pvti0, pvti1, pvti1_after;\n+\tstruct kvm_vcpu *vcpus[2];\n+\tstruct kvm_vm *vm;\n+\ts64 delta;\n+\tint ret;\n+\n+\tpr_info(\"Testing KVM_[GS]ET_CLOCK_GUEST with different TSC offsets\\n\");\n+\n+\tvm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);\n+\tconfigure_pvclock(vm);\n+\n+\t/* Set different TSC offsets on the two vCPUs */\n+\tvcpu_set_tsc_offset(vcpus[0], 0);\n+\tvcpu_set_tsc_offset(vcpus[1], 1000000000ull);\n+\n+\t/* Run both to establish kvmclock */\n+\trun_vcpu_once(vcpus[0]);\n+\trun_vcpu_once(vcpus[1]);\n+\n+\t/* GET_CLOCK_GUEST on both — should succeed (master clock active) */\n+\tret = __vcpu_get_clock_guest(vcpus[0], \u0026pvti0);\n+\tif (ret) {\n+\t\tTEST_ASSERT(errno == ENODATA,\n+\t\t\t    \"GET_CLOCK_GUEST failed with unexpected errno %d\", errno);\n+\t\tpr_info(\"  Skipping (master clock requires matched offsets on this kernel)\\n\");\n+\t\tkvm_vm_free(vm);\n+\t\treturn;\n+\t}\n+\tvcpu_get_clock_guest(vcpus[1], \u0026pvti1);\n+\n+\t/* The tsc_timestamps should differ (different offsets) */\n+\tTEST_ASSERT(pvti0.tsc_timestamp != pvti1.tsc_timestamp,\n+\t\t    \"tsc_timestamps should differ with different offsets\");\n+\n+\t/* Sleep to let time elapse, then restore vcpu0's clock */\n+\tsleep(1);\n+\tvcpu_set_clock_guest(vcpus[0], \u0026pvti0);\n+\n+\t/* Run vcpu0 to process the clock update */\n+\trun_vcpu_once(vcpus[0]);\n+\n+\t/*\n+\t * After SET on vcpu0, verify the correction worked by getting\n+\t * the clock on vcpu0 again. The mul/shift should be the same,\n+\t * and computing kvmclock at the same TSC should give the same\n+\t * result as the original (within ±2ns).\n+\t */\n+\t{\n+\t\tstruct pvclock_vcpu_time_info pvti0_after;\n+\t\tu64 tsc_now, clk_from_old, clk_from_new;\n+\n+\t\tvcpu_get_clock_guest(vcpus[0], \u0026pvti0_after);\n+\n+\t\tTEST_ASSERT(pvti0_after.tsc_to_system_mul == pvti0.tsc_to_system_mul \u0026\u0026\n+\t\t\t    pvti0_after.tsc_shift == pvti0.tsc_shift,\n+\t\t\t    \"mul/shift changed across KVM_SET_CLOCK_GUEST\");\n+\n+\t\ttsc_now = pvti0_after.tsc_timestamp;\n+\t\tclk_from_old = pvclock_read_cycles(\u0026pvti0, tsc_now);\n+\t\tclk_from_new = pvclock_read_cycles(\u0026pvti0_after, tsc_now);\n+\n+\t\tdelta = (s64)clk_from_new - (s64)clk_from_old;\n+\t\tTEST_ASSERT(delta \u003e= -2 \u0026\u0026 delta \u003c= 2,\n+\t\t\t    \"clock correction delta should be \u003c=2ns, got %ld ns\",\n+\t\t\t    delta);\n+\t}\n+\n+\t/*\n+\t * Also verify that vcpu1's clock is still accessible (master\n+\t * clock still active with different offsets).\n+\t */\n+\tvcpu_get_clock_guest(vcpus[1], \u0026pvti1_after);\n+\n+\tkvm_vm_free(vm);\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/tsc_user_set_test.c b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c\nnew file mode 100644\nindex 00000000000000..a74eb78a975b2f\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c\n@@ -0,0 +1,153 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Test that the first userspace write to MSR_IA32_TSC takes effect\n+ * precisely, and is not subjected to the 1-second \"slop\" heuristic\n+ * which is only supposed to apply between successive *userspace*\n+ * writes (kvm-\u003earch.user_set_tsc).\n+ *\n+ * The kernel synchronizes the TSC internally when a vCPU is created\n+ * (and when its frequency is set). If any of those kernel-internal\n+ * paths incorrectly sets user_set_tsc, then the first genuine write\n+ * from userspace which happens to fall within 1 second of virtual\n+ * cycle time of the kernel's default generation is \"corrected\" to\n+ * match that generation instead of being honoured exactly. That\n+ * breaks the restore of a guest which has genuinely been running\n+ * for less than one second.\n+ *\n+ * Simulate exactly that: create a vCPU (kernel establishes a default\n+ * TSC generation starting near zero), then perform the first\n+ * host-initiated write with a value corresponding to ~500ms of guest\n+ * runtime. If the slop heuristic fires, the written value is snapped\n+ * back to the kernel's generation (near zero) and the TSC reads back\n+ * hundreds of milliseconds low. Repeat with an explicit\n+ * KVM_SET_TSC_KHZ on the never-run vCPU before the write: that is\n+ * another kernel-internal synchronization which must not arm the\n+ * heuristic (nor open a generation that swallows the first write).\n+ */\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+/*\n+ * Returns false when the attempt was inconclusive: a snapped-back value\n+ * tracks time since vCPU creation, so if creation-to-write time gets\n+ * anywhere near the written 500ms, a buggy kernel's value could land\n+ * inside the assertions' tolerance and pass. The caller retries.\n+ */\n+static bool test_first_write(bool set_freq)\n+{\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tu64 freq_khz, t_write, t_read, slack_cycles, mono_ns, create_ns, read_ns;\n+\tstruct timespec ts;\n+\tint r;\n+\n+\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts);\n+\tcreate_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, NULL);\n+\n+\tif (set_freq) {\n+\t\t/*\n+\t\t * Halve the frequency so this is a real change, exercising\n+\t\t * the frequency resynchronization path rather than the\n+\t\t * unchanged-frequency no-op.\n+\t\t */\n+\t\tr = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);\n+\t\tTEST_ASSERT(r \u003e 0, \"KVM_GET_TSC_KHZ failed\");\n+\t\tvcpu_ioctl(vcpu, KVM_SET_TSC_KHZ,\n+\t\t\t   (void *)(unsigned long)(r / 2));\n+\t}\n+\n+\tr = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);\n+\tTEST_ASSERT(r \u003e 0, \"KVM_GET_TSC_KHZ failed\");\n+\tfreq_khz = r;\n+\n+\t/*\n+\t * The first user write: a guest TSC corresponding to 500ms of\n+\t * runtime. This is within 1s (of virtual cycle time) of the\n+\t * kernel's default generation, so it is exactly the case that\n+\t * the slop heuristic would destroy if it were (incorrectly)\n+\t * armed by the kernel's own internal TSC synchronization.\n+\t */\n+\tt_write = freq_khz * 500ULL;\t\t/* khz * ms = cycles */\n+\n+\t/*\n+\t * Measure only the write..read window (a window measured from\n+\t * before creation would also bound a snapped-back value), and\n+\t * insist the write lands well before 500ms of creation time so\n+\t * a snapped-back value cannot sit inside the tolerance.\n+\t */\n+\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts);\n+\tmono_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;\n+\n+\tif (mono_ns - create_ns \u003e 250000000ULL) {\n+\t\tpr_info(\"  creation took %lu ms, retrying for a conclusive run\\n\",\n+\t\t\t(mono_ns - create_ns) / 1000000);\n+\t\tkvm_vm_free(vm);\n+\t\treturn false;\n+\t}\n+\n+\tvcpu_set_msr(vcpu, MSR_IA32_TSC, t_write);\n+\n+\tt_read = vcpu_get_msr(vcpu, MSR_IA32_TSC);\n+\n+\tclock_gettime(CLOCK_MONOTONIC_RAW, \u0026ts);\n+\tread_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;\n+\n+\t/*\n+\t * Bound the whole creation..read interval too: a snapped-back\n+\t * value tracks it, so letting it approach the written 500ms\n+\t * (via a stall between the two MSR ioctls, which the slack\n+\t * below would otherwise absorb) would let a buggy kernel pass.\n+\t */\n+\tif (read_ns - create_ns \u003e 400000000ULL) {\n+\t\tpr_info(\"  creation..read took %lu ms, retrying for a conclusive run\\n\",\n+\t\t\t(read_ns - create_ns) / 1000000);\n+\t\tkvm_vm_free(vm);\n+\t\treturn false;\n+\t}\n+\n+\tmono_ns = read_ns - mono_ns;\n+\n+\t/*\n+\t * The TSC advances between the write and the read; bound the\n+\t * difference by the measured elapsed time around the two ioctls\n+\t * plus 10ms of slop, so a descheduled test cannot flake. If the\n+\t * write was snapped to the kernel's default generation, the\n+\t * value read back is ~500ms low (i.e. below t_write), which is\n+\t * unambiguous.\n+\t */\n+\tslack_cycles = freq_khz * (mono_ns / 1000000ULL + 10);\n+\n+\tTEST_ASSERT(t_read \u003e= t_write,\n+\t\t    \"TSC went backwards from explicit write: wrote %lu, read %lu\"\n+\t\t    \" (first userspace write was subjected to 1-second slop?)\",\n+\t\t    t_write, t_read);\n+\tTEST_ASSERT(t_read - t_write \u003c slack_cycles,\n+\t\t    \"TSC read back too far from written value: wrote %lu, read %lu\",\n+\t\t    t_write, t_read);\n+\n+\tkvm_vm_free(vm);\n+\treturn true;\n+}\n+\n+static void run_first_write(bool set_freq)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i \u003c 5; i++)\n+\t\tif (test_first_write(set_freq))\n+\t\t\treturn;\n+\n+\tTEST_FAIL(\"vCPU creation repeatedly too slow for a conclusive run\");\n+}\n+\n+int main(void)\n+{\n+\trun_first_write(false);\n+\n+\tif (kvm_has_cap(KVM_CAP_TSC_CONTROL))\n+\t\trun_first_write(true);\n+\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c\nnew file mode 100644\nindex 00000000000000..70d3d38966f239\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c\n@@ -0,0 +1,271 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Test that userspace can correctly populate Xen and generic CPUID\n+ * timing leaves using KVM_GET_TSC_KHZ and KVM_VCPU_TSC_SCALE.\n+ *\n+ * This validates that the removal of KVM's runtime Xen CPUID modification\n+ * doesn't break guests, because userspace has all the information needed.\n+ */\n+#include \u003cstdint.h\u003e\n+#include \u003cstdlib.h\u003e\n+#include \u003cstring.h\u003e\n+\n+#include \"test_util.h\"\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+\n+#define XEN_CPUID_BASE\t\t0x40000100\n+#define XEN_CPUID_LEAF(n)\t(XEN_CPUID_BASE + (n))\n+#define GENERIC_TIMING_LEAF\t0x40000010\n+\n+/*\n+ * Sentinel in Xen leaf 3 sub-leaf 2 EAX (where the removed runtime\n+ * update used to write the vCPU's tsc_khz): it must survive untouched.\n+ */\n+#define XEN_SENTINEL\t\t0xdeadbeef\n+\n+/* Values set by host, verified by guest */\n+static u32 expected_tsc_khz;\n+static u32 expected_bus_khz;\n+static u32 expected_tsc_mul;\n+static s8   expected_tsc_shift;\n+static u64 host_khz;\n+static bool xen_enabled;\n+\n+static void guest_code(void)\n+{\n+\tu32 eax, ebx, ecx, edx;\n+\n+\t/* Check generic timing leaf 0x40000010 */\n+\t__cpuid(GENERIC_TIMING_LEAF, 0, \u0026eax, \u0026ebx, \u0026ecx, \u0026edx);\n+\tGUEST_ASSERT_EQ(eax, expected_tsc_khz);\n+\tGUEST_ASSERT_EQ(ebx, expected_bus_khz);\n+\n+\t/* Check Xen leaf 3, sub-leaf 0: ECX = guest TSC frequency */\n+\t__cpuid(XEN_CPUID_LEAF(3), 0, \u0026eax, \u0026ebx, \u0026ecx, \u0026edx);\n+\tGUEST_ASSERT_EQ(ecx, expected_tsc_khz);\n+\n+\t/* Check Xen leaf 3, sub-leaf 1: ECX = mul, EDX = shift */\n+\t__cpuid(XEN_CPUID_LEAF(3), 1, \u0026eax, \u0026ebx, \u0026ecx, \u0026edx);\n+\tGUEST_ASSERT_EQ(ecx, expected_tsc_mul);\n+\tGUEST_ASSERT_EQ((s8)edx, expected_tsc_shift);\n+\n+\tif (xen_enabled) {\n+\t\t/*\n+\t\t * With the Xen signature present and Xen enabled, verify the\n+\t\t * sentinel survives: KVM's removed runtime CPUID update used\n+\t\t * to clobber this sub-leaf for exactly this configuration.\n+\t\t */\n+\t\t__cpuid(XEN_CPUID_LEAF(3), 2, \u0026eax, \u0026ebx, \u0026ecx, \u0026edx);\n+\t\tGUEST_ASSERT_EQ(eax, XEN_SENTINEL);\n+\t}\n+\n+\tGUEST_SYNC(0);\n+}\n+\n+static void add_cpuid_entry(struct kvm_vcpu *vcpu, u32 function,\n+\t\t\t    u32 index, u32 eax, u32 ebx,\n+\t\t\t    u32 ecx, u32 edx)\n+{\n+\tstruct kvm_cpuid2 *cpuid = vcpu-\u003ecpuid;\n+\tstruct kvm_cpuid_entry2 *entry;\n+\tint n = cpuid-\u003enent;\n+\n+\tcpuid = realloc(vcpu-\u003ecpuid,\n+\t\t\tsizeof(*cpuid) + (n + 1) * sizeof(*entry));\n+\tTEST_ASSERT(cpuid, \"Failed to grow vCPU CPUID array\");\n+\tvcpu-\u003ecpuid = cpuid;\n+\tcpuid-\u003enent = n + 1;\n+\n+\tentry = \u0026cpuid-\u003eentries[n];\n+\tmemset(entry, 0, sizeof(*entry));\n+\tentry-\u003efunction = function;\n+\tentry-\u003eindex = index;\n+\tentry-\u003eflags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;\n+\tentry-\u003eeax = eax;\n+\tentry-\u003eebx = ebx;\n+\tentry-\u003eecx = ecx;\n+\tentry-\u003eedx = edx;\n+}\n+\n+/*\n+ * Compute pvclock mul/shift from frequency, matching kvm_get_time_scale().\n+ */\n+static void compute_tsc_mul_shift(u64 tsc_hz, u32 *mul, s8 *shift)\n+{\n+\tu64 scaled = 1000000000ULL;\n+\tu64 base = tsc_hz;\n+\ts32 s = 0;\n+\tu32 base32;\n+\n+\twhile (base \u003e scaled * 2 || base \u003e\u003e 32) {\n+\t\tbase \u003e\u003e= 1;\n+\t\ts--;\n+\t}\n+\tbase32 = (u32)base;\n+\twhile (base32 \u003c= scaled || scaled \u003e\u003e 32) {\n+\t\tif (scaled \u003e\u003e 32 || base32 \u0026 (1U \u003c\u003c 31))\n+\t\t\tscaled \u003e\u003e= 1;\n+\t\telse\n+\t\t\tbase32 \u003c\u003c= 1;\n+\t\ts++;\n+\t}\n+\t*mul = (u32)((scaled \u003c\u003c 32) / base32);\n+\t*shift = (s8)s;\n+}\n+\n+static void run_test(u64 tsc_khz)\n+{\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tstruct ucall uc;\n+\tu32 effective_tsc_khz, effective_bus_khz;\n+\tint bus_cycle_ns, ret;\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\n+\tif (tsc_khz) {\n+\t\tpr_info(\"Testing at TSC frequency %lu kHz\\n\", tsc_khz);\n+\t\tvcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)tsc_khz);\n+\t} else {\n+\t\tpr_info(\"Testing at native TSC frequency\\n\");\n+\t}\n+\n+\tret = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);\n+\tTEST_ASSERT(ret \u003e 0, \"KVM_GET_TSC_KHZ failed: %d\", ret);\n+\teffective_tsc_khz = ret;\n+\tbus_cycle_ns = vm_check_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS);\n+\teffective_bus_khz = bus_cycle_ns \u003e 0 ? 1000000 / bus_cycle_ns : 1000000;\n+\n+\tpr_info(\"  Effective TSC: %u kHz, Bus: %u kHz\\n\", effective_tsc_khz, effective_bus_khz);\n+\n+\t/* Also exercise KVM_VCPU_TSC_SCALE if available */\n+\tif (!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,\n+\t\t\t\t    KVM_VCPU_TSC_SCALE)) {\n+\t\tstruct kvm_vcpu_tsc_scale scale;\n+\n+\t\tvcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL,\n+\t\t\t\t     KVM_VCPU_TSC_SCALE, \u0026scale);\n+\t\tpr_info(\"  TSC scale: ratio=%llu frac_bits=%llu\\n\",\n+\t\t\tscale.tsc_ratio, scale.tsc_frac_bits);\n+\n+\t\t/*\n+\t\t * A requested frequency within tsc_tolerance_ppm of the\n+\t\t * host's does not engage hardware scaling: the effective\n+\t\t * frequency is the requested one but the ratio stays 1.0,\n+\t\t * so the ratio cross-check cannot hold. Skip only that\n+\t\t * check — the CPUID leaf population and guest verification\n+\t\t * below are about the effective frequency and remain valid.\n+\t\t */\n+\t\tif (tsc_khz \u0026\u0026\n+\t\t    scale.tsc_ratio == (1ULL \u003c\u003c scale.tsc_frac_bits)) {\n+\t\t\tpr_info(\"  Requested frequency within host tolerance; scaling not engaged, skipping ratio cross-check\\n\");\n+\t\t} else if (tsc_khz) {\n+\t\t\t/*\n+\t\t\t * Verify: applying the ratio to the host TSC frequency\n+\t\t\t * should give approximately the effective frequency.\n+\t\t\t */\n+\t\t\tu64 computed = ((__uint128_t)host_khz * scale.tsc_ratio) \u003e\u003e scale.tsc_frac_bits;\n+\t\t\ts64 diff = (s64)computed - (s64)effective_tsc_khz;\n+\n+\t\t\tTEST_ASSERT(diff \u003e= -1 \u0026\u0026 diff \u003c= 1,\n+\t\t\t\t    \"TSC_SCALE ratio mismatch: computed %lu vs effective %u (diff %ld)\",\n+\t\t\t\t    computed, effective_tsc_khz, diff);\n+\t\t}\n+\t}\n+\n+\tcompute_tsc_mul_shift((u64)effective_tsc_khz * 1000,\n+\t\t\t      \u0026expected_tsc_mul, \u0026expected_tsc_shift);\n+\n+\texpected_tsc_khz = effective_tsc_khz;\n+\texpected_bus_khz = effective_bus_khz;\n+\n+\tsync_global_to_guest(vm, expected_tsc_khz);\n+\tsync_global_to_guest(vm, expected_bus_khz);\n+\tsync_global_to_guest(vm, expected_tsc_mul);\n+\tsync_global_to_guest(vm, expected_tsc_shift);\n+\n+\t/* Populate CPUID leaves as a VMM would */\n+\tadd_cpuid_entry(vcpu, GENERIC_TIMING_LEAF, 0,\n+\t\t\teffective_tsc_khz, effective_bus_khz, 0, 0);\n+\tadd_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 0,\n+\t\t\t0, 0, effective_tsc_khz, 0);\n+\tadd_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 1,\n+\t\t\t0, 0, expected_tsc_mul,\n+\t\t\t(u32)(s32)expected_tsc_shift);\n+\n+\t/*\n+\t * Where possible, make this a real Xen guest: install the Xen\n+\t * signature leaf and enable the Xen hypercall MSR, which is the\n+\t * configuration in which KVM's removed runtime CPUID update used\n+\t * to fire, and plant a sentinel where it used to write.\n+\t */\n+\txen_enabled = kvm_has_cap(KVM_CAP_XEN_HVM);\n+\tif (xen_enabled) {\n+\t\tstruct kvm_xen_hvm_config cfg = {\n+\t\t\t.msr = 0x40000200,\n+\t\t};\n+\n+\t\tvm_ioctl(vm, KVM_XEN_HVM_CONFIG, \u0026cfg);\n+\t\tadd_cpuid_entry(vcpu, XEN_CPUID_BASE, 0, XEN_CPUID_LEAF(4),\n+\t\t\t\t0x566e6558 /* \"XenV\" */,\n+\t\t\t\t0x65584d4d /* \"MMXe\" */,\n+\t\t\t\t0x4d4d566e /* \"nVMM\" */);\n+\t\tadd_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 2,\n+\t\t\t\tXEN_SENTINEL, 0, 0, 0);\n+\t}\n+\tsync_global_to_guest(vm, xen_enabled);\n+\n+\tvcpu_set_cpuid(vcpu);\n+\n+\tpr_info(\"  pvclock mul=%u shift=%d\\n\", expected_tsc_mul, expected_tsc_shift);\n+\n+\tvcpu_run(vcpu);\n+\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\n+\tswitch (get_ucall(vcpu, \u0026uc)) {\n+\tcase UCALL_ABORT:\n+\t\tREPORT_GUEST_ASSERT(uc);\n+\t\tbreak;\n+\tcase UCALL_SYNC:\n+\t\tbreak;\n+\tdefault:\n+\t\tTEST_FAIL(\"Unexpected ucall\");\n+\t}\n+\n+\tkvm_vm_free(vm);\n+}\n+\n+int main(void)\n+{\n+\tu64 freq;\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tbool have_tsc_scale;\n+\n+\tTEST_REQUIRE(sys_clocksource_is_based_on_tsc());\n+\n+\tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n+\thave_tsc_scale = !__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,\n+\t\t\t\t\t\t KVM_VCPU_TSC_SCALE);\n+\thost_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);\n+\tkvm_vm_free(vm);\n+\n+\t/* Native frequency */\n+\trun_test(0);\n+\n+\t/* Scaled frequencies, when hardware TSC scaling is available */\n+\tif (have_tsc_scale) {\n+\t\tfor (freq = 1000000; freq \u003c= 4000000; freq += 1000000) {\n+\t\t\tif (freq == host_khz)\n+\t\t\t\tcontinue;\n+\t\t\trun_test(freq);\n+\t\t}\n+\t} else {\n+\t\tpr_info(\"Skipping scaled frequencies (no TSC scaling)\\n\");\n+\t}\n+\n+\tpr_info(\"PASS: All CPUID timing leaf tests passed\\n\");\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/xen_migration_test.c b/tools/testing/selftests/kvm/x86/xen_migration_test.c\nnew file mode 100644\nindex 00000000000000..564781db3da286\n--- /dev/null\n+++ b/tools/testing/selftests/kvm/x86/xen_migration_test.c\n@@ -0,0 +1,222 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Test Xen runstate (steal time) preservation across simulated migration.\n+ *\n+ * Verifies that the kernel correctly accounts the migration gap as\n+ * steal time (runnable) when runstate data is saved and restored\n+ * precisely, but real time elapses during the migration.\n+ *\n+ * The key insight: userspace saves the runstate with state=RUNSTATE_runnable\n+ * (the vCPU is not running during migration). On restore, the kernel sees\n+ * that kvmclock has advanced past state_entry_time, and accounts the\n+ * difference as time spent in the runnable state.\n+ */\n+#include \u003cinttypes.h\u003e\n+#include \u003cstdint.h\u003e\n+#include \u003cstdio.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cunistd.h\u003e\n+\n+#include \"test_util.h\"\n+#include \"kvm_util.h\"\n+#include \"processor.h\"\n+\n+#include \u003casm/pvclock-abi.h\u003e\n+\n+#define SHINFO_GPA\t0xc0000000ULL\n+#define RUNSTATE_GPA\t(SHINFO_GPA + 0x1000)\n+\n+#define RUNSTATE_running  0\n+#define RUNSTATE_runnable 1\n+#define RUNSTATE_blocked  2\n+#define RUNSTATE_offline  3\n+\n+/*\n+ * The 64-bit (long mode) layout: 'state' is followed by 4 bytes of\n+ * padding so state_entry_time is naturally aligned. The VM is placed\n+ * in long mode explicitly below; without that, KVM would latch 32-bit\n+ * mode (no hypercall-page write ever happens here to latch it from\n+ * EFER) and write the packed compat layout instead.\n+ */\n+struct vcpu_runstate_info {\n+\tu32 state;\n+\tu64 state_entry_time;\n+\tu64 time[4];\n+};\n+\n+static void guest_code(void)\n+{\n+\tvolatile struct vcpu_runstate_info *rs =\n+\t\t(void *)(unsigned long)RUNSTATE_GPA;\n+\n+\t/* Report runstate times — no need to enable kvmclock MSR,\n+\t * the kernel writes runstate using its internal kvmclock. */\n+\tGUEST_SYNC_ARGS(0, rs-\u003etime[RUNSTATE_runnable],\n+\t\t\trs-\u003etime[RUNSTATE_running], 0, 0);\n+}\n+\n+static struct kvm_vm *create_xen_vm(struct kvm_vcpu **vcpu)\n+{\n+\tstruct kvm_vm *vm;\n+\tint xen_caps;\n+\n+\tvm = vm_create_with_one_vcpu(vcpu, guest_code);\n+\n+\txen_caps = kvm_check_cap(KVM_CAP_XEN_HVM);\n+\tTEST_REQUIRE(xen_caps \u0026 KVM_XEN_HVM_CONFIG_SHARED_INFO);\n+\tTEST_REQUIRE(xen_caps \u0026 KVM_XEN_HVM_CONFIG_RUNSTATE);\n+\n+\t/* Map pages */\n+\tvm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,\n+\t\t\t\t    SHINFO_GPA, 1, 2, 0);\n+\tvirt_map(vm, SHINFO_GPA, SHINFO_GPA, 2);\n+\n+\t/* Enable Xen HVM with MSR interception (enables runstate tracking) */\n+\tstruct kvm_xen_hvm_config cfg = {\n+\t\t.flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,\n+\t\t.msr = 0x40000000,\n+\t};\n+\tvm_ioctl(vm, KVM_XEN_HVM_CONFIG, \u0026cfg);\n+\n+\t/* The guest runs in long mode; make the runstate layout match. */\n+\tstruct kvm_xen_hvm_attr lm = {\n+\t\t.type = KVM_XEN_ATTR_TYPE_LONG_MODE,\n+\t\t.u.long_mode = 1,\n+\t};\n+\tvm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, \u0026lm);\n+\n+\t/* Set shared_info */\n+\tstruct kvm_xen_hvm_attr ha = {\n+\t\t.type = KVM_XEN_ATTR_TYPE_SHARED_INFO,\n+\t\t.u.shared_info.gfn = SHINFO_GPA \u003e\u003e 12,\n+\t};\n+\tvm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, \u0026ha);\n+\n+\t/* Set runstate address */\n+\tstruct kvm_xen_vcpu_attr rs_addr = {\n+\t\t.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,\n+\t\t.u.gpa = RUNSTATE_GPA,\n+\t};\n+\tvcpu_ioctl(*vcpu, KVM_XEN_VCPU_SET_ATTR, \u0026rs_addr);\n+\n+\treturn vm;\n+}\n+\n+int main(void)\n+{\n+\tstruct pvclock_vcpu_time_info pvti;\n+\tstruct kvm_xen_vcpu_attr runstate_save;\n+\tstruct kvm_vcpu *vcpu;\n+\tstruct kvm_vm *vm;\n+\tstruct ucall uc;\n+\tu64 tsc_offset;\n+\tint ret;\n+\n+\tTEST_REQUIRE(sys_clocksource_is_based_on_tsc());\n+\tTEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));\n+\n+\t/* === SOURCE SIDE === */\n+\tpr_info(\"=== Source: create VM and run guest ===\\n\");\n+\tvm = create_xen_vm(\u0026vcpu);\n+\n+\t/* Run guest once to accumulate some runstate time */\n+\tvcpu_run(vcpu);\n+\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\tTEST_ASSERT_EQ(get_ucall(vcpu, \u0026uc), UCALL_SYNC);\n+\n+\tpr_info(\"  Guest sees: runnable=%\" PRIu64 \" running=%\" PRIu64 \"\\n\",\n+\t\tuc.args[2], uc.args[3]);\n+\n+\t/* Save clock state */\n+\tvcpu_get_clock_guest(vcpu, \u0026pvti);\n+\n+\t/*\n+\t * Save the guest TSC offset. This test migrates to a new VM on\n+\t * the same host, so restoring the same offset makes the guest\n+\t * TSC continue uninterrupted across the migration gap, and the\n+\t * restored pvclock (KVM_SET_CLOCK_GUEST) then yields a kvmclock\n+\t * which has also kept running across the gap. (A real migration\n+\t * to a different host would compute the destination offset from\n+\t * KVM_GET_CLOCK's {host_tsc, realtime} pair as described in\n+\t * Documentation/virt/kvm/devices/vcpu.rst.)\n+\t */\n+\ttsc_offset = vcpu_get_tsc_offset(vcpu);\n+\n+\t/* Save runstate — the vCPU is now \"runnable\" (not running) */\n+\trunstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;\n+\tvcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, \u0026runstate_save);\n+\n+\t/*\n+\t * Transition to runnable state before saving — the vCPU is\n+\t * not running during migration.\n+\t */\n+\trunstate_save.u.runstate.state = RUNSTATE_runnable;\n+\n+\tpr_info(\"  Saved runstate: running=%\" PRIu64 \" runnable=%\" PRIu64\n+\t\t\" entry=%\" PRIu64 \"\\n\",\n+\t\t(u64)runstate_save.u.runstate.time_running,\n+\t\t(u64)runstate_save.u.runstate.time_runnable,\n+\t\t(u64)runstate_save.u.runstate.state_entry_time);\n+\n+\tu64 saved_runnable = runstate_save.u.runstate.time_runnable;\n+\n+\tkvm_vm_free(vm);\n+\n+\t/* === MIGRATION GAP === */\n+\tpr_info(\"=== Simulating migration (sleeping 10ms) ===\\n\");\n+\tusleep(10000);\n+\n+\t/* === DESTINATION SIDE === */\n+\tpr_info(\"=== Destination: create new VM and restore ===\\n\");\n+\tvm = create_xen_vm(\u0026vcpu);\n+\n+\t/* Restore the guest TSC offset (same host: TSC continues) */\n+\tvcpu_set_tsc_offset(vcpu, tsc_offset);\n+\n+\t/* Restore clock — kvmclock will now be ~10ms ahead of the snapshot */\n+\tvcpu_set_clock_guest(vcpu, \u0026pvti);\n+\n+\t/* Restore runstate exactly as saved (state=runnable) */\n+\trunstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;\n+\tret = __vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, \u0026runstate_save);\n+\tTEST_ASSERT(!ret, \"Restore runstate failed: errno %d\", errno);\n+\n+\t/*\n+\t * Run the guest. When the vCPU enters vcpu_run, the kernel\n+\t * transitions from RUNSTATE_runnable to RUNSTATE_running.\n+\t * It computes: delta = kvmclock_now - state_entry_time\n+\t * This delta (which includes the migration gap) is added to\n+\t * time_runnable (steal time).\n+\t */\n+\tvcpu_run(vcpu);\n+\tTEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);\n+\tTEST_ASSERT_EQ(get_ucall(vcpu, \u0026uc), UCALL_SYNC);\n+\n+\tu64 guest_runnable = uc.args[2];\n+\tu64 guest_running = uc.args[3];\n+\n+\tpr_info(\"  Guest sees: runnable=%\" PRIu64 \" running=%\" PRIu64 \"\\n\",\n+\t\tguest_runnable, guest_running);\n+\n+\tu64 steal_increase = guest_runnable - saved_runnable;\n+\tpr_info(\"  Steal time increase: %\" PRIu64 \" ns (migration gap)\\n\",\n+\t\tsteal_increase);\n+\n+\t/*\n+\t * The steal time increase should be at least 10ms (the sleep).\n+\t * The actual gap runs from the source's state_entry_time to the\n+\t * destination's kvmclock \"now\" at vcpu_load time, which includes\n+\t * everything from the source guest's last runstate transition\n+\t * through VM teardown and re-creation — so the upper bound exists\n+\t * only to catch wild miscalculation (e.g. an unscaled TSC delta),\n+\t * and is deliberately generous for slow or loaded hosts.\n+\t */\n+\tTEST_ASSERT(steal_increase \u003e= 10000000ULL \u0026\u0026\n+\t\t    steal_increase \u003c 60000000000ULL,\n+\t\t    \"Steal time increase %\" PRIu64 \" ns not in expected range \"\n+\t\t    \"[10ms, 60s]\", steal_increase);\n+\n+\tkvm_vm_free(vm);\n+\tpr_info(\"PASS: Migration gap correctly accounted as steal time\\n\");\n+\treturn 0;\n+}\ndiff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\nindex aaa414c677addf..43548d8faa74d4 100644\n--- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\n+++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\n@@ -98,22 +98,7 @@ struct sched_poll {\n \tu64 timeout;\n };\n \n-struct pvclock_vcpu_time_info {\n-\tu32   version;\n-\tu32   pad0;\n-\tu64   tsc_timestamp;\n-\tu64   system_time;\n-\tu32   tsc_to_system_mul;\n-\ts8    tsc_shift;\n-\tu8    flags;\n-\tu8    pad[2];\n-} __attribute__((__packed__)); /* 32 bytes */\n-\n-struct pvclock_wall_clock {\n-\tu32   version;\n-\tu32   sec;\n-\tu32   nsec;\n-} __attribute__((__packed__));\n+#include \u003casm/pvclock-abi.h\u003e\n \n struct vcpu_runstate_info {\n \tu32 state;\n@@ -987,12 +972,14 @@ int main(int argc, char *argv[])\n \n \tif (verbose) {\n \t\tprintf(\"Wall clock (v %d) %d.%09d\\n\", wc-\u003eversion, wc-\u003esec, wc-\u003ensec);\n-\t\tprintf(\"Time info 1: v %u tsc %\" PRIu64 \" time %\" PRIu64 \" mul %u shift %u flags %x\\n\",\n-\t\t       ti-\u003eversion, ti-\u003etsc_timestamp, ti-\u003esystem_time, ti-\u003etsc_to_system_mul,\n-\t\t       ti-\u003etsc_shift, ti-\u003eflags);\n-\t\tprintf(\"Time info 2: v %u tsc %\" PRIu64 \" time %\" PRIu64 \" mul %u shift %u flags %x\\n\",\n-\t\t       ti2-\u003eversion, ti2-\u003etsc_timestamp, ti2-\u003esystem_time, ti2-\u003etsc_to_system_mul,\n-\t\t       ti2-\u003etsc_shift, ti2-\u003eflags);\n+\t\tprintf(\"Time info 1: v %u tsc %llu time %llu mul %u shift %d flags %x\\n\",\n+\t\t       ti-\u003eversion, (unsigned long long)ti-\u003etsc_timestamp,\n+\t\t       (unsigned long long)ti-\u003esystem_time,\n+\t\t       ti-\u003etsc_to_system_mul, ti-\u003etsc_shift, ti-\u003eflags);\n+\t\tprintf(\"Time info 2: v %u tsc %llu time %llu mul %u shift %d flags %x\\n\",\n+\t\t       ti2-\u003eversion, (unsigned long long)ti2-\u003etsc_timestamp,\n+\t\t       (unsigned long long)ti2-\u003esystem_time,\n+\t\t       ti2-\u003etsc_to_system_mul, ti2-\u003etsc_shift, ti2-\u003eflags);\n \t}\n \n \tTEST_ASSERT(wc-\u003eversion \u0026\u0026 !(wc-\u003eversion \u0026 1),\n"
}

2/1 2026/11/11 17:18 agent patch-evaluator
2m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "KVM",
    "KVM_INTEL",
    "KVM_AMD",
    "KVM_XEN"
  ],
  "FocusSymbols": [
    "kvm_vcpu_ioctl_get_clock_guest",
    "kvm_vcpu_ioctl_set_clock_guest",
    "kvm_set_tsc_khz",
    "kvm_synchronize_tsc",
    "kvm_arch_tsc_get_attr",
    "kvm_arch_tsc_set_attr",
    "kvm_update_masterclock",
    "kvm_vm_ioctl_set_clock",
    "kvm_write_system_time",
    "kvm_xen_start_timer"
  ],
  "Reasoning": "The patch series introduces new KVM ioctls (KVM_GET_CLOCK_GUEST, KVM_SET_CLOCK_GUEST), a new vCPU device attribute (KVM_VCPU_TSC_SCALE), and significantly refactors KVM TSC synchronization and master clock management (allowing divergent TSC offsets without disabling master clock mode, updating generation tracking, and refining pvclock updates). These changes modify reachable, executable code in the x86 KVM subsystem accessible via userspace ioctls and warrant fuzzing.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 840dfffc5f02909c098eb4036b0c016646e5edff
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Nov 11 17:18:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index ddc61ea36ac59d..44c6152c5768da 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2023,6 +2023,14 @@ If the KVM_CAP_VM_TSC_CONTROL capability is advertised, this can also
 be used as a vm ioctl to set the initial tsc frequency of subsequently
 created vCPUs.  Note, the vm ioctl is only allowed prior to creating vCPUs.
 
+Changing the frequency of a vCPU with the vcpu ioctl re-synchronizes
+its TSC: for a vCPU which has run, or whose TSC userspace has written,
+the current guest TSC value is preserved across the change (the TSC
+offset, as visible through the KVM_VCPU_TSC_OFFSET attribute, is
+rewritten accordingly); otherwise the vCPU is synchronized to the
+VM's existing TSC timeline at the new frequency. Setting the current
+frequency again is a no-op.
+
 For TSC protected Confidential Computing (CoCo) VMs where TSC frequency
 is configured once at VM scope and remains unchanged during VM's
 lifetime, the vm ioctl should be used to configure the TSC frequency
@@ -6759,6 +6767,59 @@ if the guest_memfd memory was pinned in IOMMU page tables.
 
 See also: :ref:`KVM_SET_MEMORY_ATTRIBUTES`.
 
+4.147 KVM_GET_CLOCK_GUEST
+----------------------------
+
+:Capability: KVM_CAP_CLOCK_GUEST
+:Architectures: x86_64
+:Type: vcpu ioctl
+:Parameters: struct pvclock_vcpu_time_info (out)
+:Returns: 0 on success, <0 on error
+
+Retrieves the current time information structure used for KVM/PV clocks,
+in precisely the form advertised to the guest vCPU, which gives parameters
+for a direct conversion from a guest TSC value to nanoseconds.
+
+The structure is in terms of the given vCPU's TSC. It must be passed back
+to KVM_SET_CLOCK_GUEST on the *same* vCPU (on the destination VM, for
+migration); vCPUs may legitimately have different TSC offsets, which would
+otherwise be silently folded into the restored KVM clock.
+
+When the KVM clock is not in "master clock" mode, for example because the
+host TSC is unreliable or the guest TSCs are oddly configured, the KVM clock
+is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest TSC.
+In this case, the KVM_GET_CLOCK_GUEST ioctl returns -ENODATA.
+
+4.148 KVM_SET_CLOCK_GUEST
+----------------------------
+
+:Capability: KVM_CAP_CLOCK_GUEST
+:Architectures: x86_64
+:Type: vcpu ioctl
+:Parameters: struct pvclock_vcpu_time_info (in)
+:Returns: 0 on success, <0 on error
+
+Sets the KVM clock (for the whole VM) in terms of the vCPU TSC, using the
+pvclock structure as returned by KVM_GET_CLOCK_GUEST. This allows the precise
+arithmetic relationship between guest TSC and KVM clock to be preserved by
+userspace across migration.
+
+When the KVM clock is not in "master clock" mode, and the KVM clock is actually
+defined by the host CLOCK_MONOTONIC_RAW, this ioctl returns -ENODATA. Userspace
+may choose to set the clock using the less precise KVM_SET_CLOCK ioctl, or may
+choose to fail, denying migration to a host whose TSC is misbehaving. A host
+whose CPU TSC frequency is unknown (only possible without
+X86_FEATURE_CONSTANT_TSC) is never in "master clock" mode, so it also returns
+-ENODATA.
+
+If the mul/shift fields of the provided pvclock structure encode a TSC
+frequency inconsistent with the vCPU's actual TSC frequency, this ioctl
+returns -ERANGE.
+
+If the vCPU's current TSC is behind the tsc_timestamp in the provided
+structure, this ioctl returns -EINVAL. Restore the guest TSC (which the
+documented migration procedure keeps monotonic) before invoking it.
+
 .. _kvm_run:
 
 5. The kvm_run structure
diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst
index deb5c51bc00c87..8dc6ad904429dd 100644
--- a/Documentation/virt/kvm/devices/vcpu.rst
+++ b/Documentation/virt/kvm/devices/vcpu.rst
@@ -239,6 +239,7 @@ including the layout of the stolen time structure.
 :Architectures: x86
 
 4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET
+----------------------------------
 
 :Parameters: 64-bit unsigned TSC offset
 
@@ -253,7 +254,10 @@ Returns:
 Specifies the guest's TSC offset relative to the host's TSC. The guest's
 TSC is then derived by the following equation:
 
-  guest_tsc = host_tsc + KVM_VCPU_TSC_OFFSET
+  guest_tsc = ((host_tsc * tsc_ratio) >> tsc_frac_bits) + KVM_VCPU_TSC_OFFSET
+
+The values of tsc_ratio and tsc_frac_bits can be obtained using
+the KVM_VCPU_TSC_SCALE attribute.
 
 This attribute is useful to adjust the guest's TSC on live migration,
 so that the TSC counts the time during which the VM was paused. The
@@ -261,44 +265,117 @@ following describes a possible algorithm to use for this purpose.
 
 From the source VMM process:
 
-1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_src),
+1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_src),
    kvmclock nanoseconds (guest_src), and host CLOCK_REALTIME nanoseconds
-   (host_src).
+   (time_src) at a given moment (Tsrc). The host_tsc field is only valid
+   when the returned flags include KVM_CLOCK_HOST_TSC.
+
+2. For each vCPU[i]:
+
+   a. Read the KVM_VCPU_TSC_OFFSET attribute to record the guest TSC offset
+      (ofs_src[i]).
+
+   b. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling
+      ratio (ratio_src[i], frac_bits_src[i]). If the attribute is not
+      supported (-ENXIO), there is no hardware TSC scaling and identity
+      scaling applies: use ratio 1, frac_bits 0.
+
+   c. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the
+      guest's TSC (freq[i]).
+
+   d. Use host_tsc_src and the scaling/offset factors to calculate this
+      vCPU's TSC at time Tsrc:
+
+      tsc_src[i] = ((host_tsc_src * ratio_src[i]) >> frac_bits_src[i]) + ofs_src[i]
 
-2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the
-   guest TSC offset (ofs_src[i]).
+      Note that frac_bits may be as high as 48, so this multiplication
+      needs a 128-bit intermediate to avoid overflow.
 
-3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the
-   guest's TSC (freq).
+3. Invoke the KVM_GET_CLOCK_GUEST ioctl on the boot vCPU to return the KVM
+   clock as a function of the guest TSC (pvti_src). (This ioctl may not
+   succeed if the host and guest TSCs are not consistent and well-behaved.)
 
 From the destination VMM process:
 
-4. Invoke the KVM_SET_CLOCK ioctl, providing the source nanoseconds from
-   kvmclock (guest_src) and CLOCK_REALTIME (host_src) in their respective
-   fields.  Ensure that the KVM_CLOCK_REALTIME flag is set in the provided
-   structure.
+4. Invoke the KVM_SET_TSC_KHZ ioctl to set the scaled frequency of the
+   guest's TSC (freq[i]) — either on the VM before creating the vCPUs, or
+   on each vCPU after creating it (as the exemplar test does). When using
+   the per-vCPU form, set the frequency before performing step 7 on that
+   vCPU: KVM_VCPU_TSC_SCALE reports the ratio for the currently
+   configured frequency.
+
+5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_dst) and
+   host CLOCK_REALTIME nanoseconds (time_dst) at a given moment (Tdst),
+   again checking KVM_CLOCK_HOST_TSC in the returned flags.
+
+6. Calculate the number of nanoseconds elapsed between Tsrc and Tdst:
+
+   ΔT = time_dst - time_src
+
+7. As each vCPU[i] is created:
+
+   a. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling
+      ratio (ratio_dst[i], frac_bits_dst[i]). As in step 2b, -ENXIO means
+      identity scaling: use ratio 1, frac_bits 0.
+
+   b. Calculate the intended guest TSC value at time Tdst, taking care
+      with the units (ΔT is in nanoseconds; freq, as set by
+      KVM_SET_TSC_KHZ, is in kHz):
 
-   KVM will advance the VM's kvmclock to account for elapsed time since
-   recording the clock values.  Note that this will cause problems in
-   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized
-   between the source and destination, and a reasonably short time passes
-   between the source pausing the VMs and the destination executing
-   steps 4-7.
+      tsc_dst[i] = tsc_src[i] + (ΔT * freq[i] / 10^6)
+
+   c. Use host_tsc_dst and the scaling factors to calculate this vCPU's
+      raw scaled TSC at time Tdst without offsetting:
+
+      raw_dst[i] = ((host_tsc_dst * ratio_dst[i]) >> frac_bits_dst[i])
+
+   d. Calculate ofs_dst[i] = tsc_dst[i] - raw_dst[i] and set the resulting
+      offset using the KVM_VCPU_TSC_OFFSET attribute.
+
+8. If pvti_src was provided, invoke the KVM_SET_CLOCK_GUEST ioctl on the boot
+   vCPU to restore the KVM clock as a precise function of the guest TSC.
+
+9. If KVM_SET_CLOCK_GUEST was not available or failed (e.g. because the
+   master clock is not active), fall back to the KVM_SET_CLOCK ioctl,
+   providing the source nanoseconds from kvmclock (guest_src) and
+   CLOCK_REALTIME (time_src) in their respective fields. Ensure that the
+   KVM_CLOCK_REALTIME flag is set in the provided structure.
+
+   KVM will restore the VM's kvmclock, accounting for elapsed time since
+   the clock values were recorded. Note that this will cause problems in
+   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized between
+   the source and destination, and a reasonably short time passes between
+   the source pausing the VMs and the destination resuming them.
+   Due to the KVM_[SG]ET_CLOCK API using CLOCK_REALTIME instead of
+   CLOCK_TAI, leap seconds during the migration may also introduce errors.
+
+4.2 ATTRIBUTE: KVM_VCPU_TSC_SCALE
+---------------------------------
+
+:Parameters: struct kvm_vcpu_tsc_scale
+
+Returns:
+
+	 ======= ======================================
+	 -EFAULT Error writing the result to the
+		 provided address.
+	 -ENXIO  Attribute not supported (no TSC scaling)
+	 -EINVAL Invalid request to write the attribute
+	 ======= ======================================
 
-5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_dest) and
-   kvmclock nanoseconds (guest_dest).
+This read-only attribute reports the guest's TSC scaling factor, in the form
+of a fixed-point number represented by the following structure::
 
-6. Adjust the guest TSC offsets for every vCPU to account for (1) time
-   elapsed since recording state and (2) difference in TSCs between the
-   source and destination machine:
+  struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+  };
 
-   ofs_dst[i] = ofs_src[i] -
-     (guest_src - guest_dest) * freq +
-     (tsc_src - tsc_dest)
+The tsc_frac_bits field indicates the location of the fixed point, such that
+host TSC values are converted to guest TSC using the formula:
 
-   ("ofs[i] + tsc - guest * freq" is the guest TSC value corresponding to
-   a time of 0 in kvmclock.  The above formula ensures that it is the
-   same on the destination as it was on the source).
+  guest_tsc = ((host_tsc * tsc_ratio) >> tsc_frac_bits) + offset
 
-7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the
-   respective value derived in the previous step.
+Userspace can use this to precisely calculate the guest TSC from the host
+TSC at any given moment. This is needed for accurate migration of guests,
+as described in the documentation for the KVM_VCPU_TSC_OFFSET attribute.
diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst
index 662231e958a075..4548b61a7652a8 100644
--- a/Documentation/virt/kvm/locking.rst
+++ b/Documentation/virt/kvm/locking.rst
@@ -263,7 +263,7 @@ time it will be set using the Dirty tracking mechanism described above.
 
 :Type:		raw_spinlock_t
 :Arch:		x86
-:Protects:	- kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset}
+:Protects:	- kvm_arch::{cur_tsc_write,cur_tsc_nsec,cur_tsc_offset}
 		- tsc offset in vmcb
 :Comment:	'raw' because updating the tsc offsets must not be preempted.
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 9fadc98d3c4998..773f7c800f6aac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14663,8 +14663,8 @@ S:	Supported
 T:	git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
 F:	arch/um/include/asm/kvm_para.h
 F:	arch/x86/include/asm/kvm_para.h
-F:	arch/x86/include/asm/pvclock-abi.h
 F:	arch/x86/include/uapi/asm/kvm_para.h
+F:	arch/x86/include/uapi/asm/pvclock-abi.h
 F:	arch/x86/kernel/kvm.c
 F:	arch/x86/kernel/kvmclock.c
 F:	include/asm-generic/kvm_para.h
@@ -29780,8 +29780,8 @@ R:	Boris Ostrovsky <boris.ostrovsky@oracle.com>
 L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/x86/configs/xen.config
-F:	arch/x86/include/asm/pvclock-abi.h
 F:	arch/x86/include/asm/xen/
+F:	arch/x86/include/uapi/asm/pvclock-abi.h
 F:	arch/x86/platform/pvh/
 F:	arch/x86/xen/
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e2eef7057bd353..59260f08765402 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -887,6 +887,8 @@ struct kvm_vcpu_arch {
 	u64 this_tsc_nsec;
 	u64 this_tsc_write;
 	u64 this_tsc_generation;
+	u64 this_tsc_freq_generation;
+	bool user_set_tsc;
 	bool tsc_catchup;
 	bool tsc_always_catchup;
 	s8 virtual_tsc_shift;
@@ -1236,15 +1238,16 @@ struct kvm_arch {
 	 * preemption-disabled region, so it must be a raw spinlock.
 	 */
 	raw_spinlock_t tsc_write_lock;
-	u64 last_tsc_nsec;
-	u64 last_tsc_write;
-	u32 last_tsc_khz;
-	u64 last_tsc_offset;
-	u64 last_tsc_scaling_ratio;
+	u32 cur_tsc_khz;
+	u64 cur_tsc_scaling_ratio;
 	u64 cur_tsc_nsec;
 	u64 cur_tsc_write;
 	u64 cur_tsc_offset;
 	u64 cur_tsc_generation;
+	bool all_vcpus_matched_tsc;
+	bool all_vcpus_matched_freq;
+	int nr_vcpus_matched_freq;
+	u64 cur_tsc_freq_generation;
 	int nr_vcpus_matched_tsc;
 
 	u32 default_tsc_khz;
@@ -1269,7 +1272,6 @@ struct kvm_arch {
 #endif
 
 	bool backwards_tsc_observed;
-	bool boot_vcpu_runs_old_kvmclock;
 	u32 bsp_vcpu_id;
 
 	u64 disabled_quirks;
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 1585ec8040666e..f8274d8e471d63 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/stddef.h>
+#include <asm/pvclock-abi.h>
 
 #define KVM_PIO_PAGE_OFFSET 1
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2
@@ -963,6 +964,12 @@ struct kvm_hyperv_eventfd {
 /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
 #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
 #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */
+
+struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+};
 
 /* x86-specific KVM_EXIT_HYPERCALL flags. */
 #define KVM_EXIT_HYPERCALL_LONG_MODE	_BITULL(0)
diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/uapi/asm/pvclock-abi.h
similarity index 82%
rename from arch/x86/include/asm/pvclock-abi.h
rename to arch/x86/include/uapi/asm/pvclock-abi.h
index b9fece5fc96d6f..6d70cf64036293 100644
--- a/arch/x86/include/asm/pvclock-abi.h
+++ b/arch/x86/include/uapi/asm/pvclock-abi.h
@@ -1,6 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef _ASM_X86_PVCLOCK_ABI_H
 #define _ASM_X86_PVCLOCK_ABI_H
+
+#include <linux/types.h>
+
 #ifndef __ASSEMBLER__
 
 /*
@@ -24,20 +27,20 @@
  */
 
 struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
+	__u32   version;
+	__u32   pad0;
+	__u64   tsc_timestamp;
+	__u64   system_time;
+	__u32   tsc_to_system_mul;
+	__s8    tsc_shift;
+	__u8    flags;
+	__u8    pad[2];
 } __attribute__((__packed__)); /* 32 bytes */
 
 struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
+	__u32   version;
+	__u32   sec;
+	__u32   nsec;
 } __attribute__((__packed__));
 
 #define PVCLOCK_TSC_STABLE_BIT	(1 << 0)
diff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c
index e91650af44c207..94cd4d73689a77 100644
--- a/arch/x86/kvm/msrs.c
+++ b/arch/x86/kvm/msrs.c
@@ -1275,24 +1275,30 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_o
 static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time,
 				  bool old_msr, bool host_initiated)
 {
-	struct kvm_arch *ka = &vcpu->kvm->arch;
-
-	if (vcpu->vcpu_id == 0 && !host_initiated) {
-		if (ka->boot_vcpu_runs_old_kvmclock != old_msr)
-			kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
-
-		ka->boot_vcpu_runs_old_kvmclock = old_msr;
-	}
+	/*
+	 * Slide the master clock reference point forward, so that the
+	 * pvclock written below carries a recent tsc_timestamp. SUSE's
+	 * 2.6.16 kernel (the only known user of the legacy MSR with a
+	 * reason to care) re-requests the time by rewriting this MSR
+	 * whenever tsc_timestamp falls more than 1/5 jiffie behind the
+	 * TSC, and would livelock against a fixed reference point; each
+	 * rewrite now genuinely freshens it. A write with the enable
+	 * bit clear deactivates the pvclock; there is nothing to
+	 * freshen.
+	 */
+	if (old_msr && !host_initiated && (system_time & 1))
+		kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 
 	vcpu->arch.time = system_time;
-	kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 
 	/* we verify if the enable bit is set... */
-	if (system_time & 1)
+	if (system_time & 1) {
 		kvm_gpc_activate(&vcpu->arch.pv_time, system_time & ~1ULL,
 				 sizeof(struct pvclock_vcpu_time_info));
-	else
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+	} else {
 		kvm_gpc_deactivate(&vcpu->arch.pv_time);
+	}
 
 	return;
 }
@@ -1639,7 +1645,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		break;
 	case MSR_IA32_TSC:
 		if (msr_info->host_initiated) {
-			kvm_synchronize_tsc(vcpu, &data);
+			kvm_synchronize_tsc(vcpu, &data, true);
 		} else if (!vcpu->arch.guest_tsc_protected) {
 			u64 adj = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data) -
 				  vcpu->arch.l1_tsc_offset;
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 93de876c318ce5..704683532ef018 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -1003,25 +1003,25 @@ TRACE_EVENT(kvm_write_tsc_offset,
 	{VDSO_CLOCKMODE_TSC,  "tsc"}			\
 
 TRACE_EVENT(kvm_update_master_clock,
-	TP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched),
-	TP_ARGS(use_master_clock, host_clock, offset_matched),
+	TP_PROTO(bool use_master_clock, unsigned int host_clock, bool freq_matched),
+	TP_ARGS(use_master_clock, host_clock, freq_matched),
 
 	TP_STRUCT__entry(
 		__field(		bool,	use_master_clock	)
 		__field(	unsigned int,	host_clock		)
-		__field(		bool,	offset_matched		)
+		__field(		bool,	freq_matched		)
 	),
 
 	TP_fast_assign(
 		__entry->use_master_clock	= use_master_clock;
 		__entry->host_clock		= host_clock;
-		__entry->offset_matched		= offset_matched;
+		__entry->freq_matched		= freq_matched;
 	),
 
-	TP_printk("masterclock %d hostclock %s offsetmatched %u",
+	TP_printk("masterclock %d hostclock %s freqmatched %u",
 		  __entry->use_master_clock,
 		  __print_symbolic(__entry->host_clock, host_clocks),
-		  __entry->offset_matched)
+		  __entry->freq_matched)
 );
 
 TRACE_EVENT(kvm_track_tsc,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 32563a91fba99a..2136c1f6803207 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -210,6 +210,10 @@ module_param(pi_inject_timer, bint, 0644);
 static bool __read_mostly mitigate_smt_rsb;
 module_param(mitigate_smt_rsb, bool, 0444);
 
+#ifdef CONFIG_X86_64
+static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
+#endif
+
 #define KVM_SUPPORTED_XCR0     (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
 				| XFEATURE_MASK_YMM | XFEATURE_MASK_BNDREGS \
 				| XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \
@@ -885,60 +889,6 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)
 	       kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending();
 }
 
-#ifdef CONFIG_X86_64
-struct pvclock_clock {
-	int vclock_mode;
-	u64 cycle_last;
-	u64 mask;
-	u32 mult;
-	u32 shift;
-	u64 base_cycles;
-	u64 offset;
-};
-
-struct pvclock_gtod_data {
-	seqcount_t	seq;
-
-	struct pvclock_clock clock; /* extract of a clocksource struct */
-	struct pvclock_clock raw_clock; /* extract of a clocksource struct */
-
-	ktime_t		offs_boot;
-	u64		wall_time_sec;
-};
-
-static struct pvclock_gtod_data pvclock_gtod_data;
-
-static void update_pvclock_gtod(struct timekeeper *tk)
-{
-	struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
-
-	write_seqcount_begin(&vdata->seq);
-
-	/* copy pvclock gtod data */
-	vdata->clock.vclock_mode	= tk->tkr_mono.clock->vdso_clock_mode;
-	vdata->clock.cycle_last		= tk->tkr_mono.cycle_last;
-	vdata->clock.mask		= tk->tkr_mono.mask;
-	vdata->clock.mult		= tk->tkr_mono.mult;
-	vdata->clock.shift		= tk->tkr_mono.shift;
-	vdata->clock.base_cycles	= tk->tkr_mono.xtime_nsec;
-	vdata->clock.offset		= tk->tkr_mono.base;
-
-	vdata->raw_clock.vclock_mode	= tk->tkr_raw.clock->vdso_clock_mode;
-	vdata->raw_clock.cycle_last	= tk->tkr_raw.cycle_last;
-	vdata->raw_clock.mask		= tk->tkr_raw.mask;
-	vdata->raw_clock.mult		= tk->tkr_raw.mult;
-	vdata->raw_clock.shift		= tk->tkr_raw.shift;
-	vdata->raw_clock.base_cycles	= tk->tkr_raw.xtime_nsec;
-	vdata->raw_clock.offset		= tk->tkr_raw.base;
-
-	vdata->wall_time_sec            = tk->xtime_sec;
-
-	vdata->offs_boot		= tk->offs_boot;
-
-	write_seqcount_end(&vdata->seq);
-}
-#endif
-
 static s64 get_kvmclock_base_ns(void)
 {
 	/* Count up from boot time, but with the frequency of the raw clock.  */
@@ -1027,7 +977,7 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 	/* Guest TSC same frequency as host TSC? */
 	if (!scale) {
 		kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio);
-		return 0;
+		goto clear_catchup;
 	}
 
 	/* TSC scaling supported? */
@@ -1053,13 +1003,34 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 	}
 
 	kvm_vcpu_write_tsc_multiplier(vcpu, ratio);
+
+clear_catchup:
+	/*
+	 * A frequency which no longer needs catchup must also stop it: a
+	 * previous above-host-rate setting on scaling-less hardware set
+	 * the always-catchup flags, and nothing else ever clears them.
+	 * Only undo that pairing — tsc_catchup alone also serves the
+	 * unstable-host-TSC compensation in kvm_arch_vcpu_load().
+	 */
+	if (vcpu->arch.tsc_always_catchup) {
+		vcpu->arch.tsc_always_catchup = 0;
+		vcpu->arch.tsc_catchup = 0;
+	}
 	return 0;
 }
 
-static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,
+				   u64 host_tsc, s64 ns, bool user_initiated);
+
+static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)
 {
+	bool freq_changed = (vcpu->arch.virtual_tsc_khz != user_tsc_khz);
 	u32 thresh_lo, thresh_hi;
+	u32 tsc_mult;
+	s8 tsc_shift;
 	int use_scaling = 0;
+	u64 tsc, host_tsc;
+	s64 ns;
 
 	/* tsc_khz can be zero if TSC calibration fails */
 	if (user_tsc_khz == 0) {
@@ -1070,9 +1041,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
 
 	/* Compute a scale to convert nanoseconds in TSC cycles */
 	kvm_get_time_scale(user_tsc_khz * 1000LL, NSEC_PER_SEC,
-			   &vcpu->arch.virtual_tsc_shift,
-			   &vcpu->arch.virtual_tsc_mult);
-	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+			   &tsc_shift, &tsc_mult);
 
 	/*
 	 * Compute the variation in TSC rate which is acceptable
@@ -1087,7 +1056,67 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
 			 user_tsc_khz, thresh_lo, thresh_hi);
 		use_scaling = 1;
 	}
-	return set_tsc_khz(vcpu, user_tsc_khz, use_scaling);
+
+	/*
+	 * Sample the guest TSC before changing the ratio, so continuity
+	 * can be preserved across the change — as a {guest TSC, host
+	 * clock} tuple, not a bare value: the synchronization below
+	 * computes the new offset against the tuple's own reference
+	 * point, so the guest TSC keeps counting through this function
+	 * and any delay here (preemption included) costs nothing.
+	 */
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&ns, &host_tsc))
+#endif
+	{
+		host_tsc = rdtsc();
+		ns = get_kvmclock_base_ns();
+	}
+	tsc = kvm_read_l1_tsc(vcpu, host_tsc);
+
+	if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))
+		return -1;
+
+	/*
+	 * Commit the new frequency only once set_tsc_khz() can no longer
+	 * fail: a failed ioctl must leave no trace, or a retry with the
+	 * still-active frequency would wrongly look like a change.
+	 */
+	vcpu->arch.virtual_tsc_shift = tsc_shift;
+	vcpu->arch.virtual_tsc_mult = tsc_mult;
+	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+
+	/*
+	 * At vCPU creation (@init) the vCPU is not yet counted in
+	 * online_vcpus, so synchronizing here would corrupt the VM-wide
+	 * matching state (and leave it corrupted if creation subsequently
+	 * fails). The initial synchronization happens in
+	 * kvm_arch_vcpu_postcreate() instead. An unchanged frequency is
+	 * a no-op for synchronization: don't disturb the generation
+	 * tracking of a configured vCPU.
+	 */
+	if (init || !freq_changed)
+		return 0;
+
+	/*
+	 * Changing the frequency changes the vCPU's position on the
+	 * generation's cycle timeline, so re-synchronize. For a vCPU
+	 * which has run, preserve the guest TSC value read above across
+	 * the change; likewise if userspace has written a TSC on this
+	 * vCPU — a zero write would discard it. Otherwise the vCPU holds
+	 * only its creation-time synchronization, so synchronize as for
+	 * a zero write. When the generation is already at the new
+	 * frequency this places the vCPU on its timeline rather than
+	 * opening a gratuitous new generation and orphaning the matched
+	 * state of its siblings; the first vCPU to adopt a new frequency
+	 * necessarily opens a new generation, starting at zero — mixed
+	 * frequencies within a VM forfeit the master clock anyway.
+	 */
+	if (vcpu->arch.last_vmentry_cpu != -1 || vcpu->arch.user_set_tsc)
+		kvm_synchronize_tsc_at(vcpu, &tsc, host_tsc, ns, false);
+	else
+		kvm_synchronize_tsc_at(vcpu, NULL, host_tsc, ns, false);
+	return 0;
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
@@ -1104,42 +1133,97 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 }
 
 #ifdef CONFIG_X86_64
+static int kvm_host_vclock_mode;
+
 static inline bool gtod_is_based_on_tsc(int mode)
 {
 	return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;
 }
-#endif
 
-static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generation)
+static bool kvm_use_master_clock(struct kvm *kvm)
+{
+	struct kvm_arch *ka = &kvm->arch;
+
+	return ka->all_vcpus_matched_freq &&
+		!ka->backwards_tsc_observed;
+}
+
+static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclock)
 {
-#ifdef CONFIG_X86_64
 	struct kvm_arch *ka = &vcpu->kvm->arch;
-	struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
+	bool prev_matched_tsc = ka->all_vcpus_matched_tsc;
+	bool prev_matched_freq = ka->all_vcpus_matched_freq;
+
+	/*
+	 * Track whether all vCPUs have matching TSC offsets (for
+	 * PVCLOCK_TSC_STABLE_BIT) and matching frequencies (for
+	 * master clock eligibility).
+	 */
+
+	/*
+	 * A new vCPU might already have incremented ->online_vcpus
+	 * and cause a temporary false negative here. But will then
+	 * call kvm_synchronize_tsc() from kvm_arch_vcpu_postcreate()
+	 * and finish the job.
+	 */
+	int online = atomic_read(&vcpu->kvm->online_vcpus);
+	/*
+	 * WRITE_ONCE() pairs with the READ_ONCE() in kvm_guest_time_update(),
+	 * which samples the flag locklessly (outside both tsc_write_lock and
+	 * its pvclock seqcount read section); the race is benign (a stale
+	 * value merely delays the PVCLOCK_TSC_STABLE_BIT broadcast to the
+	 * masterclock update which is requested below).
+	 */
+	WRITE_ONCE(ka->all_vcpus_matched_tsc,
+		   ka->nr_vcpus_matched_tsc >= online);
+
+	update_mclock |= (prev_matched_tsc != ka->all_vcpus_matched_tsc);
+
+	/*
+	 * all_vcpus_matched_freq starts true and is cleared when
+	 * __kvm_synchronize_tsc() detects a frequency mismatch.
+	 * Re-enable when all vCPUs have synced with matching frequency.
+	 * If all offsets also match, that implies frequencies match too.
+	 */
+	if (ka->all_vcpus_matched_tsc ||
+	    ka->nr_vcpus_matched_freq >= online)
+		ka->all_vcpus_matched_freq = true;
+
+	/*
+	 * A frequency-match transition needs a masterclock update too:
+	 * when the last vCPU reaches the new frequency, the masterclock
+	 * scaling factors still describe the old one, and no toggle of
+	 * use_master_clock occurs to trigger the refresh.
+	 */
+	update_mclock |= (prev_matched_freq != ka->all_vcpus_matched_freq);
 
 	/*
 	 * To use the masterclock, the host clocksource must be based on TSC
-	 * and all vCPUs must have matching TSCs.  Note, the count for matching
-	 * vCPUs doesn't include the reference vCPU, hence "+1".
+	 * and all vCPUs must have matching TSC *frequency*. Different offsets
+	 * are fine — each vCPU's pvclock has its own tsc_timestamp that
+	 * accounts for its offset.
 	 */
-	bool use_master_clock = (ka->nr_vcpus_matched_tsc + 1 ==
-				 atomic_read(&vcpu->kvm->online_vcpus)) &&
-				gtod_is_based_on_tsc(gtod->clock.vclock_mode);
+	int host_vclock_mode = READ_ONCE(kvm_host_vclock_mode);
+	bool use_master_clock = kvm_use_master_clock(vcpu->kvm) &&
+				gtod_is_based_on_tsc(host_vclock_mode);
 
 	/*
-	 * Request a masterclock update if the masterclock needs to be toggled
-	 * on/off, or when starting a new generation and the masterclock is
-	 * enabled (compute_guest_tsc() requires the masterclock snapshot to be
-	 * taken _after_ the new generation is created).
+	 * Request a masterclock update if needed: toggling master clock,
+	 * new generation requiring a fresh snapshot, or a change in
+	 * all_vcpus_matched_tsc (to broadcast PVCLOCK_TSC_STABLE_BIT).
 	 */
-	if ((ka->use_master_clock && new_generation) ||
+	if ((ka->use_master_clock && update_mclock) ||
 	    (ka->use_master_clock != use_master_clock))
 		kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 
 	trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc,
 			    atomic_read(&vcpu->kvm->online_vcpus),
-		            ka->use_master_clock, gtod->clock.vclock_mode);
-#endif
+			    ka->use_master_clock, host_vclock_mode);
 }
+#else
+static inline void kvm_track_tsc_matching(struct kvm_vcpu *vcpu,
+					  bool update_mclock) {}
+#endif
 
 /*
  * Multiply tsc by a fixed point number represented by ratio.
@@ -1305,7 +1389,7 @@ static inline bool kvm_check_tsc_unstable(void)
 	 * TSC is marked unstable when we're running on Hyper-V,
 	 * 'TSC page' clocksource is good.
 	 */
-	if (pvclock_gtod_data.clock.vclock_mode == VDSO_CLOCKMODE_HVCLOCK)
+	if (READ_ONCE(kvm_host_vclock_mode) == VDSO_CLOCKMODE_HVCLOCK)
 		return false;
 #endif
 	return check_tsc_unstable();
@@ -1326,21 +1410,55 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
 	if (vcpu->arch.guest_tsc_protected)
 		return;
 
-	if (user_set_tsc)
+	if (user_set_tsc) {
 		vcpu->kvm->arch.user_set_tsc = true;
+		vcpu->arch.user_set_tsc = true;
+	}
 
 	/*
-	 * We also track th most recent recorded KHZ, write and time to
-	 * allow the matching interval to be extended at each write.
+	 * Track the TSC frequency, scaling ratio, and offset for the current
+	 * generation. These are used to detect matching TSC writes and to
+	 * compute the guest TSC from the host clock.
+	 *
+	 * If the frequency changed, master clock mode can no longer be used
+	 * since the kvmclock scaling factors differ between vCPUs.
 	 */
-	kvm->arch.last_tsc_nsec = ns;
-	kvm->arch.last_tsc_write = tsc;
-	kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz;
-	kvm->arch.last_tsc_offset = offset;
-	kvm->arch.last_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
+	if (vcpu->arch.virtual_tsc_khz != kvm->arch.cur_tsc_khz) {
+		kvm->arch.cur_tsc_freq_generation++;
+		kvm->arch.all_vcpus_matched_freq = false;
+		kvm->arch.nr_vcpus_matched_freq = 0;
+	}
+
+	/* Count each vCPU once per freq generation */
+	if (vcpu->arch.this_tsc_freq_generation != kvm->arch.cur_tsc_freq_generation) {
+		vcpu->arch.this_tsc_freq_generation = kvm->arch.cur_tsc_freq_generation;
+		kvm->arch.nr_vcpus_matched_freq++;
+	}
+
+	kvm->arch.cur_tsc_khz = vcpu->arch.virtual_tsc_khz;
+	kvm->arch.cur_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
 
 	vcpu->arch.last_guest_tsc = tsc;
 
+	/*
+	 * The offset written below is absolute, superseding any backwards-TSC
+	 * compensation still pending from kvm_arch_enable_virtualization_cpu()
+	 * (which has already been folded into cur_tsc_offset, and thus into
+	 * a matched @offset); applying it again at the next vcpu_load would
+	 * double it.
+	 */
+	vcpu->arch.tsc_offset_adjustment = 0;
+
+	/*
+	 * If the offset changes, the guest-visible pvclock must be
+	 * rewritten before the vCPU runs again: its tsc_timestamp was
+	 * computed with the old offset, and the masterclock (which now
+	 * survives offset changes) will not request the refresh for a
+	 * matched write.
+	 */
+	if (offset != vcpu->arch.l1_tsc_offset)
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+
 	kvm_vcpu_write_tsc_offset(vcpu, offset);
 
 	if (!matched) {
@@ -1350,39 +1468,47 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
 		 * nanosecond time, offset, and write, so if TSCs are in
 		 * sync, we can match exact offset, and if not, we can match
 		 * exact software computation in compute_guest_tsc()
-		 *
-		 * These values are tracked in kvm->arch.cur_xxx variables.
 		 */
 		kvm->arch.cur_tsc_generation++;
+		WRITE_ONCE(kvm->arch.all_vcpus_matched_tsc, false);
+		kvm->arch.nr_vcpus_matched_tsc = 0;
 		kvm->arch.cur_tsc_nsec = ns;
 		kvm->arch.cur_tsc_write = tsc;
 		kvm->arch.cur_tsc_offset = offset;
-		kvm->arch.nr_vcpus_matched_tsc = 0;
-	} else if (vcpu->arch.this_tsc_generation != kvm->arch.cur_tsc_generation) {
+	}
+
+	if (vcpu->arch.this_tsc_generation != kvm->arch.cur_tsc_generation) {
+		vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
 		kvm->arch.nr_vcpus_matched_tsc++;
 	}
 
-	/* Keep track of which generation this VCPU has synchronized to */
-	vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
 	vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec;
 	vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write;
 
 	kvm_track_tsc_matching(vcpu, !matched);
 }
 
-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
+/*
+ * Synchronize the vCPU's TSC against an explicit {host_tsc, ns} reference
+ * point: @value (when non-NULL) is the guest TSC *at* @host_tsc, not at
+ * some unspecified "now". The offset is computed against that reference,
+ * so a sampled value stays valid however much time passes between the
+ * sampling and this call.
+ */
+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,
+				   u64 host_tsc, s64 ns, bool user_initiated)
 {
-	u64 data = user_value ? *user_value : 0;
+	u64 data = value ? *value : 0;
 	struct kvm *kvm = vcpu->kvm;
-	u64 offset, ns, elapsed;
+	u64 offset, elapsed;
 	unsigned long flags;
 	bool matched = false;
 	bool synchronizing = false;
 
 	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-	offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);
-	ns = get_kvmclock_base_ns();
-	elapsed = ns - kvm->arch.last_tsc_nsec;
+
+	offset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);
+	elapsed = ns - kvm->arch.cur_tsc_nsec;
 
 	if (vcpu->arch.virtual_tsc_khz) {
 		if (data == 0) {
@@ -1392,9 +1518,10 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 			 */
 			synchronizing = true;
 		} else if (kvm->arch.user_set_tsc) {
-			u64 tsc_exp = kvm->arch.last_tsc_write +
+			u64 tsc_exp = kvm->arch.cur_tsc_write +
 						nsec_to_cycles(vcpu, elapsed);
 			u64 tsc_hz = vcpu->arch.virtual_tsc_khz * 1000LL;
+			u64 window;
 			/*
 			 * Here lies UAPI baggage: when a user-initiated TSC write has
 			 * a small delta (1 second) of virtual cycle time against the
@@ -1409,9 +1536,18 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 			 * to this 'correction' to make it sync up with values that only
 			 * come from the kernel's default vCPU creation. Make the 1-second
 			 * slop hack only trigger if the user_set_tsc flag is already set.
+			 *
+			 * A kernel-internal write (a frequency change preserving the
+			 * guest TSC) carries an exact value sampled with its own
+			 * reference point, not a racy userspace one; a vCPU on the
+			 * generation's line still matches it to within arithmetic
+			 * rounding, but one which genuinely diverged (e.g. by a guest
+			 * TSC_ADJUST write) must not be snapped back by up to a
+			 * second. Use a 1ms window for those.
 			 */
-			synchronizing = data < tsc_exp + tsc_hz &&
-					data + tsc_hz > tsc_exp;
+			window = user_initiated ? tsc_hz : tsc_hz / 1000;
+			synchronizing = data < tsc_exp + window &&
+					data + window > tsc_exp;
 		}
 	}
 
@@ -1423,21 +1559,52 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 	 * it's better to try to match offsets from the beginning.
          */
 	if (synchronizing &&
-	    vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
-		if (!kvm_check_tsc_unstable()) {
+	    vcpu->arch.virtual_tsc_khz == kvm->arch.cur_tsc_khz) {
+		/*
+		 * If synchronizing, extrapolate the generation's value to
+		 * "now": the matching window slides forward with wall time,
+		 * anchored on the generation's origin alone (a matched
+		 * write no longer updates any stored reference point).
+		 */
+		u64 delta = nsec_to_cycles(vcpu, elapsed);
+
+		data = kvm->arch.cur_tsc_write + delta;
+
+		/*
+		 * The generation's offset can be reused directly: it is in
+		 * this vCPU's scaling domain, because every generation is
+		 * opened by a vCPU (the initial VM-creation generation is
+		 * not matchable) and set_tsc_khz() derives the scaling
+		 * ratio deterministically from the kHz value, so two vCPUs
+		 * at the same frequency carry the same ratio.
+		 */
+		if (!kvm_check_tsc_unstable())
 			offset = kvm->arch.cur_tsc_offset;
-		} else {
-			u64 delta = nsec_to_cycles(vcpu, elapsed);
-			data += delta;
-			offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);
-		}
+		else
+			offset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);
 		matched = true;
 	}
 
-	__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, !!user_value);
+	__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, user_initiated);
 	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 }
 
+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)
+{
+	u64 host_tsc;
+	s64 ns;
+
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&ns, &host_tsc))
+#endif
+	{
+		host_tsc = rdtsc();
+		ns = get_kvmclock_base_ns();
+	}
+
+	kvm_synchronize_tsc_at(vcpu, value, host_tsc, ns, user_initiated);
+}
+
 #ifdef CONFIG_X86_64
 
 static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap,
@@ -1564,12 +1731,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 {
 #ifdef CONFIG_X86_64
 	struct kvm_arch *ka = &kvm->arch;
-	int vclock_mode;
-	bool host_tsc_clocksource, vcpus_matched;
+	bool host_tsc_clocksource;
 
 	lockdep_assert_held(&kvm->arch.tsc_write_lock);
-	vcpus_matched = (ka->nr_vcpus_matched_tsc + 1 ==
-			atomic_read(&kvm->online_vcpus));
 
 	/*
 	 * If the host uses TSC clock, then passthrough TSC as stable
@@ -1579,9 +1743,8 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 					&ka->master_kernel_ns,
 					&ka->master_cycle_now);
 
-	ka->use_master_clock = host_tsc_clocksource && vcpus_matched
-				&& !ka->backwards_tsc_observed
-				&& !ka->boot_vcpu_runs_old_kvmclock;
+	ka->use_master_clock = host_tsc_clocksource &&
+				kvm_use_master_clock(kvm);
 
 	if (ka->use_master_clock) {
 		u64 tsc_hz;
@@ -1594,7 +1757,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 		 * get_kvmclock() to compute kvmclock from the host TSC
 		 * without needing a vCPU reference.
 		 */
-		ka->master_tsc_scaling_ratio = ka->last_tsc_scaling_ratio;
+		ka->master_tsc_scaling_ratio = ka->cur_tsc_scaling_ratio;
 		tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;
 		if (tsc_hz && kvm_caps.has_tsc_control)
 			tsc_hz = kvm_scale_tsc(tsc_hz,
@@ -1607,9 +1770,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 			ka->use_master_clock = false;
 	}
 
-	vclock_mode = pvclock_gtod_data.clock.vclock_mode;
-	trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode,
-					vcpus_matched);
+	trace_kvm_update_master_clock(ka->use_master_clock,
+				      READ_ONCE(kvm_host_vclock_mode),
+				      ka->all_vcpus_matched_freq);
 #endif
 }
 
@@ -1618,10 +1781,51 @@ static void kvm_make_mclock_inprogress_request(struct kvm *kvm)
 	kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
 }
 
-static void __kvm_start_pvclock_update(struct kvm *kvm)
+static void kvm_clear_mclock_inprogress_request(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	unsigned long i;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);
+}
+
+static bool __kvm_start_pvclock_update(struct kvm *kvm, struct kvm_vcpu *requesting_vcpu)
 {
+	struct kvm_vcpu *vcpu;
+	unsigned long i;
+
 	raw_spin_lock_irq(&kvm->arch.tsc_write_lock);
+
+	/*
+	 * If another vCPU already did the update while we were waiting
+	 * for the lock, our request will have been cleared. Bail out,
+	 * clearing the KVM_REQ_MCLOCK_INPROGRESS kicks made on entry to
+	 * kvm_update_masterclock() so vCPUs can enter the guest again.
+	 *
+	 * Clearing them VM-wide can also clear kicks just made by yet
+	 * another updater still waiting for tsc_write_lock, letting
+	 * vCPUs run while that update is in flight. That is not new:
+	 * kvm_end_pvclock_update() has always cleared the request on
+	 * every vCPU regardless of which updater made it. The window is
+	 * harmless to readers (the pvclock seqcount covers the master
+	 * state); a vCPU which slips in runs on the old snapshot until
+	 * its KVM_REQ_CLOCK_UPDATE is serviced, exactly as if it had
+	 * entered just before the update began.
+	 */
+	if (requesting_vcpu &&
+	    !kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, requesting_vcpu)) {
+		kvm_clear_mclock_inprogress_request(kvm);
+		raw_spin_unlock_irq(&kvm->arch.tsc_write_lock);
+		return false;
+	}
+
+	/* The update is VM-wide; prevent other vCPUs from redoing it. */
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_clear_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
+
 	write_seqcount_begin(&kvm->arch.pvclock_sc);
+	return true;
 }
 
 static void kvm_start_pvclock_update(struct kvm *kvm)
@@ -1629,7 +1833,7 @@ static void kvm_start_pvclock_update(struct kvm *kvm)
 	kvm_make_mclock_inprogress_request(kvm);
 
 	/* no guest entries from this point */
-	__kvm_start_pvclock_update(kvm);
+	__kvm_start_pvclock_update(kvm, NULL);
 }
 
 static void kvm_end_pvclock_update(struct kvm *kvm)
@@ -1638,22 +1842,35 @@ static void kvm_end_pvclock_update(struct kvm *kvm)
 	struct kvm_vcpu *vcpu;
 	unsigned long i;
 
-	write_seqcount_end(&ka->pvclock_sc);
-	raw_spin_unlock_irq(&ka->tsc_write_lock);
 	kvm_for_each_vcpu(i, vcpu, kvm)
 		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
 	/* guest entries allowed */
-	kvm_for_each_vcpu(i, vcpu, kvm)
-		kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);
+	kvm_clear_mclock_inprogress_request(kvm);
+
+	write_seqcount_end(&ka->pvclock_sc);
+	raw_spin_unlock_irq(&ka->tsc_write_lock);
 }
 
-static void kvm_update_masterclock(struct kvm *kvm)
+static void kvm_update_masterclock(struct kvm *kvm, struct kvm_vcpu *vcpu)
 {
+	/*
+	 * The Hyper-V TSC page request is made before the dedupe check
+	 * in __kvm_start_pvclock_update() because it takes a mutex and
+	 * so cannot sit inside the tsc_write_lock critical section where
+	 * the winning updater is known. A losing vCPU may therefore mark
+	 * the page HOST_CHANGED after the winner has already rewritten
+	 * it; the next clock update then rewrites the page again with
+	 * the same contents, which the TSC-page sequence protocol makes
+	 * safe against concurrently running guests.
+	 */
 	kvm_hv_request_tsc_page_update(kvm);
-	kvm_start_pvclock_update(kvm);
-	pvclock_update_vm_gtod_copy(kvm);
-	kvm_end_pvclock_update(kvm);
+	kvm_make_mclock_inprogress_request(kvm);
+
+	if (__kvm_start_pvclock_update(kvm, vcpu)) {
+		pvclock_update_vm_gtod_copy(kvm);
+		kvm_end_pvclock_update(kvm);
+	}
 }
 
 /*
@@ -1680,6 +1897,7 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 	struct kvm_arch *ka = &kvm->arch;
 	struct pvclock_vcpu_time_info hv_clock;
 	struct timespec64 ts;
+	u64 clock;
 
 	if (!ka->use_master_clock)
 		return false;
@@ -1687,10 +1905,6 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 	if (!kvm_get_walltime_and_clockread(&ts, &data->host_tsc))
 		return false;
 
-	data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;
-	data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |
-		       KVM_CLOCK_TSC_STABLE;
-
 	hv_clock.tsc_timestamp = ka->master_cycle_now;
 	hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
 
@@ -1705,13 +1919,34 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 		u64 tsc_delta = data->host_tsc - ka->master_cycle_now;
 
 		tsc_delta = kvm_scale_tsc(tsc_delta, ka->master_tsc_scaling_ratio);
-		data->clock = hv_clock.system_time +
-			      pvclock_scale_delta(tsc_delta,
-						  hv_clock.tsc_to_system_mul,
-						  hv_clock.tsc_shift);
+		clock = hv_clock.system_time +
+			pvclock_scale_delta(tsc_delta,
+					    hv_clock.tsc_to_system_mul,
+					    hv_clock.tsc_shift);
 	} else {
-		data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc);
+		clock = __pvclock_read_cycles(&hv_clock, data->host_tsc);
 	}
+
+	/*
+	 * Sanity-check the snapshot: if the elapsed time it computes from
+	 * the host TSC disagrees with the raw clock by more than a second,
+	 * the TSC was reset (suspend/resume — possibly re-inited by
+	 * firmware to an arbitrary value, including an underflowing one
+	 * below master_cycle_now) while nothing refreshed the snapshot.
+	 * That can happen while the VM has no vCPUs, since both the
+	 * resume compensation and the clocksource notifier work through
+	 * vCPUs. Use the fallback clock rather than returning a
+	 * discontinuity flagged KVM_CLOCK_TSC_STABLE.
+	 */
+	if (unlikely(abs((s64)(clock - hv_clock.system_time) -
+			 (get_kvmclock_base_ns() - ka->master_kernel_ns)) >
+		     NSEC_PER_SEC))
+		return false;
+
+	data->clock = clock;
+	data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;
+	data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |
+		       KVM_CLOCK_TSC_STABLE;
 	return true;
 #else
 	return false;
@@ -1897,7 +2132,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v)
 
 	/* If the host uses TSC clocksource, then it is stable */
 	hv_clock.flags = 0;
-	if (use_master_clock)
+	if (use_master_clock && READ_ONCE(ka->all_vcpus_matched_tsc))
 		hv_clock.flags |= PVCLOCK_TSC_STABLE_BIT;
 
 	if (vcpu->pv_time.active) {
@@ -2294,6 +2529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_MEMORY_FAULT_INFO:
 	case KVM_CAP_X86_GUEST_MODE:
 	case KVM_CAP_ONE_REG:
+#ifdef CONFIG_X86_64
+	case KVM_CAP_CLOCK_GUEST:
+#endif
 		r = 1;
 		break;
 	case KVM_CAP_PRE_FAULT_MEMORY:
@@ -2608,11 +2846,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		 * On a host with synchronized TSC, there is no need to update
 		 * kvmclock on vcpu->cpu migration
 		 */
-		if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1) {
+		if (!vcpu->kvm->arch.use_master_clock) {
 			if (__ratelimit(&vcpu->kvm->arch.kvmclock_update_rs))
 				kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 			else
 				kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+		} else if (vcpu->cpu == -1) {
+			kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 		}
 
 		if (vcpu->cpu != cpu)
@@ -3276,6 +3516,9 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu,
 	case KVM_VCPU_TSC_OFFSET:
 		r = 0;
 		break;
+	case KVM_VCPU_TSC_SCALE:
+		r = kvm_caps.has_tsc_control ? 0 : -ENXIO;
+		break;
 	default:
 		r = -ENXIO;
 	}
@@ -3296,6 +3539,21 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
 			break;
 		r = 0;
 		break;
+	case KVM_VCPU_TSC_SCALE: {
+		struct kvm_vcpu_tsc_scale scale;
+
+		r = -ENXIO;
+		if (!kvm_caps.has_tsc_control)
+			break;
+
+		scale.tsc_ratio = vcpu->arch.l1_tsc_scaling_ratio;
+		scale.tsc_frac_bits = kvm_caps.tsc_scaling_ratio_frac_bits;
+		r = -EFAULT;
+		if (copy_to_user(uaddr, &scale, sizeof(scale)))
+			break;
+		r = 0;
+		break;
+	}
 	default:
 		r = -ENXIO;
 	}
@@ -3323,8 +3581,8 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
 		raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
 
 		matched = (vcpu->arch.virtual_tsc_khz &&
-			   kvm->arch.last_tsc_khz == vcpu->arch.virtual_tsc_khz &&
-			   kvm->arch.last_tsc_offset == offset);
+			   kvm->arch.cur_tsc_khz == vcpu->arch.virtual_tsc_khz &&
+			   kvm->arch.cur_tsc_offset == offset);
 
 		tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset;
 		ns = get_kvmclock_base_ns();
@@ -3335,6 +3593,9 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
 		r = 0;
 		break;
 	}
+	case KVM_VCPU_TSC_SCALE:
+		r = kvm_caps.has_tsc_control ? -EINVAL : -ENXIO;
+		break;
 	default:
 		r = -ENXIO;
 	}
@@ -3424,6 +3685,197 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 	}
 }
 
+#ifdef CONFIG_X86_64
+static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)
+{
+	struct pvclock_vcpu_time_info hv_clock = {};
+	struct kvm_arch *ka = &v->kvm->arch;
+	bool use_master_clock;
+	unsigned int seq;
+
+	/*
+	 * Construct the pvclock purely from the master clock state. The
+	 * master mul/shift are computed for the guest TSC frequency, which
+	 * in master clock mode is the frequency of every vCPU; only the
+	 * tsc_timestamp is per-vCPU, translating the master snapshot into
+	 * this vCPU's TSC domain via its scaling ratio and offset.
+	 *
+	 * Note, this deliberately does NOT invoke kvm_guest_time_update(),
+	 * which would write the guest's pvclock pages: dirtying guest
+	 * memory after the final KVM_RUN would break post-copy migration
+	 * flows. The pvclock returned here describes the same clock as the
+	 * guest-visible copy (the same linear function of the guest TSC),
+	 * anchored at the current master clock snapshot.
+	 *
+	 * Translating the snapshot through the vCPU's *current* scaling
+	 * ratio and offset is correct even if they changed after the
+	 * snapshot was taken: the snapshot anchors a host TSC value, not
+	 * a guest one. A frequency change whose masterclock update is
+	 * still pending does leave stale mul/shift here, but that is the
+	 * paused-VM migration path reading a frequency userspace itself
+	 * has just changed — and the result fails safe, as the same-vCPU
+	 * KVM_SET_CLOCK_GUEST on the destination rejects a mul/shift
+	 * inconsistent with the vCPU's frequency with -ERANGE.
+	 */
+	do {
+		seq = read_seqcount_begin(&ka->pvclock_sc);
+
+		use_master_clock = ka->use_master_clock;
+		if (!use_master_clock)
+			continue;
+
+		hv_clock.tsc_timestamp = kvm_read_l1_tsc(v, ka->master_cycle_now);
+		hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
+		hv_clock.tsc_shift = ka->master_tsc_shift;
+		hv_clock.tsc_to_system_mul = ka->master_tsc_mul;
+		hv_clock.flags = READ_ONCE(ka->all_vcpus_matched_tsc) ?
+				 PVCLOCK_TSC_STABLE_BIT : 0;
+	} while (read_seqcount_retry(&ka->pvclock_sc, seq));
+
+	if (!use_master_clock)
+		return -ENODATA;
+
+	if (copy_to_user(argp, &hv_clock, sizeof(hv_clock)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Reverse the calculation in the hv_clock definition.
+ *
+ * time_ns = ( (cycles << shift) * mul ) >> 32;
+ * (although shift can be negative, so that's bad C)
+ *
+ * So for a single second,
+ * NSEC_PER_SEC = ( ( FREQ_HZ << shift) * mul ) >> 32
+ * NSEC_PER_SEC << 32 = ( FREQ_HZ << shift ) * mul
+ * ( NSEC_PER_SEC << 32 ) / mul = FREQ_HZ << shift
+ * ( NSEC_PER_SEC << 32 ) / mul ) >> shift = FREQ_HZ
+ */
+static u64 hvclock_to_hz(u32 mul, s8 shift)
+{
+	u64 tm = NSEC_PER_SEC << 32;
+
+	/* Maximise precision. Shift left until the top bit is set */
+	tm <<= 2;
+	shift += 2;
+
+	/* While 'mul' is even, increase the shift *after* the division */
+	while (!(mul & 1)) {
+		shift++;
+		mul >>= 1;
+	}
+
+	tm /= mul;
+
+	if (shift >= 64)
+		return 0;
+	if (shift > 0)
+		return tm >> shift;
+
+	/*
+	 * A left shift can overflow for absurd user-supplied mul/shift
+	 * combinations; saturate (to a value which cannot itself overflow
+	 * the rounding in the caller's kHz conversion) so the frequency
+	 * check certainly rejects them.
+	 */
+	if (shift <= -64 || tm > (U64_MAX >> 1) >> -shift)
+		return U64_MAX >> 1;
+	return tm << -shift;
+}
+
+static int kvm_vcpu_ioctl_set_clock_guest(struct kvm_vcpu *v, void __user *argp)
+{
+	struct pvclock_vcpu_time_info user_hv_clock;
+	struct kvm *kvm = v->kvm;
+	struct kvm_arch *ka = &kvm->arch;
+	u64 curr_tsc_hz, user_tsc_hz;
+	u64 curr_tsc_khz, user_tsc_khz;
+	u64 user_clk_ns;
+	u64 guest_tsc;
+	int rc = 0;
+
+	if (copy_from_user(&user_hv_clock, argp, sizeof(user_hv_clock)))
+		return -EFAULT;
+
+	if (user_hv_clock.pad0 || user_hv_clock.pad[0] || user_hv_clock.pad[1])
+		return -EINVAL;
+
+	if (!user_hv_clock.tsc_to_system_mul)
+		return -EINVAL;
+
+	if (user_hv_clock.tsc_shift < -31 || user_hv_clock.tsc_shift > 31)
+		return -EINVAL;
+
+	user_tsc_hz = hvclock_to_hz(user_hv_clock.tsc_to_system_mul,
+				    user_hv_clock.tsc_shift);
+
+	kvm_hv_request_tsc_page_update(kvm);
+
+	/*
+	 * kvm_start_pvclock_update() takes tsc_write_lock and opens
+	 * the pvclock seqcount; kvm_end_pvclock_update() closes both.
+	 * All clock state modifications between them are atomic with
+	 * respect to readers in kvm_guest_time_update().
+	 */
+	kvm_start_pvclock_update(kvm);
+	pvclock_update_vm_gtod_copy(kvm);
+
+	if (!ka->use_master_clock) {
+		rc = -ENODATA;
+		goto out;
+	}
+
+	/*
+	 * Nonzero, or pvclock_update_vm_gtod_copy() — which read it on
+	 * this CPU, with interrupts still disabled — would have cleared
+	 * use_master_clock above.
+	 */
+	curr_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;
+
+	if (kvm_caps.has_tsc_control)
+		curr_tsc_hz = kvm_scale_tsc(curr_tsc_hz,
+					    v->arch.l1_tsc_scaling_ratio);
+
+	/*
+	 * The mul/shift in the provided pvclock structure encode the guest
+	 * TSC frequency at which it was generated. Sanity-check that it is
+	 * consistent with this vCPU's effective TSC frequency, allowing a
+	 * discrepancy of 1 kHz either way since independently calibrated
+	 * hosts will not measure precisely the same value even for the
+	 * same nominal frequency. Compare in kHz: the reconstruction of
+	 * each side's frequency in Hz carries a few Hz of rounding, which
+	 * must not push two hosts calibrated exactly 1 kHz apart over the
+	 * line.
+	 */
+	user_tsc_khz = DIV_ROUND_CLOSEST_ULL(user_tsc_hz, HZ_PER_KHZ);
+	curr_tsc_khz = DIV_ROUND_CLOSEST_ULL(curr_tsc_hz, HZ_PER_KHZ);
+	if (user_tsc_khz + 1 < curr_tsc_khz ||
+	    user_tsc_khz > curr_tsc_khz + 1) {
+		rc = -ERANGE;
+		goto out;
+	}
+
+	/*
+	 * Calculate the guest TSC at the new reference point, and the
+	 * corresponding KVM clock value according to user_hv_clock.
+	 * Adjust kvmclock_offset so both definitions agree.
+	 */
+	guest_tsc = kvm_read_l1_tsc(v, ka->master_cycle_now);
+	if ((s64)(guest_tsc - user_hv_clock.tsc_timestamp) < 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+	user_clk_ns = __pvclock_read_cycles(&user_hv_clock, guest_tsc);
+	ka->kvmclock_offset = user_clk_ns - ka->master_kernel_ns;
+
+out:
+	kvm_end_pvclock_update(kvm);
+	return rc;
+}
+#endif
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -3734,7 +4186,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (user_tsc_khz == 0)
 			user_tsc_khz = tsc_khz;
 
-		if (!kvm_set_tsc_khz(vcpu, user_tsc_khz))
+		if (!kvm_set_tsc_khz(vcpu, user_tsc_khz, false))
 			r = 0;
 
 		goto out;
@@ -3817,6 +4269,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
 	}
+#ifdef CONFIG_X86_64
+	case KVM_SET_CLOCK_GUEST:
+		r = kvm_vcpu_ioctl_set_clock_guest(vcpu, argp);
+		break;
+	case KVM_GET_CLOCK_GUEST:
+		r = kvm_vcpu_ioctl_get_clock_guest(vcpu, argp);
+		break;
+#endif
 #ifdef CONFIG_KVM_HYPERV
 	case KVM_GET_SUPPORTED_HV_CPUID:
 		r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
@@ -4382,19 +4842,45 @@ static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp)
 	 * 'system_time' when 'data.clock' is very small.
 	 */
 	if (data.flags & KVM_CLOCK_REALTIME) {
-		u64 now_real_ns = ktime_get_real_ns();
+		struct system_time_snapshot snap = {};
+		u64 now_real_ns;
+
+		/*
+		 * Snapshot CLOCK_REALTIME and CLOCK_MONOTONIC_RAW at the
+		 * same instant, so that the elapsed time applied to
+		 * data.clock and the reference point the result is anchored
+		 * to are coherent.
+		 */
+		ktime_get_snapshot_id(CLOCK_REALTIME, &snap);
+		now_real_ns = ktime_to_ns(snap.systime);
+		now_raw_ns = ktime_to_ns(ktime_mono_to_any(snap.monoraw,
+							   TK_OFFS_BOOT));
+
+		/*
+		 * When the master clock is in use, anchor at its reference
+		 * point instead, projecting the realtime value back to the
+		 * same instant. The two clocks tick at the same rate across
+		 * the few ns in between, give or take NTP slew. Skip the
+		 * projection in the absurd case that it would take a
+		 * CLOCK_REALTIME set to within moments of the 1970 epoch
+		 * (legal with CAP_SYS_TIME) below zero and wrap.
+		 */
+		if (ka->use_master_clock &&
+		    now_real_ns >= now_raw_ns - ka->master_kernel_ns) {
+			now_real_ns -= now_raw_ns - ka->master_kernel_ns;
+			now_raw_ns = ka->master_kernel_ns;
+		}
 
 		/*
 		 * Avoid stepping the kvmclock backwards.
 		 */
 		if (now_real_ns > data.realtime)
 			data.clock += now_real_ns - data.realtime;
-	}
-
-	if (ka->use_master_clock)
+	} else if (ka->use_master_clock) {
 		now_raw_ns = ka->master_kernel_ns;
-	else
+	} else {
 		now_raw_ns = get_kvmclock_base_ns();
+	}
 	ka->kvmclock_offset = data.clock - now_raw_ns;
 	kvm_end_pvclock_update(kvm);
 	return 0;
@@ -6752,7 +7238,14 @@ static void kvm_hyperv_tsc_notifier(void)
 	kvm_caps.max_guest_tsc_khz = tsc_khz;
 
 	list_for_each_entry(kvm, &vm_list, vm_list) {
-		__kvm_start_pvclock_update(kvm);
+		/*
+		 * Invalidate the Hyper-V TSC page explicitly: the update
+		 * below consumes any pending KVM_REQ_MASTERCLOCK_UPDATE,
+		 * which would otherwise have refreshed the page from
+		 * kvm_update_masterclock().
+		 */
+		kvm_hv_request_tsc_page_update(kvm);
+		__kvm_start_pvclock_update(kvm, NULL);
 		pvclock_update_vm_gtod_copy(kvm);
 		kvm_end_pvclock_update(kvm);
 	}
@@ -6926,17 +7419,21 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);
 static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,
 			       void *priv)
 {
-	struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
 	struct timekeeper *tk = priv;
 
-	update_pvclock_gtod(tk);
+	/*
+	 * Pairs with the READ_ONCE() in the lockless readers; the race is
+	 * benign by design, relying on eventual consistency (the notifier
+	 * fires on every timekeeping update).
+	 */
+	WRITE_ONCE(kvm_host_vclock_mode, tk->tkr_mono.clock->vdso_clock_mode);
 
 	/*
 	 * Disable master clock if host does not trust, or does not use,
 	 * TSC based clocksource. Delegate queue_work() to irq_work as
 	 * this is invoked with tk_core.seq write held.
 	 */
-	if (!gtod_is_based_on_tsc(gtod->clock.vclock_mode) &&
+	if (!gtod_is_based_on_tsc(kvm_host_vclock_mode) &&
 	    atomic_read(&kvm_guest_has_master_clock) != 0)
 		irq_work_queue(&pvclock_irq_work);
 	return 0;
@@ -8158,8 +8655,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 			kvm_mmu_free_obsolete_roots(vcpu);
 		if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
 			__kvm_migrate_timers(vcpu);
-		if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
-			kvm_update_masterclock(vcpu->kvm);
+		if (kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
+			kvm_update_masterclock(vcpu->kvm, vcpu);
 		if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
 			kvm_gen_kvmclock_update(vcpu);
 		if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
@@ -9502,7 +9999,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	kvm_xen_init_vcpu(vcpu);
 	vcpu_load(vcpu);
 	kvm_vcpu_after_set_cpuid(vcpu);
-	kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz);
+	kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz, true);
 	kvm_vcpu_reset(vcpu, false);
 	kvm_init_mmu(vcpu);
 	vcpu_put(vcpu);
@@ -9527,12 +10024,39 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 {
-	if (mutex_lock_killable(&vcpu->mutex))
+	if (mutex_lock_killable(&vcpu->mutex)) {
+		/*
+		 * The new vCPU is already counted in online_vcpus but has
+		 * not been synchronized. Nothing recomputes the cached
+		 * matched state against the raised count until the next
+		 * synchronization, so clear it here rather than leave the
+		 * clock advertised as matched while an unmatched vCPU is
+		 * runnable. It heals when this vCPU first synchronizes.
+		 */
+		struct kvm_arch *ka = &vcpu->kvm->arch;
+		unsigned long flags;
+
+		raw_spin_lock_irqsave(&ka->tsc_write_lock, flags);
+		WRITE_ONCE(ka->all_vcpus_matched_tsc, false);
+		ka->all_vcpus_matched_freq = false;
+		raw_spin_unlock_irqrestore(&ka->tsc_write_lock, flags);
 		return;
+	}
 	vcpu_load(vcpu);
-	kvm_synchronize_tsc(vcpu, NULL);
-	if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
-		kvm_update_masterclock(vcpu->kvm);
+	kvm_synchronize_tsc(vcpu, NULL, false);
+
+	/*
+	 * Refresh the VM-creation masterclock snapshot (see
+	 * kvm_arch_init_vm), synchronously so that it is valid even for
+	 * userspace which queries the clock before ever running a vCPU.
+	 * Likewise service any masterclock update the synchronization
+	 * above requested on this vCPU, which would otherwise languish
+	 * until it first enters the guest.
+	 */
+	if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu) ||
+	    vcpu->vcpu_idx == 0)
+		kvm_update_masterclock(vcpu->kvm, NULL);
+
 	vcpu_put(vcpu);
 
 	/* poll control enabled by default */
@@ -9782,7 +10306,7 @@ int kvm_arch_enable_virtualization_cpu(void)
 {
 	struct kvm *kvm;
 	struct kvm_vcpu *vcpu;
-	unsigned long i;
+	unsigned long i, flags;
 	int ret;
 	u64 local_tsc;
 	u64 max_tsc = 0;
@@ -9853,6 +10377,44 @@ int kvm_arch_enable_virtualization_cpu(void)
 	if (backwards_tsc) {
 		u64 delta_cyc = max_tsc - local_tsc;
 		list_for_each_entry(kvm, &vm_list, vm_list) {
+			/*
+			 * Hold tsc_write_lock across the per-vCPU adjustments
+			 * AND the generation reference offset adjustment, so
+			 * that a concurrent TSC synchronization cannot observe
+			 * one without the other (it would compute an offset
+			 * with the delta applied twice, or not at all). The
+			 * consume of tsc_offset_adjustment in
+			 * kvm_arch_vcpu_load() remains outside the lock, as
+			 * it always was; its races are with vcpu_put/load
+			 * ordering, not with the generation state.
+			 *
+			 * The generation's reference offset is adjusted by the
+			 * same (guest-scaled, as adjust_tsc_offset_host()
+			 * does for each vCPU) delta, so that future
+			 * KVM_SET_TSC / vCPU creation still matches against
+			 * the adjusted TSC timeline.
+			 *
+			 * The recorded {cur_tsc_nsec, cur_tsc_write} pair is
+			 * left alone, and ends up stale by the sleep period:
+			 * cur_tsc_nsec is CLOCK_BOOTTIME, which has the sleep
+			 * injected on resume, while the guest TSC (kept
+			 * continuous across the host TSC jump) does not
+			 * advance during the sleep. It cannot be re-anchored
+			 * here because, as noted above, timekeeping has not
+			 * yet been resumed. The 1-second matching window
+			 * therefore fails to match across a longer sleep,
+			 * and the next nonzero TSC write opens a fresh,
+			 * coherent generation. A forced synchronization
+			 * (vCPU creation, or a zero write) bypasses the
+			 * window and does extrapolate along the stale line,
+			 * overshooting by the sleep period — but it installs
+			 * the compensated offset, so the vCPU's actual TSC
+			 * is correct; only last_guest_tsc overshoots, which
+			 * matters only if the TSC turns unstable before the
+			 * vCPU first enters the guest, exactly as it did
+			 * before this accounting existed.
+			 */
+			raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
 			kvm->arch.backwards_tsc_observed = true;
 			kvm_for_each_vcpu(i, vcpu, kvm) {
 				vcpu->arch.tsc_offset_adjustment += delta_cyc;
@@ -9860,14 +10422,10 @@ int kvm_arch_enable_virtualization_cpu(void)
 				kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 			}
 
-			/*
-			 * We have to disable TSC offset matching.. if you were
-			 * booting a VM while issuing an S4 host suspend....
-			 * you may have some problem.  Solving this issue is
-			 * left as an exercise to the reader.
-			 */
-			kvm->arch.last_tsc_nsec = 0;
-			kvm->arch.last_tsc_write = 0;
+			kvm->arch.cur_tsc_offset +=
+				kvm_scale_tsc(delta_cyc,
+					      kvm->arch.cur_tsc_scaling_ratio);
+			raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 		}
 
 	}
@@ -9937,6 +10495,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	int ret;
 	unsigned long flags;
+	u64 kvmclock_host_tsc;
+	s64 kvmclock_ns;
 
 	if (!kvm_is_vm_type_supported(type))
 		return -EINVAL;
@@ -9968,17 +10528,68 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc, &kvm->arch.tsc_write_lock);
 	ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10);
 	ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEASE);
-	kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
-
-	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-	pvclock_update_vm_gtod_copy(kvm);
-	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 
 	kvm->arch.default_tsc_khz = max_tsc_khz ? : tsc_khz;
 	kvm->arch.apic_bus_cycle_ns = APIC_BUS_CYCLE_NS_DEFAULT;
 	kvm->arch.guest_can_read_msr_platform_info = true;
 	kvm->arch.enable_pmu = enable_pmu && !kvm->arch.has_protected_pmu;
 
+	kvm->arch.all_vcpus_matched_freq = true;
+	/*
+	 * Start with all (zero) vCPUs considered matched, so that a VM whose
+	 * vCPUs never reach kvm_track_tsc_matching() — notably when the guest
+	 * TSC is protected (TDX, SNP Secure TSC) and __kvm_synchronize_tsc()
+	 * returns early — is still eligible for PVCLOCK_TSC_STABLE_BIT. The
+	 * scaling ratio must then also be initialized: with vcpus_matched
+	 * now true here, pvclock_update_vm_gtod_copy() reaches the scaling
+	 * path, and a zero ratio would zero tsc_hz and turn the master
+	 * clock straight back off (permanently so for protected-TSC guests,
+	 * which never write the ratio in __kvm_synchronize_tsc()).
+	 */
+	kvm->arch.all_vcpus_matched_tsc = true;
+	kvm->arch.cur_tsc_scaling_ratio = kvm_caps.default_tsc_scaling_ratio;
+
+	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
+
+	/*
+	 * Establish an initial TSC generation so that the master clock
+	 * snapshot taken below is immediately valid and KVM_GET_CLOCK
+	 * works before any vCPU exists. The snapshot is refreshed again
+	 * when the first vCPU is created, in case the host clocksource
+	 * changed (and changed back) in between: pvclock_gtod_update_fn()
+	 * does not notify a VM with no vCPUs.
+	 *
+	 * This generation is deliberately not matchable: cur_tsc_khz is
+	 * left at zero, which no vCPU frequency ever equals, so the first
+	 * vCPU opens its own generation with its TSC starting at zero,
+	 * exactly as it always has. Letting it match would make the first
+	 * vCPU's TSC start at the cycles elapsed since KVM_CREATE_VM — a
+	 * silent guest-visible change over an unbounded window — and
+	 * would hand it this offset verbatim even when a host suspend
+	 * reset the TSC in between, since the backwards-TSC compensation
+	 * in kvm_arch_enable_virtualization_cpu() detects the jump only
+	 * through existing vCPUs.
+	 */
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&kvmclock_ns, &kvmclock_host_tsc))
+#endif
+	{
+		/*
+		 * If not simultaneous, we want the TSC to be zero slightly
+		 * *after* the kvmclock is zero.
+		 */
+		kvmclock_ns = get_kvmclock_base_ns();
+		kvmclock_host_tsc = rdtsc();
+	}
+	kvm->arch.cur_tsc_write = 0;
+	kvm->arch.cur_tsc_offset = -(s64)kvmclock_host_tsc;
+	kvm->arch.cur_tsc_nsec = kvmclock_ns;
+	kvm->arch.cur_tsc_generation = 1;
+	kvm->arch.kvmclock_offset = -kvmclock_ns;
+
+	pvclock_update_vm_gtod_copy(kvm);
+	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+
 #if IS_ENABLED(CONFIG_HYPERV)
 	spin_lock_init(&kvm->arch.hv_root_tdp_lock);
 	kvm->arch.hv_root_tdp = INVALID_PAGE;
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 436e2fb1396c46..de4c86ea5a7de6 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -330,7 +330,7 @@ uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm);
 bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
 int kvm_guest_time_update(struct kvm_vcpu *v);
 
-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value);
+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated);
 u64 kvm_scale_tsc(u64 tsc, u64 ratio);
 u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
 u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier);
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 6aa00f746cba39..dae43acb3cc37d 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -188,7 +188,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 	struct kvm_vcpu_xen *xen = &vcpu->arch.xen;
 	int64_t kernel_now, delta;
 	uint64_t guest_now;
-	int r = -EOPNOTSUPP;
+	bool fallback = true;
 
 	/*
 	 * The guest provides the requested timeout in absolute nanoseconds
@@ -210,6 +210,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 	do {
 		struct pvclock_vcpu_time_info hv_clock;
 		uint64_t host_tsc, guest_tsc;
+		int r = -EOPNOTSUPP;
 
 		if (!cpu_feature_enabled(X86_FEATURE_CONSTANT_TSC) ||
 		    !vcpu->kvm->arch.use_master_clock)
@@ -230,43 +231,40 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 		if (r)
 			break;
 
+		/*
+		 * With use_master_clock set, the clocksource was TSC-based
+		 * when the master clock was last updated. The clockread can
+		 * only fail here if the clocksource has changed since, in
+		 * which case a masterclock update is already pending and
+		 * get_kvmclock_ns() returns the raw-clock fallback value —
+		 * continuous with the last valid snapshot, which is as good
+		 * as it gets in that transient window.
+		 */
 		if (!IS_ENABLED(CONFIG_64BIT) ||
-		    !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc)) {
-			/*
-			 * Don't fall back to get_kvmclock_ns() because it's
-			 * broken; it has a systemic error in its results
-			 * because it scales directly from host TSC to
-			 * nanoseconds, and doesn't scale first to guest TSC
-			 * and *then* to nanoseconds as the guest does.
-			 *
-			 * There is a small error introduced here because time
-			 * continues to elapse between the ktime_get() and the
-			 * subsequent rdtsc(). But not the systemic drift due
-			 * to get_kvmclock_ns().
-			 */
-			kernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */
-			host_tsc = rdtsc();
-		}
+		    !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc))
+			break;
 
 		/* Calculate the guest kvmclock as the guest would do it. */
 		guest_tsc = kvm_read_l1_tsc(vcpu, host_tsc);
 		guest_now = __pvclock_read_cycles(&hv_clock, guest_tsc);
+		fallback = false;
 	} while (0);
 
-	if (r) {
+	if (fallback) {
 		/*
-		 * Without CONSTANT_TSC, get_kvmclock_ns() is the only option.
+		 * Without CONSTANT_TSC and the master clock,
+		 * get_kvmclock_ns() is the only option.
 		 *
 		 * Also if the guest PV clock hasn't been set up yet, as is
 		 * likely to be the case during migration when the vCPU has
 		 * not been run yet. It would be possible to calculate the
 		 * scaling factors properly in that case but there's not much
-		 * point in doing so. The get_kvmclock_ns() drift accumulates
-		 * over time, so it's OK to use it at startup. Besides, on
-		 * migration there's going to be a little bit of skew in the
-		 * precise moment at which timers fire anyway. Often they'll
-		 * be in the "past" by the time the VM is running again after
-		 * migration.
+		 * point in doing so. Without the master clock, the
+		 * get_kvmclock_ns() drift accumulates over time, so it's OK
+		 * to use it at startup. Besides, on migration there's going
+		 * to be a little bit of skew in the precise moment at which
+		 * timers fire anyway. Often they'll be in the "past" by the
+		 * time the VM is running again after migration.
 		 */
 		guest_now = get_kvmclock_ns(vcpu->kvm);
 		kernel_now = ktime_get();
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8dff2fc1972e97..1349387cceb040 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1000,6 +1000,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_PPC_COMPAT_CAPS 250
 #define KVM_CAP_ARM_PMU_V3_STRICT 251
 #define KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES 252
+#define KVM_CAP_CLOCK_GUEST 253
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1690,4 +1691,7 @@ struct kvm_pre_fault_memory {
 	__u64 padding[5];
 };
 
+#define KVM_SET_CLOCK_GUEST	_IOW(KVMIO, 0xd6, struct pvclock_vcpu_time_info)
+#define KVM_GET_CLOCK_GUEST	_IOR(KVMIO, 0xd7, struct pvclock_vcpu_time_info)
+
 #endif /* __LINUX_KVM_H */
diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh
index f18b00843df3ff..51a722198997da 100755
--- a/scripts/xen-hypercalls.sh
+++ b/scripts/xen-hypercalls.sh
@@ -5,7 +5,7 @@ shift
 in="$@"
 
 for i in $in; do
-	eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null
+	eval $CPP -D__KERNEL__ $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null
 done | \
 awk '$1 == "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 }
 	END {   print "/* auto-generated by scripts/xen-hypercall.sh */"
diff --git a/tools/arch/x86/include/asm/pvclock-abi.h b/tools/arch/x86/include/asm/pvclock-abi.h
index b9fece5fc96d6f..6d70cf64036293 100644
--- a/tools/arch/x86/include/asm/pvclock-abi.h
+++ b/tools/arch/x86/include/asm/pvclock-abi.h
@@ -1,6 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef _ASM_X86_PVCLOCK_ABI_H
 #define _ASM_X86_PVCLOCK_ABI_H
+
+#include <linux/types.h>
+
 #ifndef __ASSEMBLER__
 
 /*
@@ -24,20 +27,20 @@
  */
 
 struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
+	__u32   version;
+	__u32   pad0;
+	__u64   tsc_timestamp;
+	__u64   system_time;
+	__u32   tsc_to_system_mul;
+	__s8    tsc_shift;
+	__u8    flags;
+	__u8    pad[2];
 } __attribute__((__packed__)); /* 32 bytes */
 
 struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
+	__u32   version;
+	__u32   sec;
+	__u32   nsec;
 } __attribute__((__packed__));
 
 #define PVCLOCK_TSC_STABLE_BIT	(1 << 0)
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h
index 1585ec8040666e..7b3afccb6cb237 100644
--- a/tools/arch/x86/include/uapi/asm/kvm.h
+++ b/tools/arch/x86/include/uapi/asm/kvm.h
@@ -963,6 +963,12 @@ struct kvm_hyperv_eventfd {
 /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
 #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
 #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */
+
+struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+};
 
 /* x86-specific KVM_EXIT_HYPERCALL flags. */
 #define KVM_EXIT_HYPERCALL_LONG_MODE	_BITULL(0)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 888a7530a2808f..fd063806a7fb96 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -95,6 +95,7 @@ TEST_GEN_PROGS_x86 += x86/hyperv_tlb_flush
 TEST_GEN_PROGS_x86 += x86/kvm_clock_test
 TEST_GEN_PROGS_x86 += x86/kvm_pv_test
 TEST_GEN_PROGS_x86 += x86/kvm_buslock_test
+TEST_GEN_PROGS_x86 += x86/masterclock_offset_test
 TEST_GEN_PROGS_x86 += x86/monitor_mwait_test
 TEST_GEN_PROGS_x86 += x86/msrs_test
 TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test
@@ -113,6 +114,8 @@ TEST_GEN_PROGS_x86 += x86/pmu_counters_test
 TEST_GEN_PROGS_x86 += x86/pmu_event_filter_test
 TEST_GEN_PROGS_x86 += x86/private_mem_conversions_test
 TEST_GEN_PROGS_x86 += x86/private_mem_kvm_exits_test
+TEST_GEN_PROGS_x86 += x86/pvclock_migration_test
+TEST_GEN_PROGS_x86 += x86/pvclock_test
 TEST_GEN_PROGS_x86 += x86/save_restore_pf_stress_test
 TEST_GEN_PROGS_x86 += x86/set_boot_cpu_id
 TEST_GEN_PROGS_x86 += x86/set_sregs_test
@@ -148,7 +151,10 @@ TEST_GEN_PROGS_x86 += x86/xcr0_cpuid_test
 TEST_GEN_PROGS_x86 += x86/xss_msr_test
 TEST_GEN_PROGS_x86 += x86/debug_regs
 TEST_GEN_PROGS_x86 += x86/tsc_msrs_test
+TEST_GEN_PROGS_x86 += x86/tsc_user_set_test
 TEST_GEN_PROGS_x86 += x86/vmx_pmu_caps_test
+TEST_GEN_PROGS_x86 += x86/xen_cpuid_timing_test
+TEST_GEN_PROGS_x86 += x86/xen_migration_test
 TEST_GEN_PROGS_x86 += x86/xen_shinfo_test
 TEST_GEN_PROGS_x86 += x86/xen_vmcall_test
 TEST_GEN_PROGS_x86 += x86/sev_dbg_test
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 5898a277a2e01c..4062bdb3271604 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -12,6 +12,7 @@
 
 #include <asm/msr-index.h>
 #include <asm/prctl.h>
+#include <asm/pvclock-abi.h>
 
 #include <linux/kvm_para.h>
 #include <linux/stringify.h>
@@ -1029,6 +1030,55 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
 	vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs);
 }
 
+static inline int __vcpu_get_clock_guest(struct kvm_vcpu *vcpu,
+					 struct pvclock_vcpu_time_info *pvti)
+{
+	return __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);
+}
+
+static inline void vcpu_get_clock_guest(struct kvm_vcpu *vcpu,
+					struct pvclock_vcpu_time_info *pvti)
+{
+	vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);
+}
+
+static inline int __vcpu_set_clock_guest(struct kvm_vcpu *vcpu,
+					 struct pvclock_vcpu_time_info *pvti)
+{
+	return __vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);
+}
+
+static inline void vcpu_set_clock_guest(struct kvm_vcpu *vcpu,
+					struct pvclock_vcpu_time_info *pvti)
+{
+	vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);
+}
+
+static inline u64 vcpu_get_tsc_offset(struct kvm_vcpu *vcpu)
+{
+	u64 offset;
+
+	vcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
+			     &offset);
+	return offset;
+}
+
+static inline void vcpu_set_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+	vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
+			     &offset);
+}
+
+static inline void vm_get_clock(struct kvm_vm *vm, struct kvm_clock_data *data)
+{
+	vm_ioctl(vm, KVM_GET_CLOCK, data);
+}
+
+static inline void vm_set_clock(struct kvm_vm *vm, struct kvm_clock_data *data)
+{
+	vm_ioctl(vm, KVM_SET_CLOCK, data);
+}
+
 const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
 					       u32 function, u32 index);
 const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
diff --git a/tools/testing/selftests/kvm/x86/masterclock_offset_test.c b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c
new file mode 100644
index 00000000000000..faf81872538ebb
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that KVM master clock mode works with different TSC offsets
+ * as long as all vCPUs have the same TSC frequency.
+ */
+#include <string.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock.h>
+#include <asm/pvclock-abi.h>
+
+#define KVMCLOCK_GPA	0xc0000000ull
+#define TSC_OFFSET	(1000000000ULL)
+
+#define NR_VCPUS	3
+
+/* Read the per-vCPU pvclocks in an order other than creation order. */
+static const int vcpu_order[NR_VCPUS] = {0, 2, 1};
+
+static void guest_code(u64 pvti_gpa)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, pvti_gpa | KVM_MSR_ENABLED);
+	for (;;)
+		GUEST_SYNC(0);
+}
+
+static void get_pvtis(struct kvm_vcpu **vcpus,
+		      struct pvclock_vcpu_time_info *pvti)
+{
+	int i;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		int idx = vcpu_order[i];
+
+		vcpu_get_clock_guest(vcpus[idx], &pvti[idx]);
+		pr_info("vCPU %d: tsc_timestamp=%lu system_time=%lu "
+			"mul=%u shift=%d flags=0x%x\n",
+			idx, (unsigned long)pvti[idx].tsc_timestamp,
+			(unsigned long)pvti[idx].system_time,
+			pvti[idx].tsc_to_system_mul, pvti[idx].tsc_shift,
+			pvti[idx].flags);
+	}
+}
+
+/*
+ * Read the host TSC once and feed it through each vCPU's pvclock
+ * (adding each vCPU's TSC offset). All must compute exactly the same
+ * kvmclock value.
+ */
+static void assert_pvclocks_match(struct pvclock_vcpu_time_info *pvti,
+				  u64 offset0, const char *what)
+{
+	u64 host_tsc, clk0, clk1, clk2;
+
+	host_tsc = rdtsc();
+	clk0 = __pvclock_read_cycles(&pvti[0], host_tsc + offset0);
+	clk1 = __pvclock_read_cycles(&pvti[1], host_tsc + offset0);
+	clk2 = __pvclock_read_cycles(&pvti[2], host_tsc + offset0 + TSC_OFFSET);
+
+	pr_info("%s: kvmclock via vCPU 0: %lu ns, vCPU 1: %lu ns, vCPU 2: %lu ns\n",
+		what, (unsigned long)clk0, (unsigned long)clk1,
+		(unsigned long)clk2);
+	TEST_ASSERT(clk0 == clk1 && clk0 == clk2,
+		    "%s: kvmclock from all vCPUs should match exactly "
+		    "(0: %lu, 1: %lu, 2: %lu)", what, (unsigned long)clk0,
+		    (unsigned long)clk1, (unsigned long)clk2);
+}
+
+static void test_masterclock_active(struct kvm_vm *vm,
+				    struct kvm_clock_data *clock)
+{
+	memset(clock, 0, sizeof(*clock));
+	vm_get_clock(vm, clock);
+	pr_info("KVM_GET_CLOCK flags: 0x%x\n", clock->flags);
+	TEST_ASSERT(clock->flags & KVM_CLOCK_HOST_TSC,
+		    "Master clock should be active, flags=0x%x", clock->flags);
+	TEST_ASSERT(clock->flags & KVM_CLOCK_TSC_STABLE,
+		    "KVM_CLOCK_TSC_STABLE should be set, flags=0x%x",
+		    clock->flags);
+}
+
+static void test_offset_consistency(struct kvm_vcpu **vcpus,
+				    struct pvclock_vcpu_time_info *pvti,
+				    u64 offset0)
+{
+	u64 gtsc0, gtsc1, gtsc2;
+
+	get_pvtis(vcpus, pvti);
+
+	/* Read guest TSCs: should see (0+OFF) < 2 < (1+OFF) */
+	gtsc0 = vcpu_get_msr(vcpus[0], MSR_IA32_TSC);
+	gtsc2 = vcpu_get_msr(vcpus[2], MSR_IA32_TSC);
+	gtsc1 = vcpu_get_msr(vcpus[1], MSR_IA32_TSC);
+	pr_info("Guest TSCs: vcpu0=%lu vcpu2=%lu vcpu1=%lu\n",
+		(unsigned long)gtsc0, (unsigned long)gtsc2,
+		(unsigned long)gtsc1);
+	TEST_ASSERT(gtsc0 + TSC_OFFSET < gtsc2 && gtsc2 < gtsc1 + TSC_OFFSET,
+		    "Expected (vcpu0+OFF) < vcpu2 < (vcpu1+OFF)");
+
+	/* PVCLOCK_TSC_STABLE_BIT should NOT be set (offsets differ) */
+	TEST_ASSERT(!(pvti[2].flags & PVCLOCK_TSC_STABLE_BIT),
+		    "PVCLOCK_TSC_STABLE_BIT should NOT be set, flags=0x%x",
+		    pvti[2].flags);
+
+	/* Same mul/shift */
+	TEST_ASSERT(pvti[0].tsc_to_system_mul == pvti[1].tsc_to_system_mul &&
+		    pvti[0].tsc_to_system_mul == pvti[2].tsc_to_system_mul &&
+		    pvti[0].tsc_shift == pvti[1].tsc_shift &&
+		    pvti[0].tsc_shift == pvti[2].tsc_shift,
+		    "All vCPUs should have same mul/shift");
+
+	assert_pvclocks_match(pvti, offset0, "Initial");
+}
+
+#define ONE_HOUR_NS (3600ULL * NSEC_PER_SEC)
+
+static void test_set_clock_consistency(struct kvm_vm *vm,
+				       struct kvm_vcpu **vcpus,
+				       struct pvclock_vcpu_time_info *pvti,
+				       struct kvm_clock_data *clock,
+				       u64 offset0)
+{
+	struct kvm_clock_data setclk = { .clock = clock->clock + ONE_HOUR_NS };
+	u64 clk0;
+	int i;
+
+	/*
+	 * Add an hour to the VM kvmclock via KVM_SET_CLOCK, run each
+	 * vCPU to pick up the update, and check they're still in sync.
+	 */
+	vm_set_clock(vm, &setclk);
+
+	/* Guest code does GUEST_SYNC then exits — run each to see update */
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_run(vcpus[vcpu_order[i]]);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpus[vcpu_order[i]], KVM_EXIT_IO);
+	}
+
+	get_pvtis(vcpus, pvti);
+
+	TEST_ASSERT(pvti[0].system_time == pvti[1].system_time &&
+		    pvti[0].system_time == pvti[2].system_time,
+		    "system_time should still match after KVM_SET_CLOCK");
+
+	assert_pvclocks_match(pvti, offset0, "After +1h");
+
+	/* Verify the clock actually moved by ~1 hour */
+	clk0 = __pvclock_read_cycles(&pvti[0], rdtsc() + offset0);
+	TEST_ASSERT(clk0 > ONE_HOUR_NS,
+		    "Clock should be > 1 hour after set, got %lu ns",
+		    (unsigned long)clk0);
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti[NR_VCPUS];
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct kvm_clock_data clock;
+	struct kvm_vm *vm;
+	u64 offset0;
+	int nr_pages;
+	int i;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	TEST_REQUIRE(!__vcpu_has_device_attr(vcpus[0], KVM_VCPU_TSC_CTRL,
+					     KVM_VCPU_TSC_OFFSET));
+
+	nr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, nr_pages, 0);
+
+	/* Give each vCPU its own pvclock structure within the page */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_args_set(vcpus[i], 1, KVMCLOCK_GPA +
+			      i * sizeof(struct pvclock_vcpu_time_info) * 2);
+
+	/* Get vCPU 0's default offset and set vCPU 2's offset higher */
+	offset0 = vcpu_get_tsc_offset(vcpus[0]);
+	vcpu_set_tsc_offset(vcpus[2], offset0 + TSC_OFFSET);
+
+	/* Run each vCPU to enable kvmclock (with offset already set) */
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_run(vcpus[i]);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpus[i], KVM_EXIT_IO);
+	}
+
+	test_masterclock_active(vm, &clock);
+	test_offset_consistency(vcpus, pvti, offset0);
+	pr_info("PASSED: pvclock consistent across offset vCPUs\n");
+
+	test_set_clock_consistency(vm, vcpus, pvti, &clock, offset0);
+	pr_info("PASSED: pvclock still consistent after KVM_SET_CLOCK +1h\n");
+
+	kvm_vm_free(vm);
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/pvclock_migration_test.c b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c
new file mode 100644
index 00000000000000..c18c9132308d6c
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test KVM clock precision across simulated live migration.
+ *
+ * Verifies that the documented TSC migration procedure (using
+ * KVM_VCPU_TSC_OFFSET, KVM_VCPU_TSC_SCALE, KVM_GET_CLOCK, and
+ * KVM_SET_CLOCK_GUEST) preserves the kvmclock's relationship to
+ * CLOCK_MONOTONIC_RAW — including for vCPUs whose TSCs are offset
+ * from one another (same frequency), which no longer disables the
+ * master clock.
+ *
+ * The test:
+ * 1. Creates a VM with 3 vCPUs, runs each guest to enable kvmclock
+ * 2. Applies divergent TSC offsets to vCPUs 1 and 2
+ * 3. Verifies the master clock remains active (KVM_CLOCK_HOST_TSC),
+ *    that the guests see PVCLOCK_TSC_STABLE_BIT clear, and that all
+ *    vCPUs' pvclocks agree on "now" despite the divergent offsets
+ * 4. Does a PTP-like ABA measurement of kvmclock vs CLOCK_MONOTONIC_RAW
+ * 5. Follows the documented migration procedure (same host, 1s pause),
+ *    migrating each vCPU's TSC individually but setting the KVM clock
+ *    only once, via KVM_SET_CLOCK_GUEST on vCPU0
+ * 6. Does the same ABA measurement on the destination VM
+ * 7. Verifies the kvmclock-vs-monotonic delta is preserved, the
+ *    cross-vCPU TSC deltas are preserved, and all destination vCPUs'
+ *    pvclocks again agree on "now"
+ */
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+#define KVMCLOCK_GPA	0xc0000000ULL
+#define NR_VCPUS	3
+
+/*
+ * Divergent TSC offsets applied to vCPUs 1 and 2, in guest cycles.
+ * Roughly +1s and -0.5s at 1.5 GHz — large enough that any failure
+ * to account for them is orders of magnitude outside the ABA bounds.
+ */
+static const s64 tsc_deltas[NR_VCPUS] = { 0, 1500000000LL, -750000000LL };
+
+static void guest_code(int idx)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, (KVMCLOCK_GPA + idx * PAGE_SIZE) | 1);
+
+	for (;;)
+		GUEST_SYNC(0);
+}
+
+static u64 read_kvmclock_ns(struct kvm_vm *vm)
+{
+	struct kvm_clock_data data = {};
+
+	vm_get_clock(vm, &data);
+	return data.clock;
+}
+
+static u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,
+				    u64 tsc)
+{
+	u64 delta = tsc - src->tsc_timestamp;
+	u64 ns;
+
+	if (src->tsc_shift >= 0)
+		delta <<= src->tsc_shift;
+	else
+		delta >>= -(s32)src->tsc_shift;
+
+	ns = (unsigned __int128)delta * src->tsc_to_system_mul >> 32;
+	return src->system_time + ns;
+}
+
+/*
+ * ABA measurement: read CLOCK_MONOTONIC_RAW, kvmclock, CLOCK_MONOTONIC_RAW.
+ * Repeat 3 times, keep the reading with the smallest spread.
+ */
+static void aba_reading(struct kvm_vm *vm, u64 *lo, u64 *kvm_ns,
+			u64 *hi)
+{
+	u64 best_spread = UINT64_MAX;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		struct timespec ts1, ts2;
+		u64 m1, m2, clk;
+
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
+		clk = read_kvmclock_ns(vm);
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
+
+		m1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;
+		m2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;
+
+		if (m2 - m1 < best_spread) {
+			best_spread = m2 - m1;
+			*lo = m1;
+			*kvm_ns = clk;
+			*hi = m2;
+		}
+	}
+}
+
+static struct kvm_vm *create_vm(struct kvm_vcpu **vcpus, u32 freq_khz)
+{
+	struct kvm_vm *vm;
+	int i;
+
+	vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, NR_VCPUS, 0);
+	virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, NR_VCPUS);
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_args_set(vcpus[i], 1, i);
+		/* Set guest TSC frequency (may trigger scaling) */
+		vcpu_ioctl(vcpus[i], KVM_SET_TSC_KHZ,
+			   (void *)(unsigned long)freq_khz);
+	}
+	return vm;
+}
+
+static void run_to_sync(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+}
+
+/*
+ * Compute a vCPU's guest TSC for a given host TSC value, using the
+ * vCPU's scale and offset as saved from KVM_VCPU_TSC_SCALE/OFFSET.
+ */
+static u64 host_to_guest_tsc(struct kvm_vcpu_tsc_scale *scale, u64 ofs,
+			     u64 host_tsc)
+{
+	if (scale->tsc_frac_bits)
+		return ((unsigned __int128)host_tsc * scale->tsc_ratio
+			>> scale->tsc_frac_bits) + ofs;
+	return host_tsc + ofs;
+}
+
+/*
+ * Verify that all vCPUs agree on the KVM clock, despite having
+ * different TSC offsets. Take one atomic {host_tsc, kvmclock} pair
+ * for the whole VM, derive each vCPU's guest TSC at that instant,
+ * and evaluate each vCPU's pvti at its own guest TSC. All must give
+ * the same nanosecond value (same instant, same clock), and must
+ * match what KVM_GET_CLOCK itself said.
+ */
+static void check_cross_vcpu_coherence(struct kvm_vm *vm,
+				       struct kvm_vcpu **vcpus,
+				       struct pvclock_vcpu_time_info *pvtis,
+				       const char *what)
+{
+	struct kvm_clock_data now = {};
+	u64 clk[NR_VCPUS];
+	int i;
+
+	vm_get_clock(vm, &now);
+	TEST_ASSERT(now.flags & KVM_CLOCK_HOST_TSC,
+		    "%s: master clock inactive with divergent TSC offsets",
+		    what);
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct kvm_vcpu_tsc_scale scale = {};
+		u64 ofs = vcpu_get_tsc_offset(vcpus[i]);
+		u64 guest_tsc;
+
+		vcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale);
+		guest_tsc = host_to_guest_tsc(&scale, ofs, now.host_tsc);
+		clk[i] = pvclock_read_cycles(&pvtis[i], guest_tsc);
+
+		TEST_ASSERT(!(pvtis[i].flags & PVCLOCK_TSC_STABLE_BIT),
+			    "%s: vCPU%d still advertises TSC_STABLE with divergent offsets",
+			    what, i);
+	}
+
+	for (i = 1; i < NR_VCPUS; i++) {
+		s64 d = (s64)(clk[i] - clk[0]);
+
+		pr_info("  %s: vCPU%d vs vCPU0 kvmclock delta %" PRId64 " ns\n",
+			what, i, d);
+		TEST_ASSERT(d >= -2 && d <= 2,
+			    "%s: vCPU%d kvmclock disagrees with vCPU0 by %" PRId64 " ns",
+			    what, i, d);
+	}
+
+	/* And all of them must agree with KVM_GET_CLOCK itself */
+	s64 d0 = (s64)(clk[0] - now.clock);
+	pr_info("  %s: vCPU0 pvclock vs KVM_GET_CLOCK delta %" PRId64 " ns\n",
+		what, d0);
+	TEST_ASSERT(d0 >= -2 && d0 <= 2,
+		    "%s: vCPU0 pvclock disagrees with KVM_GET_CLOCK by %" PRId64 " ns",
+		    what, d0);
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti_src[NR_VCPUS];
+	struct pvclock_vcpu_time_info pvti_dst_ioctl[NR_VCPUS];
+	struct kvm_clock_data clock_src, clock_dst;
+	struct kvm_vcpu_tsc_scale scale_src[NR_VCPUS], scale_dst;
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct kvm_vm *vm;
+	u64 mono_before, kvm_before, kvm_after;
+	s64 delta_before;
+	u64 ofs_src[NR_VCPUS], tsc_src[NR_VCPUS], tsc_dst, raw_dst;
+	u64 ofs_dst[NR_VCPUS];
+	u64 host_tsc_src, host_tsc_dst;
+	u64 time_src, time_dst;
+	s64 delta_t;
+	u32 freq_khz = 1500000; /* 1.5 GHz — forces TSC scaling */
+	int i, pass;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	/* === SOURCE SIDE === */
+	pr_info("=== Source VM ===\n");
+	vm = create_vm(vcpus, freq_khz);
+
+	/* Run each guest to enable its kvmclock */
+	for (i = 0; i < NR_VCPUS; i++)
+		run_to_sync(vcpus[i]);
+
+	/*
+	 * Apply divergent TSC offsets. Same frequency, different offsets:
+	 * this must no longer disable the master clock, but must clear
+	 * PVCLOCK_TSC_STABLE_BIT.
+	 */
+	for (i = 1; i < NR_VCPUS; i++)
+		vcpu_set_tsc_offset(vcpus[i],
+				    vcpu_get_tsc_offset(vcpus[i]) + tsc_deltas[i]);
+
+	/*
+	 * Re-run each vCPU twice. The offset writes leave a masterclock
+	 * update pending on vCPUs 1 and 2; the first pass processes it and
+	 * broadcasts KVM_REQ_CLOCK_UPDATE to every vCPU, and the second
+	 * pass has each vCPU rewrite its guest-visible pvclock page with
+	 * PVCLOCK_TSC_STABLE_BIT now clear. A single pass would leave
+	 * vCPU0's page stale: its rewrite happens before the broadcast.
+	 */
+	for (pass = 0; pass < 2; pass++)
+		for (i = 0; i < NR_VCPUS; i++)
+			run_to_sync(vcpus[i]);
+
+	/* Fetch each vCPU's pvti and verify cross-vCPU coherence */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_get_clock_guest(vcpus[i], &pvti_src[i]);
+	check_cross_vcpu_coherence(vm, vcpus, pvti_src, "source");
+
+	/* The guest-visible pvti pages must also show TSC_STABLE clear */
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct pvclock_vcpu_time_info *pvti =
+			addr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());
+
+		TEST_ASSERT(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT),
+			    "vCPU%d guest pvti advertises TSC_STABLE with divergent offsets", i);
+	}
+
+	/* ABA measurement: kvmclock vs CLOCK_MONOTONIC_RAW */
+	u64 src_mono_lo, src_mono_hi;
+	aba_reading(vm, &src_mono_lo, &kvm_before, &src_mono_hi);
+	mono_before = (src_mono_lo + src_mono_hi) / 2;
+	delta_before = (s64)(kvm_before - mono_before);
+	pr_info("  kvmclock - MONOTONIC_RAW = %" PRId64 " ns (±%" PRIu64 " ns)\n",
+		delta_before, (src_mono_hi - src_mono_lo) / 2);
+
+	/* Step 1: KVM_GET_CLOCK for atomic {host_tsc, realtime} */
+	memset(&clock_src, 0, sizeof(clock_src));
+	clock_src.flags = KVM_CLOCK_REALTIME;
+	vm_get_clock(vm, &clock_src);
+	TEST_ASSERT(clock_src.flags & KVM_CLOCK_HOST_TSC,
+		    "KVM_GET_CLOCK did not provide host_tsc (no master clock?)");
+	host_tsc_src = clock_src.host_tsc;
+	time_src = clock_src.realtime;
+
+	/* Step 2: Save each vCPU's TSC offset and scale */
+	for (i = 0; i < NR_VCPUS; i++) {
+		ofs_src[i] = vcpu_get_tsc_offset(vcpus[i]);
+		memset(&scale_src[i], 0, sizeof(scale_src[i]));
+		vcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale_src[i]);
+
+		/* Compute this vCPU's guest TSC at Tsrc */
+		tsc_src[i] = host_to_guest_tsc(&scale_src[i], ofs_src[i],
+					       host_tsc_src);
+		pr_info("  vCPU%d: TSC freq=%u kHz, offset=%" PRId64 "\n",
+			i, freq_khz, (s64)ofs_src[i]);
+	}
+
+	/* Step 3: KVM_GET_CLOCK_GUEST (already fetched above as pvti_src[]) */
+
+	kvm_vm_free(vm);
+
+	/* === PAUSE (simulate migration) === */
+	pr_info("=== Pausing 1 second ===\n");
+	sleep(1);
+
+	/* === DESTINATION SIDE === */
+	pr_info("=== Destination VM ===\n");
+	/* Step 4: create + KVM_SET_TSC_KHZ (in create_vm) */
+	vm = create_vm(vcpus, freq_khz);
+
+	/* Step 5: KVM_GET_CLOCK for atomic {host_tsc, realtime} pair.
+	 * Master clock is active from VM creation.
+	 */
+	memset(&clock_dst, 0, sizeof(clock_dst));
+	vm_get_clock(vm, &clock_dst);
+	TEST_ASSERT(clock_dst.flags & KVM_CLOCK_HOST_TSC,
+		    "KVM_GET_CLOCK did not provide host_tsc (no master clock?)");
+	host_tsc_dst = clock_dst.host_tsc;
+	time_dst = clock_dst.realtime;
+
+	/* Step 6: ΔT */
+	delta_t = (s64)(time_dst - time_src);
+
+	/* Step 7: Compute and set each vCPU's destination offset */
+	memset(&scale_dst, 0, sizeof(scale_dst));
+	vcpu_device_attr_get(vcpus[0], KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_SCALE,
+			     &scale_dst);
+
+	if (scale_dst.tsc_frac_bits)
+		raw_dst = (unsigned __int128)host_tsc_dst * scale_dst.tsc_ratio
+			  >> scale_dst.tsc_frac_bits;
+	else
+		raw_dst = host_tsc_dst;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		tsc_dst = tsc_src[i] + (u64)((s64)freq_khz * delta_t / 1000000LL);
+		ofs_dst[i] = tsc_dst - raw_dst;
+		vcpu_set_tsc_offset(vcpus[i], ofs_dst[i]);
+	}
+
+	/*
+	 * The cross-vCPU TSC relationships must be preserved exactly:
+	 * every vCPU's offset moved by the same amount, so the deltas
+	 * between them are untouched by the CLOCK_REALTIME imprecision.
+	 */
+	for (i = 1; i < NR_VCPUS; i++) {
+		s64 src_delta = (s64)(ofs_src[i] - ofs_src[0]);
+		s64 dst_delta = (s64)(ofs_dst[i] - ofs_dst[0]);
+
+		pr_info("  vCPU%d-vCPU0 TSC delta: src %" PRId64
+			", dst %" PRId64 " cycles\n", i, src_delta, dst_delta);
+		TEST_ASSERT(src_delta == dst_delta,
+			    "vCPU%d TSC delta not preserved: %" PRId64 " -> %" PRId64,
+			    i, src_delta, dst_delta);
+	}
+
+	/*
+	 * The TSC offset delta introduced by using CLOCK_REALTIME to
+	 * estimate elapsed time. On same host, the correct offset is
+	 * ofs_src; the difference is the CLOCK_REALTIME-vs-TSC error.
+	 */
+	s64 tsc_ofs_delta = (s64)(ofs_dst[0] - ofs_src[0]);
+	s64 tsc_ofs_delta_ns = tsc_ofs_delta * 1000000LL / freq_khz;
+	pr_info("  Destination TSC offset=%" PRId64
+		", imprecision from CLOCK_REALTIME: %" PRId64 " cycles = %"
+		PRId64 " ns\n", (s64)ofs_dst[0], tsc_ofs_delta, tsc_ofs_delta_ns);
+
+	/*
+	 * Step 8: KVM_SET_CLOCK_GUEST — once, via vCPU0. The other
+	 * vCPUs' clocks must come out right too: the KVM clock is
+	 * VM-wide, and each vCPU's pvti relates it to that vCPU's
+	 * own TSC.
+	 */
+	vcpu_set_clock_guest(vcpus[0], &pvti_src[0]);
+
+	/* Run each guest to write its pvclock page on the destination */
+	for (i = 0; i < NR_VCPUS; i++)
+		run_to_sync(vcpus[i]);
+
+	/* Verify cross-vCPU coherence on the destination */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_get_clock_guest(vcpus[i], &pvti_dst_ioctl[i]);
+	check_cross_vcpu_coherence(vm, vcpus, pvti_dst_ioctl, "dest");
+
+	/* ABA measurement on destination */
+	u64 mono_lo, mono_hi;
+	aba_reading(vm, &mono_lo, &kvm_after, &mono_hi);
+
+	/*
+	 * The kvmclock is tied to the guest TSC via SET_CLOCK_GUEST.
+	 * The guest TSC is offset from the correct value by tsc_ofs_delta_ns
+	 * (due to CLOCK_REALTIME imprecision). So the kvmclock should be
+	 * offset from CLOCK_MONOTONIC_RAW by exactly:
+	 *   (original delta) + tsc_ofs_delta_ns
+	 *
+	 * The "original delta" has uncertainty from the source ABA spread,
+	 * and the measurement has uncertainty from the destination ABA spread.
+	 * Verify the expected value falls within the combined bounds.
+	 */
+	s64 delta_before_lo = (s64)(kvm_before - src_mono_hi);
+	s64 delta_before_hi = (s64)(kvm_before - src_mono_lo);
+	s64 expected_lo = delta_before_lo + tsc_ofs_delta_ns;
+	s64 expected_hi = delta_before_hi + tsc_ofs_delta_ns;
+	s64 actual_lo = (s64)(kvm_after - mono_hi);
+	s64 actual_hi = (s64)(kvm_after - mono_lo);
+
+	/* Show the shift relative to the source measurement */
+	s64 expected_mid = tsc_ofs_delta_ns;
+	s64 expected_err = (s64)(src_mono_hi - src_mono_lo) / 2;
+	s64 actual_mid = ((actual_lo + actual_hi) / 2) - delta_before;
+	s64 actual_err = (s64)(mono_hi - mono_lo) / 2;
+	pr_info("  kvmclock-mono shift: expected %" PRId64 " ns (±%" PRId64
+		"), measured %" PRId64 " ns (±%" PRId64 ")\n",
+		expected_mid, expected_err, actual_mid, actual_err);
+
+	/* The ranges must overlap */
+	TEST_ASSERT(expected_hi >= actual_lo && expected_lo <= actual_hi,
+		    "Ranges don't overlap: expected [%" PRId64 ", %" PRId64
+		    "] measured [%" PRId64 ", %" PRId64 "]",
+		    expected_lo, expected_hi, actual_lo, actual_hi);
+
+	/*
+	 * Direct pvclock verification: read each destination pvclock page
+	 * (as written for the guest) and verify that computing kvmclock
+	 * from the source pvti and the destination pvti at the same
+	 * instant gives the same result, for every vCPU.
+	 *
+	 * Get one atomic {host_tsc, kvmclock} pair, derive each vCPU's
+	 * guest TSC at that instant, then compute kvmclock from both
+	 * pvclock structs. The source pvti evaluates at the *migrated*
+	 * guest TSC, i.e. shifted by the CLOCK_REALTIME imprecision that
+	 * was baked into the offsets — which is exactly what "the clock
+	 * follows the TSC" means.
+	 */
+	struct kvm_clock_data clock_now = {};
+	vm_get_clock(vm, &clock_now);
+	pr_info("  KVM_GET_CLOCK:  %" PRIu64 " ns\n", (u64)clock_now.clock);
+
+	u64 host_tsc_now = clock_now.host_tsc;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct pvclock_vcpu_time_info *pvti_page =
+			addr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());
+		u64 guest_tsc_now = host_to_guest_tsc(&scale_dst, ofs_dst[i],
+						      host_tsc_now);
+		u64 clk_from_src = pvclock_read_cycles(&pvti_src[i],
+						       guest_tsc_now);
+		u64 clk_from_dst = pvclock_read_cycles(pvti_page,
+						       guest_tsc_now);
+		s64 pvclock_delta = (s64)(clk_from_src - clk_from_dst);
+
+		pr_info("  vCPU%d pvclock direct: src=%" PRIu64 " dst=%" PRIu64
+			" delta=%" PRId64 " ns\n", i, clk_from_src,
+			clk_from_dst, pvclock_delta);
+
+		TEST_ASSERT(pvclock_delta >= -2 && pvclock_delta <= 2,
+			    "vCPU%d pvclock src vs dst disagree by %" PRId64 " ns",
+			    i, pvclock_delta);
+	}
+
+	/*
+	 * Tight ABA: compare pvclock_read() directly (no ioctl) against
+	 * CLOCK_MONOTONIC_RAW. The spread should be much smaller since
+	 * there's no syscall between the two clock_gettime calls — just
+	 * rdtsc + userspace mul/shift.
+	 */
+	struct pvclock_vcpu_time_info *pvti0 = addr_gpa2hva(vm, KVMCLOCK_GPA);
+	u64 tight_mono_lo = 0, tight_mono_hi = 0, tight_kvm = 0;
+	u64 tight_best_spread = UINT64_MAX;
+	for (i = 0; i < 3; i++) {
+		struct timespec ts1, ts2;
+		u64 m1, m2, tsc, clk;
+
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
+		tsc = rdtsc();
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
+
+		m1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;
+		m2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;
+
+		/* Scale host TSC to vCPU0's guest TSC */
+		tsc = host_to_guest_tsc(&scale_dst, ofs_dst[0], tsc);
+
+		clk = pvclock_read_cycles(pvti0, tsc);
+
+		if (m2 - m1 < tight_best_spread) {
+			tight_best_spread = m2 - m1;
+			tight_mono_lo = m1;
+			tight_mono_hi = m2;
+			tight_kvm = clk;
+		}
+	}
+	pr_info("  Tight ABA spread: %" PRIu64 " ns (best of 3)\n", tight_best_spread);
+
+	s64 tight_expected_lo = delta_before_lo + tsc_ofs_delta_ns;
+	s64 tight_expected_hi = delta_before_hi + tsc_ofs_delta_ns;
+	s64 tight_actual_lo = (s64)(tight_kvm - tight_mono_hi);
+	s64 tight_actual_hi = (s64)(tight_kvm - tight_mono_lo);
+	s64 tight_actual_mid = ((tight_actual_lo + tight_actual_hi) / 2) - delta_before;
+	s64 tight_actual_err = (s64)(tight_mono_hi - tight_mono_lo) / 2;
+
+	pr_info("  Tight kvmclock-mono shift: expected %" PRId64
+		" ns (±%" PRId64 "), measured %" PRId64 " ns (±%" PRId64 ")\n",
+		expected_mid, expected_err, tight_actual_mid, tight_actual_err);
+
+	TEST_ASSERT(tight_expected_hi >= tight_actual_lo &&
+		    tight_expected_lo <= tight_actual_hi,
+		    "Tight ABA ranges don't overlap");
+
+	kvm_vm_free(vm);
+	pr_info("PASS: kvmclock offset matches TSC delta from CLOCK_REALTIME"
+		" (%" PRId64 " ns) within ABA bounds\n", tsc_ofs_delta_ns);
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/pvclock_test.c b/tools/testing/selftests/kvm/x86/pvclock_test.c
new file mode 100644
index 00000000000000..1599fb0c727536
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/pvclock_test.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright © Amazon.com, Inc. or its affiliates.
+ *
+ * Tests for pvclock API
+ * KVM_SET_CLOCK_GUEST/KVM_GET_CLOCK_GUEST
+ */
+#include <getopt.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+/*
+ * Reproduce the pvclock calculation the guest uses to convert TSC to
+ * nanoseconds. This must match the kernel's __pvclock_read_cycles().
+ */
+static inline u64 pvclock_scale_delta(u64 delta, u32 mul,
+					   s8 shift)
+{
+	if (shift < 0)
+		delta >>= -shift;
+	else
+		delta <<= shift;
+	return ((__uint128_t)delta * mul) >> 32;
+}
+
+static inline u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,
+					   u64 tsc)
+{
+	u64 delta = tsc - src->tsc_timestamp;
+
+	return src->system_time + pvclock_scale_delta(delta,
+						      src->tsc_to_system_mul,
+						      src->tsc_shift);
+}
+
+static inline void pvti_snapshot(struct pvclock_vcpu_time_info *dst,
+				 volatile struct pvclock_vcpu_time_info *src)
+{
+	u32 version;
+
+	do {
+		version = src->version;
+		__asm__ __volatile__("" ::: "memory");
+		*dst = *src;
+		__asm__ __volatile__("" ::: "memory");
+	} while ((src->version & 1) || src->version != version);
+}
+
+enum {
+	STAGE_FIRST_BOOT,
+	STAGE_UNCORRECTED,
+	STAGE_CORRECTED
+};
+
+#define KVMCLOCK_GPA	0xc0000000ull
+#define KVMCLOCK_SIZE	sizeof(struct pvclock_vcpu_time_info)
+
+static void trigger_pvti_update(void)
+{
+	/*
+	 * Toggle between KVM's old and new system time methods to coerce KVM
+	 * into updating the fields in the PV time info struct.
+	 */
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+}
+
+static void guest_code(void)
+{
+	struct pvclock_vcpu_time_info *pvti =
+		(void *)(unsigned long)KVMCLOCK_GPA;
+	struct pvclock_vcpu_time_info pvti_boot;
+	struct pvclock_vcpu_time_info pvti_uncorrected;
+	struct pvclock_vcpu_time_info pvti_corrected;
+	u64 tsc_guest;
+	u64 clk_boot, clk_uncorrected, clk_corrected;
+	s64 delta_corrected;
+
+	/* Set up kvmclock and snapshot the initial pvclock parameters. */
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	pvti_snapshot(&pvti_boot, pvti);
+	GUEST_SYNC(STAGE_FIRST_BOOT);
+
+	/*
+	 * Trigger an update of the PVTI. Calculating the KVM clock using this
+	 * updated structure will show a delta from the original.
+	 */
+	trigger_pvti_update();
+	pvti_snapshot(&pvti_uncorrected, pvti);
+	GUEST_SYNC(STAGE_UNCORRECTED);
+
+	/*
+	 * Snapshot the corrected time (the host does KVM_SET_CLOCK_GUEST when
+	 * handling STAGE_UNCORRECTED).
+	 */
+	pvti_snapshot(&pvti_corrected, pvti);
+
+	/*
+	 * Sample the TSC at a single point in time, then calculate the
+	 * effective KVM clock using the PVTI from each stage. Verify that the
+	 * corrected clock matches the boot clock to within ±2ns.
+	 */
+	tsc_guest = rdtsc();
+
+	clk_boot = pvclock_read_cycles(&pvti_boot, tsc_guest);
+	clk_uncorrected = pvclock_read_cycles(&pvti_uncorrected, tsc_guest);
+	clk_corrected = pvclock_read_cycles(&pvti_corrected, tsc_guest);
+
+	/*
+	 * The host stepped the KVM clock forward by 10 seconds at
+	 * STAGE_FIRST_BOOT, so the uncorrected clock must diverge; without
+	 * this, a no-op KVM_SET_CLOCK_GUEST would pass the test below.
+	 */
+	__GUEST_ASSERT((s64)(clk_uncorrected - clk_boot) > NSEC_PER_SEC,
+		       "uncorrected clock did not diverge (boot=%lu uncorrected=%lu)",
+		       clk_boot, clk_uncorrected);
+
+	delta_corrected = clk_boot - clk_corrected;
+
+	__GUEST_ASSERT(delta_corrected >= -2 && delta_corrected <= 2,
+		       "corrected delta %ld out of range (boot=%lu uncorrected=%lu corrected=%lu)",
+		       delta_corrected, clk_boot, clk_uncorrected, clk_corrected);
+
+	GUEST_SYNC(STAGE_CORRECTED);
+}
+
+static void run_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
+		     unsigned int sleep_sec)
+{
+	struct pvclock_vcpu_time_info pvti_before;
+	struct kvm_clock_data clock_step;
+	struct ucall uc;
+
+	for (;;) {
+		vcpu_run(vcpu);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+		switch (get_ucall(vcpu, &uc)) {
+		case UCALL_ABORT:
+			REPORT_GUEST_ASSERT(uc);
+			break;
+		case UCALL_SYNC:
+			break;
+		default:
+			TEST_FAIL("Unexpected ucall");
+		}
+
+		switch (uc.args[1]) {
+		case STAGE_FIRST_BOOT:
+			/* Save the pvclock parameters before the update. */
+			vcpu_get_clock_guest(vcpu, &pvti_before);
+
+			/* Sleep to let the clocks diverge. */
+			sleep(sleep_sec);
+
+			/*
+			 * Step the KVM clock forward 10 seconds so that the
+			 * divergence the correction must eliminate is
+			 * deterministic, not at the mercy of accumulated
+			 * drift during the sleep.
+			 */
+			vm_get_clock(vm, &clock_step);
+			clock_step.clock += 10ull * NSEC_PER_SEC;
+			clock_step.flags = 0;
+			vm_set_clock(vm, &clock_step);
+			break;
+
+		case STAGE_UNCORRECTED:
+			/* Restore the original pvclock parameters. */
+			vcpu_set_clock_guest(vcpu, &pvti_before);
+			break;
+
+		case STAGE_CORRECTED:
+			/* Guest verified the delta in-guest. */
+			return;
+
+		default:
+			TEST_FAIL("Unknown stage %lu", uc.args[1]);
+		}
+	}
+}
+
+static void configure_pvclock(struct kvm_vm *vm)
+{
+	unsigned int nr_pages;
+
+	nr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, nr_pages, 0);
+	virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, nr_pages);
+}
+
+static void run_at_frequency(u64 tsc_khz, unsigned int sleep_sec)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz);
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	configure_pvclock(vm);
+	vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)tsc_khz);
+	run_test(vm, vcpu, sleep_sec);
+	kvm_vm_free(vm);
+}
+
+static void test_tsc_stable_bit(void);
+static void test_clock_guest_with_offsets(void);
+static void test_legacy_msr(void);
+static void run_vcpu_once(struct kvm_vcpu *vcpu);
+
+static void usage(const char *name)
+{
+	printf("Usage: %s [options]\n"
+	       "  -s, --sleep SEC     sleep duration between snapshots (default: 2)\n"
+	       "  -h, --help          show this help\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+	static const struct option long_opts[] = {
+		{ "sleep", required_argument, NULL, 's' },
+		{ "help",  no_argument,       NULL, 'h' },
+		{ NULL,    0,                  NULL,  0  },
+	};
+	unsigned int sleep_sec = 2;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 host_khz;
+	u64 freq;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "s:h", long_opts, NULL)) != -1) {
+		switch (opt) {
+		case 's':
+			sleep_sec = atoi_non_negative("sleep", optarg);
+			break;
+		case 'h':
+		default:
+			usage(argv[0]);
+			return opt == 'h' ? 0 : 1;
+		}
+	}
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));
+
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	configure_pvclock(vm);
+
+	/* First run at native frequency (no scaling). */
+	run_test(vm, vcpu, sleep_sec);
+
+	/*
+	 * Then enumerate a range of TSC frequencies crossing the 32-bit
+	 * boundary, to exercise the scaling path at various ratios.
+	 */
+	host_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	kvm_vm_free(vm);
+
+	for (freq = 1000000; freq <= 5000000; freq += 500000) {
+		if (freq == host_khz)
+			continue;
+		run_at_frequency(freq, sleep_sec);
+	}
+
+	test_tsc_stable_bit();
+	test_clock_guest_with_offsets();
+	test_legacy_msr();
+
+	return 0;
+}
+
+static void guest_code_legacy_msr(void)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	GUEST_SYNC(0);
+	/* Re-request the time, as SUSE's 2.6.16 kernel would. */
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	GUEST_SYNC(1);
+}
+
+/*
+ * A guest using the legacy MSR_KVM_SYSTEM_TIME must no longer lose the
+ * master clock, and rewriting the MSR must slide the reference point
+ * forward so the pvclock's tsc_timestamp is recent — that freshness is
+ * what SUSE's 2.6.16 kernel demands instead of tolerating a fixed
+ * reference point.
+ */
+static void test_legacy_msr(void)
+{
+	struct pvclock_vcpu_time_info *pvti;
+	struct kvm_clock_data clock;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 tsc_now, age_limit;
+
+	pr_info("Testing the legacy MSR_KVM_SYSTEM_TIME\n");
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code_legacy_msr);
+	configure_pvclock(vm);
+
+	run_vcpu_once(vcpu);
+	vm_ioctl(vm, KVM_GET_CLOCK, &clock);
+	TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE,
+		    "Legacy MSR_KVM_SYSTEM_TIME should not disable the master clock");
+
+	/* Age the master clock reference point, then re-request. */
+	usleep(300 * 1000);
+	run_vcpu_once(vcpu);
+
+	pvti = addr_gpa2hva(vm, KVMCLOCK_GPA);
+	tsc_now = vcpu_get_msr(vcpu, MSR_IA32_TSC);
+
+	/*
+	 * The rewrite slid the reference point, so the pvclock must be
+	 * anchored after the 300ms sleep: allow 250ms of slack for the
+	 * ioctls around it. SUSE's real threshold was 1/5 jiffie, but
+	 * asserting that tightly would flake on a loaded host.
+	 */
+	age_limit = (u64)__vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL) * 250;
+	TEST_ASSERT(tsc_now - pvti->tsc_timestamp < age_limit,
+		    "pvclock tsc_timestamp should be fresh after legacy MSR rewrite (age %llu cycles, limit %llu)",
+		    (unsigned long long)(tsc_now - pvti->tsc_timestamp),
+		    (unsigned long long)age_limit);
+
+	vm_ioctl(vm, KVM_GET_CLOCK, &clock);
+	TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE,
+		    "Master clock should survive a legacy MSR rewrite");
+
+	kvm_vm_free(vm);
+}
+
+static volatile u32 vcpu_counter;
+static void guest_code_stable_bit(void)
+{
+	u32 idx = __atomic_fetch_add(&vcpu_counter, 1, __ATOMIC_SEQ_CST);
+	u64 gpa = KVMCLOCK_GPA + idx * KVMCLOCK_SIZE;
+
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, gpa | KVM_MSR_ENABLED);
+	GUEST_SYNC(0);
+	GUEST_SYNC(0);
+	GUEST_SYNC(0);
+}
+
+static void run_vcpu_once(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_SYNC:
+		break;
+	default:
+		TEST_FAIL("Unexpected ucall");
+	}
+}
+
+static void test_tsc_stable_bit(void)
+{
+	struct pvclock_vcpu_time_info pvti;
+	struct kvm_vcpu *vcpus[2];
+	struct kvm_vm *vm;
+	int ret;
+
+	pr_info("Testing PVCLOCK_TSC_STABLE_BIT with matched/unmatched TSCs\n");
+
+	vm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);
+	configure_pvclock(vm);
+
+	/*
+	 * Case 1: All TSCs matched (same frequency and offset).
+	 * Master clock should be active, PVCLOCK_TSC_STABLE_BIT set.
+	 */
+	run_vcpu_once(vcpus[0]);
+
+	vcpu_get_clock_guest(vcpus[0], &pvti);
+	TEST_ASSERT(pvti.flags & PVCLOCK_TSC_STABLE_BIT,
+		    "PVCLOCK_TSC_STABLE_BIT should be set with matched TSCs");
+
+	/*
+	 * Case 2: Different TSC offset, same frequency.
+	 * Master clock should still be active (frequency matches), but
+	 * PVCLOCK_TSC_STABLE_BIT should be cleared (offsets differ).
+	 */
+	if (__vcpu_has_device_attr(vcpus[1], KVM_VCPU_TSC_CTRL,
+				   KVM_VCPU_TSC_OFFSET)) {
+		pr_info("  Skipping offset test (KVM_VCPU_TSC_OFFSET not supported)\n");
+		goto case_freq;
+	}
+	vcpu_set_tsc_offset(vcpus[1], 12345678);
+	run_vcpu_once(vcpus[1]);
+	run_vcpu_once(vcpus[0]);
+
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti);
+	if (ret) {
+		/*
+		 * Master clock disabled by offset mismatch — old kernel.
+		 * -ENODATA is the only legitimate reason to skip; anything
+		 * else is a regression, not an old kernel.
+		 */
+		TEST_ASSERT(errno == ENODATA,
+			    "GET_CLOCK_GUEST failed with unexpected errno %d", errno);
+		pr_info("  Skipping offset test (master clock requires matched offsets)\n");
+		goto case_freq;
+	}
+	TEST_ASSERT(!(pvti.flags & PVCLOCK_TSC_STABLE_BIT),
+		    "PVCLOCK_TSC_STABLE_BIT should be clear with offset-mismatched TSCs");
+
+case_freq:
+	/*
+	 * Case 3: Different TSC frequency.
+	 * Master clock should be disabled entirely.
+	 */
+	vcpu_ioctl(vcpus[1], KVM_SET_TSC_KHZ,
+		   (void *)(unsigned long)(__vcpu_ioctl(vcpus[1], KVM_GET_TSC_KHZ, NULL) / 2));
+	/* Write TSC to trigger kvm_synchronize_tsc / kvm_track_tsc_matching */
+	vcpu_set_msr(vcpus[1], MSR_IA32_TSC, 0);
+	run_vcpu_once(vcpus[1]);
+
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti);
+	TEST_ASSERT(ret && errno == ENODATA,
+		    "GET_CLOCK_GUEST should fail with frequency-mismatched TSCs, got %d (errno %d)",
+		    ret, errno);
+
+	kvm_vm_free(vm);
+}
+
+static void test_clock_guest_with_offsets(void)
+{
+	struct pvclock_vcpu_time_info pvti0, pvti1, pvti1_after;
+	struct kvm_vcpu *vcpus[2];
+	struct kvm_vm *vm;
+	s64 delta;
+	int ret;
+
+	pr_info("Testing KVM_[GS]ET_CLOCK_GUEST with different TSC offsets\n");
+
+	vm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);
+	configure_pvclock(vm);
+
+	/* Set different TSC offsets on the two vCPUs */
+	vcpu_set_tsc_offset(vcpus[0], 0);
+	vcpu_set_tsc_offset(vcpus[1], 1000000000ull);
+
+	/* Run both to establish kvmclock */
+	run_vcpu_once(vcpus[0]);
+	run_vcpu_once(vcpus[1]);
+
+	/* GET_CLOCK_GUEST on both — should succeed (master clock active) */
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti0);
+	if (ret) {
+		TEST_ASSERT(errno == ENODATA,
+			    "GET_CLOCK_GUEST failed with unexpected errno %d", errno);
+		pr_info("  Skipping (master clock requires matched offsets on this kernel)\n");
+		kvm_vm_free(vm);
+		return;
+	}
+	vcpu_get_clock_guest(vcpus[1], &pvti1);
+
+	/* The tsc_timestamps should differ (different offsets) */
+	TEST_ASSERT(pvti0.tsc_timestamp != pvti1.tsc_timestamp,
+		    "tsc_timestamps should differ with different offsets");
+
+	/* Sleep to let time elapse, then restore vcpu0's clock */
+	sleep(1);
+	vcpu_set_clock_guest(vcpus[0], &pvti0);
+
+	/* Run vcpu0 to process the clock update */
+	run_vcpu_once(vcpus[0]);
+
+	/*
+	 * After SET on vcpu0, verify the correction worked by getting
+	 * the clock on vcpu0 again. The mul/shift should be the same,
+	 * and computing kvmclock at the same TSC should give the same
+	 * result as the original (within ±2ns).
+	 */
+	{
+		struct pvclock_vcpu_time_info pvti0_after;
+		u64 tsc_now, clk_from_old, clk_from_new;
+
+		vcpu_get_clock_guest(vcpus[0], &pvti0_after);
+
+		TEST_ASSERT(pvti0_after.tsc_to_system_mul == pvti0.tsc_to_system_mul &&
+			    pvti0_after.tsc_shift == pvti0.tsc_shift,
+			    "mul/shift changed across KVM_SET_CLOCK_GUEST");
+
+		tsc_now = pvti0_after.tsc_timestamp;
+		clk_from_old = pvclock_read_cycles(&pvti0, tsc_now);
+		clk_from_new = pvclock_read_cycles(&pvti0_after, tsc_now);
+
+		delta = (s64)clk_from_new - (s64)clk_from_old;
+		TEST_ASSERT(delta >= -2 && delta <= 2,
+			    "clock correction delta should be <=2ns, got %ld ns",
+			    delta);
+	}
+
+	/*
+	 * Also verify that vcpu1's clock is still accessible (master
+	 * clock still active with different offsets).
+	 */
+	vcpu_get_clock_guest(vcpus[1], &pvti1_after);
+
+	kvm_vm_free(vm);
+}
diff --git a/tools/testing/selftests/kvm/x86/tsc_user_set_test.c b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c
new file mode 100644
index 00000000000000..a74eb78a975b2f
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that the first userspace write to MSR_IA32_TSC takes effect
+ * precisely, and is not subjected to the 1-second "slop" heuristic
+ * which is only supposed to apply between successive *userspace*
+ * writes (kvm->arch.user_set_tsc).
+ *
+ * The kernel synchronizes the TSC internally when a vCPU is created
+ * (and when its frequency is set). If any of those kernel-internal
+ * paths incorrectly sets user_set_tsc, then the first genuine write
+ * from userspace which happens to fall within 1 second of virtual
+ * cycle time of the kernel's default generation is "corrected" to
+ * match that generation instead of being honoured exactly. That
+ * breaks the restore of a guest which has genuinely been running
+ * for less than one second.
+ *
+ * Simulate exactly that: create a vCPU (kernel establishes a default
+ * TSC generation starting near zero), then perform the first
+ * host-initiated write with a value corresponding to ~500ms of guest
+ * runtime. If the slop heuristic fires, the written value is snapped
+ * back to the kernel's generation (near zero) and the TSC reads back
+ * hundreds of milliseconds low. Repeat with an explicit
+ * KVM_SET_TSC_KHZ on the never-run vCPU before the write: that is
+ * another kernel-internal synchronization which must not arm the
+ * heuristic (nor open a generation that swallows the first write).
+ */
+#include "kvm_util.h"
+#include "processor.h"
+
+/*
+ * Returns false when the attempt was inconclusive: a snapped-back value
+ * tracks time since vCPU creation, so if creation-to-write time gets
+ * anywhere near the written 500ms, a buggy kernel's value could land
+ * inside the assertions' tolerance and pass. The caller retries.
+ */
+static bool test_first_write(bool set_freq)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 freq_khz, t_write, t_read, slack_cycles, mono_ns, create_ns, read_ns;
+	struct timespec ts;
+	int r;
+
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	create_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+
+	if (set_freq) {
+		/*
+		 * Halve the frequency so this is a real change, exercising
+		 * the frequency resynchronization path rather than the
+		 * unchanged-frequency no-op.
+		 */
+		r = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+		TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ failed");
+		vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ,
+			   (void *)(unsigned long)(r / 2));
+	}
+
+	r = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ failed");
+	freq_khz = r;
+
+	/*
+	 * The first user write: a guest TSC corresponding to 500ms of
+	 * runtime. This is within 1s (of virtual cycle time) of the
+	 * kernel's default generation, so it is exactly the case that
+	 * the slop heuristic would destroy if it were (incorrectly)
+	 * armed by the kernel's own internal TSC synchronization.
+	 */
+	t_write = freq_khz * 500ULL;		/* khz * ms = cycles */
+
+	/*
+	 * Measure only the write..read window (a window measured from
+	 * before creation would also bound a snapped-back value), and
+	 * insist the write lands well before 500ms of creation time so
+	 * a snapped-back value cannot sit inside the tolerance.
+	 */
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	mono_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	if (mono_ns - create_ns > 250000000ULL) {
+		pr_info("  creation took %lu ms, retrying for a conclusive run\n",
+			(mono_ns - create_ns) / 1000000);
+		kvm_vm_free(vm);
+		return false;
+	}
+
+	vcpu_set_msr(vcpu, MSR_IA32_TSC, t_write);
+
+	t_read = vcpu_get_msr(vcpu, MSR_IA32_TSC);
+
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	read_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	/*
+	 * Bound the whole creation..read interval too: a snapped-back
+	 * value tracks it, so letting it approach the written 500ms
+	 * (via a stall between the two MSR ioctls, which the slack
+	 * below would otherwise absorb) would let a buggy kernel pass.
+	 */
+	if (read_ns - create_ns > 400000000ULL) {
+		pr_info("  creation..read took %lu ms, retrying for a conclusive run\n",
+			(read_ns - create_ns) / 1000000);
+		kvm_vm_free(vm);
+		return false;
+	}
+
+	mono_ns = read_ns - mono_ns;
+
+	/*
+	 * The TSC advances between the write and the read; bound the
+	 * difference by the measured elapsed time around the two ioctls
+	 * plus 10ms of slop, so a descheduled test cannot flake. If the
+	 * write was snapped to the kernel's default generation, the
+	 * value read back is ~500ms low (i.e. below t_write), which is
+	 * unambiguous.
+	 */
+	slack_cycles = freq_khz * (mono_ns / 1000000ULL + 10);
+
+	TEST_ASSERT(t_read >= t_write,
+		    "TSC went backwards from explicit write: wrote %lu, read %lu"
+		    " (first userspace write was subjected to 1-second slop?)",
+		    t_write, t_read);
+	TEST_ASSERT(t_read - t_write < slack_cycles,
+		    "TSC read back too far from written value: wrote %lu, read %lu",
+		    t_write, t_read);
+
+	kvm_vm_free(vm);
+	return true;
+}
+
+static void run_first_write(bool set_freq)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		if (test_first_write(set_freq))
+			return;
+
+	TEST_FAIL("vCPU creation repeatedly too slow for a conclusive run");
+}
+
+int main(void)
+{
+	run_first_write(false);
+
+	if (kvm_has_cap(KVM_CAP_TSC_CONTROL))
+		run_first_write(true);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c
new file mode 100644
index 00000000000000..70d3d38966f239
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that userspace can correctly populate Xen and generic CPUID
+ * timing leaves using KVM_GET_TSC_KHZ and KVM_VCPU_TSC_SCALE.
+ *
+ * This validates that the removal of KVM's runtime Xen CPUID modification
+ * doesn't break guests, because userspace has all the information needed.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+
+#define XEN_CPUID_BASE		0x40000100
+#define XEN_CPUID_LEAF(n)	(XEN_CPUID_BASE + (n))
+#define GENERIC_TIMING_LEAF	0x40000010
+
+/*
+ * Sentinel in Xen leaf 3 sub-leaf 2 EAX (where the removed runtime
+ * update used to write the vCPU's tsc_khz): it must survive untouched.
+ */
+#define XEN_SENTINEL		0xdeadbeef
+
+/* Values set by host, verified by guest */
+static u32 expected_tsc_khz;
+static u32 expected_bus_khz;
+static u32 expected_tsc_mul;
+static s8   expected_tsc_shift;
+static u64 host_khz;
+static bool xen_enabled;
+
+static void guest_code(void)
+{
+	u32 eax, ebx, ecx, edx;
+
+	/* Check generic timing leaf 0x40000010 */
+	__cpuid(GENERIC_TIMING_LEAF, 0, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(eax, expected_tsc_khz);
+	GUEST_ASSERT_EQ(ebx, expected_bus_khz);
+
+	/* Check Xen leaf 3, sub-leaf 0: ECX = guest TSC frequency */
+	__cpuid(XEN_CPUID_LEAF(3), 0, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(ecx, expected_tsc_khz);
+
+	/* Check Xen leaf 3, sub-leaf 1: ECX = mul, EDX = shift */
+	__cpuid(XEN_CPUID_LEAF(3), 1, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(ecx, expected_tsc_mul);
+	GUEST_ASSERT_EQ((s8)edx, expected_tsc_shift);
+
+	if (xen_enabled) {
+		/*
+		 * With the Xen signature present and Xen enabled, verify the
+		 * sentinel survives: KVM's removed runtime CPUID update used
+		 * to clobber this sub-leaf for exactly this configuration.
+		 */
+		__cpuid(XEN_CPUID_LEAF(3), 2, &eax, &ebx, &ecx, &edx);
+		GUEST_ASSERT_EQ(eax, XEN_SENTINEL);
+	}
+
+	GUEST_SYNC(0);
+}
+
+static void add_cpuid_entry(struct kvm_vcpu *vcpu, u32 function,
+			    u32 index, u32 eax, u32 ebx,
+			    u32 ecx, u32 edx)
+{
+	struct kvm_cpuid2 *cpuid = vcpu->cpuid;
+	struct kvm_cpuid_entry2 *entry;
+	int n = cpuid->nent;
+
+	cpuid = realloc(vcpu->cpuid,
+			sizeof(*cpuid) + (n + 1) * sizeof(*entry));
+	TEST_ASSERT(cpuid, "Failed to grow vCPU CPUID array");
+	vcpu->cpuid = cpuid;
+	cpuid->nent = n + 1;
+
+	entry = &cpuid->entries[n];
+	memset(entry, 0, sizeof(*entry));
+	entry->function = function;
+	entry->index = index;
+	entry->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+	entry->eax = eax;
+	entry->ebx = ebx;
+	entry->ecx = ecx;
+	entry->edx = edx;
+}
+
+/*
+ * Compute pvclock mul/shift from frequency, matching kvm_get_time_scale().
+ */
+static void compute_tsc_mul_shift(u64 tsc_hz, u32 *mul, s8 *shift)
+{
+	u64 scaled = 1000000000ULL;
+	u64 base = tsc_hz;
+	s32 s = 0;
+	u32 base32;
+
+	while (base > scaled * 2 || base >> 32) {
+		base >>= 1;
+		s--;
+	}
+	base32 = (u32)base;
+	while (base32 <= scaled || scaled >> 32) {
+		if (scaled >> 32 || base32 & (1U << 31))
+			scaled >>= 1;
+		else
+			base32 <<= 1;
+		s++;
+	}
+	*mul = (u32)((scaled << 32) / base32);
+	*shift = (s8)s;
+}
+
+static void run_test(u64 tsc_khz)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	u32 effective_tsc_khz, effective_bus_khz;
+	int bus_cycle_ns, ret;
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	if (tsc_khz) {
+		pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz);
+		vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)tsc_khz);
+	} else {
+		pr_info("Testing at native TSC frequency\n");
+	}
+
+	ret = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	TEST_ASSERT(ret > 0, "KVM_GET_TSC_KHZ failed: %d", ret);
+	effective_tsc_khz = ret;
+	bus_cycle_ns = vm_check_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS);
+	effective_bus_khz = bus_cycle_ns > 0 ? 1000000 / bus_cycle_ns : 1000000;
+
+	pr_info("  Effective TSC: %u kHz, Bus: %u kHz\n", effective_tsc_khz, effective_bus_khz);
+
+	/* Also exercise KVM_VCPU_TSC_SCALE if available */
+	if (!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
+				    KVM_VCPU_TSC_SCALE)) {
+		struct kvm_vcpu_tsc_scale scale;
+
+		vcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale);
+		pr_info("  TSC scale: ratio=%llu frac_bits=%llu\n",
+			scale.tsc_ratio, scale.tsc_frac_bits);
+
+		/*
+		 * A requested frequency within tsc_tolerance_ppm of the
+		 * host's does not engage hardware scaling: the effective
+		 * frequency is the requested one but the ratio stays 1.0,
+		 * so the ratio cross-check cannot hold. Skip only that
+		 * check — the CPUID leaf population and guest verification
+		 * below are about the effective frequency and remain valid.
+		 */
+		if (tsc_khz &&
+		    scale.tsc_ratio == (1ULL << scale.tsc_frac_bits)) {
+			pr_info("  Requested frequency within host tolerance; scaling not engaged, skipping ratio cross-check\n");
+		} else if (tsc_khz) {
+			/*
+			 * Verify: applying the ratio to the host TSC frequency
+			 * should give approximately the effective frequency.
+			 */
+			u64 computed = ((__uint128_t)host_khz * scale.tsc_ratio) >> scale.tsc_frac_bits;
+			s64 diff = (s64)computed - (s64)effective_tsc_khz;
+
+			TEST_ASSERT(diff >= -1 && diff <= 1,
+				    "TSC_SCALE ratio mismatch: computed %lu vs effective %u (diff %ld)",
+				    computed, effective_tsc_khz, diff);
+		}
+	}
+
+	compute_tsc_mul_shift((u64)effective_tsc_khz * 1000,
+			      &expected_tsc_mul, &expected_tsc_shift);
+
+	expected_tsc_khz = effective_tsc_khz;
+	expected_bus_khz = effective_bus_khz;
+
+	sync_global_to_guest(vm, expected_tsc_khz);
+	sync_global_to_guest(vm, expected_bus_khz);
+	sync_global_to_guest(vm, expected_tsc_mul);
+	sync_global_to_guest(vm, expected_tsc_shift);
+
+	/* Populate CPUID leaves as a VMM would */
+	add_cpuid_entry(vcpu, GENERIC_TIMING_LEAF, 0,
+			effective_tsc_khz, effective_bus_khz, 0, 0);
+	add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 0,
+			0, 0, effective_tsc_khz, 0);
+	add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 1,
+			0, 0, expected_tsc_mul,
+			(u32)(s32)expected_tsc_shift);
+
+	/*
+	 * Where possible, make this a real Xen guest: install the Xen
+	 * signature leaf and enable the Xen hypercall MSR, which is the
+	 * configuration in which KVM's removed runtime CPUID update used
+	 * to fire, and plant a sentinel where it used to write.
+	 */
+	xen_enabled = kvm_has_cap(KVM_CAP_XEN_HVM);
+	if (xen_enabled) {
+		struct kvm_xen_hvm_config cfg = {
+			.msr = 0x40000200,
+		};
+
+		vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &cfg);
+		add_cpuid_entry(vcpu, XEN_CPUID_BASE, 0, XEN_CPUID_LEAF(4),
+				0x566e6558 /* "XenV" */,
+				0x65584d4d /* "MMXe" */,
+				0x4d4d566e /* "nVMM" */);
+		add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 2,
+				XEN_SENTINEL, 0, 0, 0);
+	}
+	sync_global_to_guest(vm, xen_enabled);
+
+	vcpu_set_cpuid(vcpu);
+
+	pr_info("  pvclock mul=%u shift=%d\n", expected_tsc_mul, expected_tsc_shift);
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_SYNC:
+		break;
+	default:
+		TEST_FAIL("Unexpected ucall");
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(void)
+{
+	u64 freq;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	bool have_tsc_scale;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	have_tsc_scale = !__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
+						 KVM_VCPU_TSC_SCALE);
+	host_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	kvm_vm_free(vm);
+
+	/* Native frequency */
+	run_test(0);
+
+	/* Scaled frequencies, when hardware TSC scaling is available */
+	if (have_tsc_scale) {
+		for (freq = 1000000; freq <= 4000000; freq += 1000000) {
+			if (freq == host_khz)
+				continue;
+			run_test(freq);
+		}
+	} else {
+		pr_info("Skipping scaled frequencies (no TSC scaling)\n");
+	}
+
+	pr_info("PASS: All CPUID timing leaf tests passed\n");
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_migration_test.c b/tools/testing/selftests/kvm/x86/xen_migration_test.c
new file mode 100644
index 00000000000000..564781db3da286
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/xen_migration_test.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test Xen runstate (steal time) preservation across simulated migration.
+ *
+ * Verifies that the kernel correctly accounts the migration gap as
+ * steal time (runnable) when runstate data is saved and restored
+ * precisely, but real time elapses during the migration.
+ *
+ * The key insight: userspace saves the runstate with state=RUNSTATE_runnable
+ * (the vCPU is not running during migration). On restore, the kernel sees
+ * that kvmclock has advanced past state_entry_time, and accounts the
+ * difference as time spent in the runnable state.
+ */
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+#define SHINFO_GPA	0xc0000000ULL
+#define RUNSTATE_GPA	(SHINFO_GPA + 0x1000)
+
+#define RUNSTATE_running  0
+#define RUNSTATE_runnable 1
+#define RUNSTATE_blocked  2
+#define RUNSTATE_offline  3
+
+/*
+ * The 64-bit (long mode) layout: 'state' is followed by 4 bytes of
+ * padding so state_entry_time is naturally aligned. The VM is placed
+ * in long mode explicitly below; without that, KVM would latch 32-bit
+ * mode (no hypercall-page write ever happens here to latch it from
+ * EFER) and write the packed compat layout instead.
+ */
+struct vcpu_runstate_info {
+	u32 state;
+	u64 state_entry_time;
+	u64 time[4];
+};
+
+static void guest_code(void)
+{
+	volatile struct vcpu_runstate_info *rs =
+		(void *)(unsigned long)RUNSTATE_GPA;
+
+	/* Report runstate times — no need to enable kvmclock MSR,
+	 * the kernel writes runstate using its internal kvmclock. */
+	GUEST_SYNC_ARGS(0, rs->time[RUNSTATE_runnable],
+			rs->time[RUNSTATE_running], 0, 0);
+}
+
+static struct kvm_vm *create_xen_vm(struct kvm_vcpu **vcpu)
+{
+	struct kvm_vm *vm;
+	int xen_caps;
+
+	vm = vm_create_with_one_vcpu(vcpu, guest_code);
+
+	xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM);
+	TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO);
+	TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE);
+
+	/* Map pages */
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    SHINFO_GPA, 1, 2, 0);
+	virt_map(vm, SHINFO_GPA, SHINFO_GPA, 2);
+
+	/* Enable Xen HVM with MSR interception (enables runstate tracking) */
+	struct kvm_xen_hvm_config cfg = {
+		.flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
+		.msr = 0x40000000,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &cfg);
+
+	/* The guest runs in long mode; make the runstate layout match. */
+	struct kvm_xen_hvm_attr lm = {
+		.type = KVM_XEN_ATTR_TYPE_LONG_MODE,
+		.u.long_mode = 1,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
+
+	/* Set shared_info */
+	struct kvm_xen_hvm_attr ha = {
+		.type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
+		.u.shared_info.gfn = SHINFO_GPA >> 12,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha);
+
+	/* Set runstate address */
+	struct kvm_xen_vcpu_attr rs_addr = {
+		.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
+		.u.gpa = RUNSTATE_GPA,
+	};
+	vcpu_ioctl(*vcpu, KVM_XEN_VCPU_SET_ATTR, &rs_addr);
+
+	return vm;
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti;
+	struct kvm_xen_vcpu_attr runstate_save;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	u64 tsc_offset;
+	int ret;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	/* === SOURCE SIDE === */
+	pr_info("=== Source: create VM and run guest ===\n");
+	vm = create_xen_vm(&vcpu);
+
+	/* Run guest once to accumulate some runstate time */
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+
+	pr_info("  Guest sees: runnable=%" PRIu64 " running=%" PRIu64 "\n",
+		uc.args[2], uc.args[3]);
+
+	/* Save clock state */
+	vcpu_get_clock_guest(vcpu, &pvti);
+
+	/*
+	 * Save the guest TSC offset. This test migrates to a new VM on
+	 * the same host, so restoring the same offset makes the guest
+	 * TSC continue uninterrupted across the migration gap, and the
+	 * restored pvclock (KVM_SET_CLOCK_GUEST) then yields a kvmclock
+	 * which has also kept running across the gap. (A real migration
+	 * to a different host would compute the destination offset from
+	 * KVM_GET_CLOCK's {host_tsc, realtime} pair as described in
+	 * Documentation/virt/kvm/devices/vcpu.rst.)
+	 */
+	tsc_offset = vcpu_get_tsc_offset(vcpu);
+
+	/* Save runstate — the vCPU is now "runnable" (not running) */
+	runstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;
+	vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &runstate_save);
+
+	/*
+	 * Transition to runnable state before saving — the vCPU is
+	 * not running during migration.
+	 */
+	runstate_save.u.runstate.state = RUNSTATE_runnable;
+
+	pr_info("  Saved runstate: running=%" PRIu64 " runnable=%" PRIu64
+		" entry=%" PRIu64 "\n",
+		(u64)runstate_save.u.runstate.time_running,
+		(u64)runstate_save.u.runstate.time_runnable,
+		(u64)runstate_save.u.runstate.state_entry_time);
+
+	u64 saved_runnable = runstate_save.u.runstate.time_runnable;
+
+	kvm_vm_free(vm);
+
+	/* === MIGRATION GAP === */
+	pr_info("=== Simulating migration (sleeping 10ms) ===\n");
+	usleep(10000);
+
+	/* === DESTINATION SIDE === */
+	pr_info("=== Destination: create new VM and restore ===\n");
+	vm = create_xen_vm(&vcpu);
+
+	/* Restore the guest TSC offset (same host: TSC continues) */
+	vcpu_set_tsc_offset(vcpu, tsc_offset);
+
+	/* Restore clock — kvmclock will now be ~10ms ahead of the snapshot */
+	vcpu_set_clock_guest(vcpu, &pvti);
+
+	/* Restore runstate exactly as saved (state=runnable) */
+	runstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;
+	ret = __vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &runstate_save);
+	TEST_ASSERT(!ret, "Restore runstate failed: errno %d", errno);
+
+	/*
+	 * Run the guest. When the vCPU enters vcpu_run, the kernel
+	 * transitions from RUNSTATE_runnable to RUNSTATE_running.
+	 * It computes: delta = kvmclock_now - state_entry_time
+	 * This delta (which includes the migration gap) is added to
+	 * time_runnable (steal time).
+	 */
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+
+	u64 guest_runnable = uc.args[2];
+	u64 guest_running = uc.args[3];
+
+	pr_info("  Guest sees: runnable=%" PRIu64 " running=%" PRIu64 "\n",
+		guest_runnable, guest_running);
+
+	u64 steal_increase = guest_runnable - saved_runnable;
+	pr_info("  Steal time increase: %" PRIu64 " ns (migration gap)\n",
+		steal_increase);
+
+	/*
+	 * The steal time increase should be at least 10ms (the sleep).
+	 * The actual gap runs from the source's state_entry_time to the
+	 * destination's kvmclock "now" at vcpu_load time, which includes
+	 * everything from the source guest's last runstate transition
+	 * through VM teardown and re-creation — so the upper bound exists
+	 * only to catch wild miscalculation (e.g. an unscaled TSC delta),
+	 * and is deliberately generous for slow or loaded hosts.
+	 */
+	TEST_ASSERT(steal_increase >= 10000000ULL &&
+		    steal_increase < 60000000000ULL,
+		    "Steal time increase %" PRIu64 " ns not in expected range "
+		    "[10ms, 60s]", steal_increase);
+
+	kvm_vm_free(vm);
+	pr_info("PASS: Migration gap correctly accounted as steal time\n");
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
index aaa414c677addf..43548d8faa74d4 100644
--- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
+++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
@@ -98,22 +98,7 @@ struct sched_poll {
 	u64 timeout;
 };
 
-struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
-} __attribute__((__packed__)); /* 32 bytes */
-
-struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
-} __attribute__((__packed__));
+#include <asm/pvclock-abi.h>
 
 struct vcpu_runstate_info {
 	u32 state;
@@ -987,12 +972,14 @@ int main(int argc, char *argv[])
 
 	if (verbose) {
 		printf("Wall clock (v %d) %d.%09d\n", wc->version, wc->sec, wc->nsec);
-		printf("Time info 1: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n",
-		       ti->version, ti->tsc_timestamp, ti->system_time, ti->tsc_to_system_mul,
-		       ti->tsc_shift, ti->flags);
-		printf("Time info 2: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n",
-		       ti2->version, ti2->tsc_timestamp, ti2->system_time, ti2->tsc_to_system_mul,
-		       ti2->tsc_shift, ti2->flags);
+		printf("Time info 1: v %u tsc %llu time %llu mul %u shift %d flags %x\n",
+		       ti->version, (unsigned long long)ti->tsc_timestamp,
+		       (unsigned long long)ti->system_time,
+		       ti->tsc_to_system_mul, ti->tsc_shift, ti->flags);
+		printf("Time info 2: v %u tsc %llu time %llu mul %u shift %d flags %x\n",
+		       ti2->version, (unsigned long long)ti2->tsc_timestamp,
+		       (unsigned long long)ti2->system_time,
+		       ti2->tsc_to_system_mul, ti2->tsc_shift, ti2->flags);
 	}
 
 	TEST_ASSERT(wc->version && !(wc->version & 1),

3/2 2026/11/11 17:18 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 61369
							output: 33
							thoughts: 1743
						

Thoughts:
**KVM Patch Series Evaluation: WorthFuzzing = true**

Okay, so I need to evaluate this KVM patch series for the x86-64 architecture. First, let's understand the scope. It looks like we're diving deep into KVM's TSC (Timestamp Counter) and clock management. The diff touches a significant number of files, including documentation updates, MAINTAINERS, and core KVM x86 files. Specifically, I see changes to `kvm_vcpu_arch`, `kvm_arch`, and related structures. The introduction of `KVM_VCPU_TSC_SCALE`, and new ioctls (`KVM_SET_CLOCK_GUEST`, `KVM_GET_CLOCK_GUEST`), along with modifications to functions like `kvm_set_tsc_khz`, `kvm_synchronize_tsc`, `kvm_update_masterclock` signals this is clock-related.

Now, I need to determine if this is worth fuzzing. The triage instructions are clear: reachability is key. Thankfully, KVM is *definitely* reachable in standard virtualized environments. I'm thinking QEMU or GCE running KVM, either nested or direct, and importantly, syzkaller *heavily* fuzzes KVM ioctls via `/dev/kvm`. That's a huge plus. This patch series directly modifies code accessible through those ioctls, including setting clock guest, getting clock guest, setting TSC, and setting device attributes.

I see changes that touch: `KVM_SET_CLOCK_GUEST`, `KVM_GET_CLOCK_GUEST`, `KVM_SET_TSC_KHZ`, `KVM_SET_DEVICE_ATTR`, `KVM_SET_CLOCK`, and `KVM_SET_MSRS`. This means that I can trigger the changes within user space via the `/dev/kvm` ioctl calls, and that makes it worth fuzzing.

My conclusion? Based on the triage instructions and the scope of the code changes, this is reachable, executable code in the KVM core. There are refactorings and new runtime assertions. Therefore, I'm confident that `WorthFuzzing = true`. Now, it is time to check which config options are required to enable this code. I will use grepper to examine Kconfig dependencies.



4/2 2026/11/11 17:18 tool grepper
0m Args:
{
  "Expression": "config KVM",
  "PathPrefixes": [
    "arch/x86/kvm/"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/Kconfig=18=if VIRTUALIZATION\narch/x86/kvm/Kconfig-19-\narch/x86/kvm/Kconfig:20:config KVM_X86\narch/x86/kvm/Kconfig-21-\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n--\narch/x86/kvm/Kconfig-51-\narch/x86/kvm/Kconfig:52:config KVM\narch/x86/kvm/Kconfig-53-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/x86/kvm/Kconfig-68-\narch/x86/kvm/Kconfig:69:config KVM_WERROR\narch/x86/kvm/Kconfig-70-\tbool \"Compile KVM with -Werror\"\n--\narch/x86/kvm/Kconfig-82-\narch/x86/kvm/Kconfig:83:config KVM_VM_MEMORY_ATTRIBUTES\narch/x86/kvm/Kconfig-84-\tbool \"Enable per-VM PRIVATE vs. SHARED attributes (for CoCo VMs)\"\n--\narch/x86/kvm/Kconfig-94-\narch/x86/kvm/Kconfig:95:config KVM_SW_PROTECTED_VM\narch/x86/kvm/Kconfig-96-\tbool \"Enable support for KVM software-protected VMs\"\n--\narch/x86/kvm/Kconfig-106-\narch/x86/kvm/Kconfig:107:config KVM_INTEL\narch/x86/kvm/Kconfig-108-\ttristate \"KVM for Intel (and compatible) processors support\"\n--\narch/x86/kvm/Kconfig-117-\narch/x86/kvm/Kconfig:118:config KVM_INTEL_PROVE_VE\narch/x86/kvm/Kconfig-119-        bool \"Check that guests do not receive #VE exceptions\"\n--\narch/x86/kvm/Kconfig=133=config X86_SGX_KVM\n--\narch/x86/kvm/Kconfig-144-\narch/x86/kvm/Kconfig:145:config KVM_INTEL_TDX\narch/x86/kvm/Kconfig-146-\tbool \"Intel Trust Domain Extensions (TDX) support\"\n--\narch/x86/kvm/Kconfig-155-\narch/x86/kvm/Kconfig:156:config KVM_AMD\narch/x86/kvm/Kconfig-157-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-165-\narch/x86/kvm/Kconfig:166:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-167-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n--\narch/x86/kvm/Kconfig-181-\narch/x86/kvm/Kconfig:182:config KVM_IOAPIC\narch/x86/kvm/Kconfig-183-\tbool \"I/O APIC, PIC, and PIT emulation\"\n--\narch/x86/kvm/Kconfig-191-\narch/x86/kvm/Kconfig:192:config KVM_SMM\narch/x86/kvm/Kconfig-193-\tbool \"System Management Mode emulation\"\n--\narch/x86/kvm/Kconfig-202-\narch/x86/kvm/Kconfig:203:config KVM_HYPERV\narch/x86/kvm/Kconfig-204-\tbool \"Support for Microsoft Hyper-V emulation\"\n--\narch/x86/kvm/Kconfig-216-\narch/x86/kvm/Kconfig:217:config KVM_XEN\narch/x86/kvm/Kconfig-218-\tbool \"Support for Xen hypercall interface\"\n--\narch/x86/kvm/Kconfig-225-\narch/x86/kvm/Kconfig:226:config KVM_PROVE_MMU\narch/x86/kvm/Kconfig-227-\tbool \"Prove KVM MMU correctness\"\n--\narch/x86/kvm/Kconfig-238-\narch/x86/kvm/Kconfig:239:config KVM_EXTERNAL_WRITE_TRACKING\narch/x86/kvm/Kconfig-240-\tbool\narch/x86/kvm/Kconfig-241-\narch/x86/kvm/Kconfig:242:config KVM_MAX_NR_VCPUS\narch/x86/kvm/Kconfig-243-\tint \"Maximum number of vCPUs per KVM guest\"\n"
}

5/2 2026/11/11 17:18 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 64949
							output: 35
							thoughts: 17
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into the KVM x86 Makefile**

Okay, time to dig in. I need to understand something specific about the KVM x86 architecture and, naturally, the `Makefile` in `arch/x86/kvm/` is the logical place to start. This is where the crucial build rules and dependencies are defined for that particular subsystem. I need to see how they've structured things, any specific compiler flags being used, what modules are being built and linked, how the kernel interacts with the hypervisor... everything. I'm hoping I can find the answer to my question or at least a direction to seek the answer. Let's see what secrets this Makefile holds.



6/2 2026/11/11 17:18 tool grepper
0m Args:
{
  "Expression": "x86\\.o",
  "PathPrefixes": [
    "arch/x86/kvm/"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/Makefile=6=include $(srctree)/virt/kvm/Makefile.kvm\narch/x86/kvm/Makefile-7-\narch/x86/kvm/Makefile:8:kvm-y\t\t\t+= x86.o emulate.o irq.o lapic.o cpuid.o msrs.o pmu.o regs.o \\\narch/x86/kvm/Makefile-9-\t\t\t   mtrr.o debugfs.o mmu/mmu.o mmu/page_track.o mmu/spte.o\n"
}

7/2 2026/11/11 17:18 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 65314
							output: 36
							thoughts: 24
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Diving into the KVM Build Process**

Right, let's get down to brass tacks. I need to understand the KVM build process, specifically within the x86 architecture. Time to check the `Makefile` located in `arch/x86/kvm/`. I'm expecting this file to hold the crucial rules and dependencies that orchestrate the compilation of the KVM modules and related components for x86. Hopefully, it provides a clear picture of how the different source files are linked together, the flags being used, and any cross-dependencies that exist within that architecture. I'm going to look for common patterns, particularly the way modules are handled, if there are any specific compilation options that would indicate tuning for different processor levels or virtualization extensions, and how it handles things like debugging symbols. This `Makefile` is the Rosetta Stone, it should unlock how the whole thing is put together and hopefully help me with the work I am doing!



8/2 2026/11/11 17:19 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/Makefile",
  "FirstLine": 1,
  "LineCount": 40
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\t\n   3:\tccflags-y += -I $(srctree)/arch/x86/kvm\n   4:\tccflags-$(CONFIG_KVM_WERROR) += -Werror\n   5:\t\n   6:\tinclude $(srctree)/virt/kvm/Makefile.kvm\n   7:\t\n   8:\tkvm-y\t\t\t+= x86.o emulate.o irq.o lapic.o cpuid.o msrs.o pmu.o regs.o \\\n   9:\t\t\t\t   mtrr.o debugfs.o mmu/mmu.o mmu/page_track.o mmu/spte.o\n  10:\t\n  11:\tkvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o\n  12:\tkvm-$(CONFIG_KVM_IOAPIC) += i8259.o i8254.o ioapic.o\n  13:\tkvm-$(CONFIG_KVM_HYPERV) += hyperv.o\n  14:\tkvm-$(CONFIG_KVM_XEN)\t+= xen.o\n  15:\tkvm-$(CONFIG_KVM_SMM)\t+= smm.o\n  16:\t\n  17:\tkvm-intel-y\t\t+= vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \\\n  18:\t\t\t\t   vmx/nested.o vmx/posted_intr.o vmx/main.o\n  19:\t\n  20:\tkvm-intel-$(CONFIG_X86_SGX_KVM)\t+= vmx/sgx.o\n  21:\tkvm-intel-$(CONFIG_KVM_HYPERV)\t+= vmx/hyperv.o vmx/hyperv_evmcs.o\n  22:\tkvm-intel-$(CONFIG_KVM_INTEL_TDX)\t+= vmx/tdx.o\n  23:\t\n  24:\tkvm-amd-y\t\t+= svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o\n  25:\t\n  26:\tkvm-amd-$(CONFIG_KVM_AMD_SEV)\t+= svm/sev.o\n  27:\tkvm-amd-$(CONFIG_KVM_HYPERV)\t+= svm/hyperv.o\n  28:\t\n  29:\tifdef CONFIG_HYPERV\n  30:\tkvm-y\t\t\t+= kvm_onhyperv.o\n  31:\tkvm-intel-y\t\t+= vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o\n  32:\tkvm-amd-y\t\t+= svm/svm_onhyperv.o\n  33:\tendif\n  34:\t\n  35:\tobj-$(CONFIG_KVM_X86)\t+= kvm.o\n  36:\tobj-$(CONFIG_KVM_INTEL)\t+= kvm-intel.o\n  37:\tobj-$(CONFIG_KVM_AMD)\t+= kvm-amd.o\n  38:\t\n  39:\tAFLAGS_svm/vmenter.o    := -iquote $(obj)\n  40:\t$(obj)/svm/vmenter.o: $(obj)/kvm-asm-offsets.h\n"
}

9/2 2026/11/11 17:19 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 66484
							output: 43
							thoughts: 2582
						

Thoughts:
**Analysis of KVM X86 and Xen Changes: Identifying Focus Symbols for Fuzzing**

Okay, so I'm looking at these changes, specifically how they're built and what's been modified. I see `obj-$(CONFIG_KVM_X86) += kvm.o` and `kvm-$(CONFIG_KVM_XEN) += xen.o`, and then notice that `xen.c` is also touched, which piques my interest. The modification to `kvm_xen_start_timer` in `xen.c` suggests some interplay between KVM and Xen. I also see that `x86.c` and `msrs.c` are compiled into `kvm.o`, which is pretty standard.

I need to confirm the configurations. Looking at the Kconfig files, `CONFIG_KVM_X86` depends on `KVM`, which is defined with a bunch of dependencies and selects. To have KVM on x86, you need either `CONFIG_KVM_INTEL` or `CONFIG_KVM_AMD`, and `CONFIG_KVM` needs to be enabled. Then, there's `CONFIG_KVM_XEN`, which provides support for the Xen hypercall interface; it depends on `KVM`. This suggests an integration point.

Alright, let's drill down into the actual code changes. I'll focus on what's been added or significantly altered. In `arch/x86/kvm/x86.c`, I see a cluster of modifications related to guest clock management and TSC synchronization: New ioctls `KVM_GET_CLOCK_GUEST` and `KVM_SET_CLOCK_GUEST` are now handled by new functions `kvm_vcpu_ioctl_get_clock_guest` and `kvm_vcpu_ioctl_set_clock_guest` respectively. There's `hvclock_to_hz` as a helper. There are changes to the TSC attributes handling, including a new `KVM_VCPU_TSC_SCALE` attribute in `kvm_arch_tsc_get_attr` and `kvm_arch_tsc_set_attr`. I'm seeing changes in `kvm_set_tsc_khz`, with a new signature and logic, handling things like `clear_catchup` and `user_set_tsc`. `kvm_synchronize_tsc` and its helpers (`kvm_synchronize_tsc_at`, `__kvm_synchronize_tsc`) have been modified for TSC synchronization; this is very interesting. There's also `kvm_track_tsc_matching`, `pvclock_update_vm_gtod_copy`, `__kvm_start_pvclock_update`, `kvm_update_masterclock` (which now takes `requesting_vcpu`), `__get_kvmclock_master_clock`, `kvm_vm_ioctl_set_clock` (time snapshot and synchronization), `kvm_arch_vcpu_postcreate` (master clock refresh), and `kvm_arch_enable_virtualization_cpu` all being modified. The TSC initialization is also being set in `kvm_arch_init_vm`.

In `arch/x86/kvm/msrs.c`, I notice modifications to `kvm_write_system_time`, specifically regarding the master clock update request logic. And, of course, the modifications in `xen.c` to `kvm_xen_start_timer`, which hints at some specific Xen integration.

Now, based on the fuzzing guidelines, I need to choose *specific* entrypoints or logic functions. The goal is to avoid ubiquitous functions that would dilute the fuzzing effort. Therefore, I need to focus on code that specifically implements the new features or logic changes.

So, here's my shortlist of focus symbols:

*   `kvm_vcpu_ioctl_get_clock_guest` (new ioctl handler)
*   `kvm_vcpu_ioctl_set_clock_guest` (new ioctl handler)
*   `kvm_arch_tsc_get_attr` (KVM_VCPU_TSC_SCALE handling)
*   `kvm_arch_tsc_set_attr` (KVM_VCPU_TSC_SCALE handling, altered TSC logic)
*   `kvm_set_tsc_khz` (ioctl handling, and significant logic changes)
*   `kvm_synchronize_tsc` (entrypoint for TSC synchronization)
*   `kvm_update_masterclock` (heavily modified pvclock update flow)
*   `kvm_vm_ioctl


10/2 2026/11/11 17:19 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 3680,
  "LineCount": 40
}

Results:
{
  "Contents": "3680:\t\tcase KVM_CAP_ENFORCE_PV_FEATURE_CPUID:\n3681:\t\t\tvcpu-\u003earch.pv_cpuid.enforce = cap-\u003eargs[0];\n3682:\t\t\treturn 0;\n3683:\t\tdefault:\n3684:\t\t\treturn -EINVAL;\n3685:\t\t}\n3686:\t}\n3687:\t\n3688:\t#ifdef CONFIG_X86_64\n3689:\tstatic int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)\n3690:\t{\n3691:\t\tstruct pvclock_vcpu_time_info hv_clock = {};\n3692:\t\tstruct kvm_arch *ka = \u0026v-\u003ekvm-\u003earch;\n3693:\t\tbool use_master_clock;\n3694:\t\tunsigned int seq;\n3695:\t\n3696:\t\t/*\n3697:\t\t * Construct the pvclock purely from the master clock state. The\n3698:\t\t * master mul/shift are computed for the guest TSC frequency, which\n3699:\t\t * in master clock mode is the frequency of every vCPU; only the\n3700:\t\t * tsc_timestamp is per-vCPU, translating the master snapshot into\n3701:\t\t * this vCPU's TSC domain via its scaling ratio and offset.\n3702:\t\t *\n3703:\t\t * Note, this deliberately does NOT invoke kvm_guest_time_update(),\n3704:\t\t * which would write the guest's pvclock pages: dirtying guest\n3705:\t\t * memory after the final KVM_RUN would break post-copy migration\n3706:\t\t * flows. The pvclock returned here describes the same clock as the\n3707:\t\t * guest-visible copy (the same linear function of the guest TSC),\n3708:\t\t * anchored at the current master clock snapshot.\n3709:\t\t *\n3710:\t\t * Translating the snapshot through the vCPU's *current* scaling\n3711:\t\t * ratio and offset is correct even if they changed after the\n3712:\t\t * snapshot was taken: the snapshot anchors a host TSC value, not\n3713:\t\t * a guest one. A frequency change whose masterclock update is\n3714:\t\t * still pending does leave stale mul/shift here, but that is the\n3715:\t\t * paused-VM migration path reading a frequency userspace itself\n3716:\t\t * has just changed — and the result fails safe, as the same-vCPU\n3717:\t\t * KVM_SET_CLOCK_GUEST on the destination rejects a mul/shift\n3718:\t\t * inconsistent with the vCPU's frequency with -ERANGE.\n3719:\t\t */\n"
}

11/2 2026/11/11 17:19 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 70852
							output: 37
							thoughts: 30
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into `kvm_synchronize_tsc`**

Okay, time to dig into this. I need to get a better handle on how the TSC (Time Stamp Counter) is synchronized within KVM, specifically for x86 architectures. My initial thought is to navigate directly to the source code. I'm going to jump into `arch/x86/kvm/x86.c` and focus on the `kvm_synchronize_tsc` function. That seems like the logical starting point to understand how they're handling TSC synchronization. Let's see what the implementation reveals.



12/2 2026/11/11 17:20 tool grepper
0m Args:
{
  "Expression": "kvm_synchronize_tsc",
  "PathPrefixes": [
    "arch/x86/kvm/"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/msrs.c=1458=int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)\n--\narch/x86/kvm/msrs.c-1647-\t\tif (msr_info-\u003ehost_initiated) {\narch/x86/kvm/msrs.c:1648:\t\t\tkvm_synchronize_tsc(vcpu, \u0026data, true);\narch/x86/kvm/msrs.c-1649-\t\t} else if (!vcpu-\u003earch.guest_tsc_protected) {\n--\narch/x86/kvm/x86.c=973=static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)\n--\narch/x86/kvm/x86.c-1021-\narch/x86/kvm/x86.c:1022:static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,\narch/x86/kvm/x86.c-1023-\t\t\t\t   u64 host_tsc, s64 ns, bool user_initiated);\n--\narch/x86/kvm/x86.c=1025=static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)\n--\narch/x86/kvm/x86.c-1115-\tif (vcpu-\u003earch.last_vmentry_cpu != -1 || vcpu-\u003earch.user_set_tsc)\narch/x86/kvm/x86.c:1116:\t\tkvm_synchronize_tsc_at(vcpu, \u0026tsc, host_tsc, ns, false);\narch/x86/kvm/x86.c-1117-\telse\narch/x86/kvm/x86.c:1118:\t\tkvm_synchronize_tsc_at(vcpu, NULL, host_tsc, ns, false);\narch/x86/kvm/x86.c-1119-\treturn 0;\n--\narch/x86/kvm/x86.c=1151=static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclock)\n--\narch/x86/kvm/x86.c-1165-\t * and cause a temporary false negative here. But will then\narch/x86/kvm/x86.c:1166:\t * call kvm_synchronize_tsc() from kvm_arch_vcpu_postcreate()\narch/x86/kvm/x86.c-1167-\t * and finish the job.\n--\narch/x86/kvm/x86.c-1183-\t * all_vcpus_matched_freq starts true and is cleared when\narch/x86/kvm/x86.c:1184:\t * __kvm_synchronize_tsc() detects a frequency mismatch.\narch/x86/kvm/x86.c-1185-\t * Re-enable when all vCPUs have synced with matching frequency.\n--\narch/x86/kvm/x86.c=1385=static inline bool kvm_check_tsc_unstable(void)\n--\narch/x86/kvm/x86.c-1402- */\narch/x86/kvm/x86.c:1403:static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,\narch/x86/kvm/x86.c-1404-\t\t\t\t  u64 ns, bool matched, bool user_set_tsc)\n--\narch/x86/kvm/x86.c-1497- */\narch/x86/kvm/x86.c:1498:static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,\narch/x86/kvm/x86.c-1499-\t\t\t\t   u64 host_tsc, s64 ns, bool user_initiated)\n--\narch/x86/kvm/x86.c-1587-\narch/x86/kvm/x86.c:1588:\t__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, user_initiated);\narch/x86/kvm/x86.c-1589-\traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n--\narch/x86/kvm/x86.c-1591-\narch/x86/kvm/x86.c:1592:void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)\narch/x86/kvm/x86.c-1593-{\n--\narch/x86/kvm/x86.c-1604-\narch/x86/kvm/x86.c:1605:\tkvm_synchronize_tsc_at(vcpu, value, host_tsc, ns, user_initiated);\narch/x86/kvm/x86.c-1606-}\n--\narch/x86/kvm/x86.c=3564=static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,\n--\narch/x86/kvm/x86.c-3589-\narch/x86/kvm/x86.c:3590:\t\t__kvm_synchronize_tsc(vcpu, offset, tsc, ns, matched, true);\narch/x86/kvm/x86.c-3591-\t\traw_spin_unlock_irqrestore(\u0026kvm-\u003earch.tsc_write_lock, flags);\n--\narch/x86/kvm/x86.c=10025=void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/x86.c-10045-\tvcpu_load(vcpu);\narch/x86/kvm/x86.c:10046:\tkvm_synchronize_tsc(vcpu, NULL, false);\narch/x86/kvm/x86.c-10047-\n--\narch/x86/kvm/x86.c=10494=int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n--\narch/x86/kvm/x86.c-10540-\t * vCPUs never reach kvm_track_tsc_matching() — notably when the guest\narch/x86/kvm/x86.c:10541:\t * TSC is protected (TDX, SNP Secure TSC) and __kvm_synchronize_tsc()\narch/x86/kvm/x86.c-10542-\t * returns early — is still eligible for PVCLOCK_TSC_STABLE_BIT. The\n--\narch/x86/kvm/x86.c-10546-\t * clock straight back off (permanently so for protected-TSC guests,\narch/x86/kvm/x86.c:10547:\t * which never write the ratio in __kvm_synchronize_tsc()).\narch/x86/kvm/x86.c-10548-\t */\n--\narch/x86/kvm/x86.h=331=int kvm_guest_time_update(struct kvm_vcpu *v);\narch/x86/kvm/x86.h-332-\narch/x86/kvm/x86.h:333:void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated);\narch/x86/kvm/x86.h-334-u64 kvm_scale_tsc(u64 tsc, u64 ratio);\n"
}

13/2 2026/11/11 17:20 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 73220
							output: 40
							thoughts: 33
						

Thoughts:
Here's a summary of my thought process:

**Diving into the KVM Clock Master**

Alright, let's get down to brass tacks. I need to understand how the KVM clock master is being handled. My immediate instinct is to check the `__get_kvmclock_master_clock` function. Specifically, I know that function is likely defined in `arch/x86/kvm/x86.c`, so that's where I'm going to start digging. Time to see what's going on under the hood and get a grasp of how this is implemented.



14/2 2026/11/11 17:20 tool grepper
0m Args:
{
  "Expression": "__get_kvmclock_master_clock",
  "PathPrefixes": [
    "arch/x86/kvm/"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/x86.c=1884=static unsigned long get_cpu_tsc_khz(void)\n--\narch/x86/kvm/x86.c-1892-/* Called within read_seqcount_begin/retry for kvm-\u003epvclock_sc.  */\narch/x86/kvm/x86.c:1893:static bool __get_kvmclock_master_clock(struct kvm *kvm,\narch/x86/kvm/x86.c-1894-\t\t\t\t\tstruct kvm_clock_data *data)\n--\narch/x86/kvm/x86.c=1956=static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data)\n--\narch/x86/kvm/x86.c-1964-\t\tseq = read_seqcount_begin(\u0026ka-\u003epvclock_sc);\narch/x86/kvm/x86.c:1965:\t\tif (!__get_kvmclock_master_clock(kvm, data))\narch/x86/kvm/x86.c-1966-\t\t\tdata-\u003eclock = get_kvmclock_base_ns() + ka-\u003ekvmclock_offset;\n"
}

15/2 2026/11/11 17:20 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 73761
							output: 35
							thoughts: 637
						

Thoughts:
**Deep Dive into KVM Clock Handling and Dependencies**

Okay, so I'm digging into how the KVM clock mechanism works, specifically looking at `get_kvmclock`. It seems this is called from `kvm_vm_ioctl_get_clock`, which handles the `KVM_GET_CLOCK` ioctl. Right, let's trace this.

First, I'm checking `arch/x86/kvm/x86.c`. I see `kvm_vcpu_ioctl_get_clock_guest` and `kvm_vcpu_ioctl_set_clock_guest` there, along with some TSC-related functions: `kvm_set_tsc_khz`, `kvm_synchronize_tsc`, and `kvm_arch_tsc_get_attr`, `kvm_arch_tsc_set_attr`. I'm also seeing `kvm_update_masterclock`, `kvm_vm_ioctl_set_clock`, and `kvm_write_system_time` are there, along with `kvm_xen_start_timer`. Interesting.

Now, I'm remembering that I need to double-check `kvm_vm_ioctl_check_extension` to see if there's any important capability related to this. Yup, `KVM_CAP_CLOCK_GUEST` was added. Good.

Next, I need to understand the required Kconfig options. Let's look at `arch/x86/kvm/Kconfig`. Right, the core KVM module is defined here. It's dependent on `KVM` itself, obviously, and either `KVM_INTEL` or `KVM_AMD`. That makes sense. I see `KVM_X86` is also defined, and importantly, `def_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)` which makes `KVM` enabled if either Intel or AMD KVM support is enabled. And, it seems, `obj-$(CONFIG_KVM_X86) += kvm.o` and `CONFIG_HAVE_KVM` are required.

Oh, and `CONFIG_KVM_XEN` is present because of the `xen.c` file; and it was modified in this patch series. Now, I see that `CONFIG_X86_64` is used extensively in those clock-related functions, and in the capability definition for `KVM_CAP_CLOCK_GUEST` as well! Seems sensible given the target architecture is amd64, which is x86_64.

Okay, let's clarify that. I'm double-checking whether `KVM` or `KVM_INTEL`/`KVM_AMD` are configs without the `CONFIG_` prefix. Yes, they are. That's it! "KVM", "KVM_INTEL", "KVM_AMD" and "KVM_XEN" are required without the `CONFIG_` prefix.

Alright, so are there any other dependencies I need to be aware of? Let me re-examine `arch/x86/kvm/Kconfig` to see if there are any other direct dependencies that either `KVM_XEN`, `KVM_INTEL`, or `KVM` require. I should cover my bases.



16/2 2026/11/11 17:20 tool grepper
0m Args:
{
  "Expression": "config KVM",
  "PathPrefixes": [
    "arch/x86/kvm/Kconfig"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/Kconfig=18=if VIRTUALIZATION\narch/x86/kvm/Kconfig-19-\narch/x86/kvm/Kconfig:20:config KVM_X86\narch/x86/kvm/Kconfig-21-\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n--\narch/x86/kvm/Kconfig-51-\narch/x86/kvm/Kconfig:52:config KVM\narch/x86/kvm/Kconfig-53-\ttristate \"Kernel-based Virtual Machine (KVM) support\"\n--\narch/x86/kvm/Kconfig-68-\narch/x86/kvm/Kconfig:69:config KVM_WERROR\narch/x86/kvm/Kconfig-70-\tbool \"Compile KVM with -Werror\"\n--\narch/x86/kvm/Kconfig-82-\narch/x86/kvm/Kconfig:83:config KVM_VM_MEMORY_ATTRIBUTES\narch/x86/kvm/Kconfig-84-\tbool \"Enable per-VM PRIVATE vs. SHARED attributes (for CoCo VMs)\"\n--\narch/x86/kvm/Kconfig-94-\narch/x86/kvm/Kconfig:95:config KVM_SW_PROTECTED_VM\narch/x86/kvm/Kconfig-96-\tbool \"Enable support for KVM software-protected VMs\"\n--\narch/x86/kvm/Kconfig-106-\narch/x86/kvm/Kconfig:107:config KVM_INTEL\narch/x86/kvm/Kconfig-108-\ttristate \"KVM for Intel (and compatible) processors support\"\n--\narch/x86/kvm/Kconfig-117-\narch/x86/kvm/Kconfig:118:config KVM_INTEL_PROVE_VE\narch/x86/kvm/Kconfig-119-        bool \"Check that guests do not receive #VE exceptions\"\n--\narch/x86/kvm/Kconfig=133=config X86_SGX_KVM\n--\narch/x86/kvm/Kconfig-144-\narch/x86/kvm/Kconfig:145:config KVM_INTEL_TDX\narch/x86/kvm/Kconfig-146-\tbool \"Intel Trust Domain Extensions (TDX) support\"\n--\narch/x86/kvm/Kconfig-155-\narch/x86/kvm/Kconfig:156:config KVM_AMD\narch/x86/kvm/Kconfig-157-\ttristate \"KVM for AMD processors support\"\n--\narch/x86/kvm/Kconfig-165-\narch/x86/kvm/Kconfig:166:config KVM_AMD_SEV\narch/x86/kvm/Kconfig-167-\tbool \"AMD Secure Encrypted Virtualization (SEV) support\"\n--\narch/x86/kvm/Kconfig-181-\narch/x86/kvm/Kconfig:182:config KVM_IOAPIC\narch/x86/kvm/Kconfig-183-\tbool \"I/O APIC, PIC, and PIT emulation\"\n--\narch/x86/kvm/Kconfig-191-\narch/x86/kvm/Kconfig:192:config KVM_SMM\narch/x86/kvm/Kconfig-193-\tbool \"System Management Mode emulation\"\n--\narch/x86/kvm/Kconfig-202-\narch/x86/kvm/Kconfig:203:config KVM_HYPERV\narch/x86/kvm/Kconfig-204-\tbool \"Support for Microsoft Hyper-V emulation\"\n--\narch/x86/kvm/Kconfig-216-\narch/x86/kvm/Kconfig:217:config KVM_XEN\narch/x86/kvm/Kconfig-218-\tbool \"Support for Xen hypercall interface\"\n--\narch/x86/kvm/Kconfig-225-\narch/x86/kvm/Kconfig:226:config KVM_PROVE_MMU\narch/x86/kvm/Kconfig-227-\tbool \"Prove KVM MMU correctness\"\n--\narch/x86/kvm/Kconfig-238-\narch/x86/kvm/Kconfig:239:config KVM_EXTERNAL_WRITE_TRACKING\narch/x86/kvm/Kconfig-240-\tbool\narch/x86/kvm/Kconfig-241-\narch/x86/kvm/Kconfig:242:config KVM_MAX_NR_VCPUS\narch/x86/kvm/Kconfig-243-\tint \"Maximum number of vCPUs per KVM guest\"\n"
}

17/2 2026/11/11 17:20 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 76464
							output: 37
							thoughts: 24
						

Thoughts:
Here's my thought process, as requested:

**Navigating the KVM Configuration Landscape**

Okay, so I need to understand something about KVM configuration, specifically within the x86 architecture. My first instinct, given my experience, is to zero in on the `Kconfig` files – they're the bedrock of kernel configuration. And given the context, I'm pretty sure I want to check `arch/x86/kvm/Kconfig`. It's almost a reflex at this point. That directory is where the KVM-specific configurations for x86 would reside.

Now, my mental roadmap: I'm primarily interested in aspects related to *virtualization* itself. So, I need to hunt around within that `Kconfig` file for relevant options. That's my immediate focus – I need to understand how the virtualization features are exposed and controlled within the x86 KVM context. I'll need to look for definitions, dependencies, and any conditional logic associated with `VIRTUALIZATION` or related terms. This should give me a solid foundation for further investigation, should I need it. Let's see what's in there...



18/2 2026/11/11 17:20 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/Kconfig",
  "FirstLine": 1,
  "LineCount": 25
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0\n   2:\t#\n   3:\t# KVM configuration\n   4:\t#\n   5:\t\n   6:\tsource \"virt/kvm/Kconfig\"\n   7:\t\n   8:\tmenuconfig VIRTUALIZATION\n   9:\t\tbool \"Virtualization\"\n  10:\t\tdefault y\n  11:\t\thelp\n  12:\t\t  Say Y here to get to see options for using your Linux host to run other\n  13:\t\t  operating systems inside virtual machines (guests).\n  14:\t\t  This option alone does not add any kernel code.\n  15:\t\n  16:\t\t  If you say N, all options in this submenu will be skipped and disabled.\n  17:\t\n  18:\tif VIRTUALIZATION\n  19:\t\n  20:\tconfig KVM_X86\n  21:\t\tdef_tristate KVM if (KVM_INTEL != n || KVM_AMD != n)\n  22:\t\tselect KVM_COMMON\n  23:\t\tselect KVM_ELIDE_TLB_FLUSH_IF_YOUNG\n  24:\t\tselect KVM_MMU_LOCKLESS_AGING\n  25:\t\tselect HAVE_KVM_IRQCHIP\n"
}

19/2 2026/11/11 17:20 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 77100
							output: 290
							thoughts: 2156
						

Thoughts:
**KVM Target Identification and Analysis**

Okay, so we're looking at a patch related to `VIRTUALIZATION`, specifically focusing on `KVM`. We need to determine the best approach to fuzz this.  First, let's confirm the relevant configuration options: `KVM`, `KVM_INTEL`, `KVM_AMD`, and `KVM_XEN`.  `KVM_X86` is also indirectly enabled, which is good to know. And because `KVM_XEN` is enabled that enables  `kvm_xen_start_timer` function.

Now, I'll go over the modified code.  The patch touches `arch/x86/kvm/msrs.c`, `arch/x86/kvm/x86.c`, and `arch/x86/kvm/xen.c`, as well as several headers. This is a good starting point. `msrs.c` deals with `kvm_write_system_time` and `x86.c` seems to have extensive changes to TSC synchronization and clock handling: `set_tsc_khz`, `kvm_set_tsc_khz`, `kvm_track_tsc_matching`, `__kvm_synchronize_tsc`, `kvm_synchronize_tsc_at`, `kvm_synchronize_tsc`, and so on. Also `kvm_xen_start_timer` in `xen.c` catches my eye.

Let's identify the best functions to focus on. We need to be careful not to pick something too broad.  `kvm_arch_vcpu_ioctl` is a good example; it's fundamental but maybe too ubiquitous. However, the new ioctls, `kvm_vcpu_ioctl_get_clock_guest` and `kvm_vcpu_ioctl_set_clock_guest`, look promising because they're new API entrypoints, as are the other functions that are introduced.  `kvm_set_tsc_khz`, `kvm_synchronize_tsc`, `kvm_arch_tsc_get_attr`, `kvm_arch_tsc_set_attr`, `kvm_update_masterclock`, `kvm_vm_ioctl_set_clock` and `kvm_write_system_time`, as well as `kvm_xen_start_timer` seem specific.

Now, let's verify if `kvm_vcpu_ioctl_get_clock_guest` and `kvm_vcpu_ioctl_set_clock_guest` are static. If they were static inlined functions in a header, they wouldn't be directly targetable, but they're regular static functions in `x86.c`.  Syzkaller can definitely target those symbols!  `kvm_synchronize_tsc` is non-static, so we should be good to go.

The question of whether these are worth fuzzing is absolutely a 'yes'.  This patch series introduces new ioctls, a new attribute, and fundamentally modifies TSC synchronization, clock handling, and synchronization across vCPUs within the KVM (x86) subsystem.  All changes are in reachable kernel code, which makes them high-value targets.

So, the configurations we need are `KVM`, `KVM_INTEL`, `KVM_AMD`, and `KVM_XEN`. `X86_64` and `VIRTUALIZATION` are also required, but those are already assumed.  `KVM_X86` is implied.

In summary, the patch introduces new KVM vCPU ioctls and a vCPU attribute, and significantly modifies x86 KVM TSC synchronization, frequency tracking, and master clock handling. These changes are all in user-space reachable code, which makes these excellent fuzzing targets.



20/2 2026/11/11 17:20 tool set-results
0m Args:
{
  "EnableConfigs": [
    "KVM",
    "KVM_INTEL",
    "KVM_AMD",
    "KVM_XEN"
  ],
  "FocusSymbols": [
    "kvm_vcpu_ioctl_get_clock_guest",
    "kvm_vcpu_ioctl_set_clock_guest",
    "kvm_set_tsc_khz",
    "kvm_synchronize_tsc",
    "kvm_arch_tsc_get_attr",
    "kvm_arch_tsc_set_attr",
    "kvm_update_masterclock",
    "kvm_vm_ioctl_set_clock",
    "kvm_write_system_time",
    "kvm_xen_start_timer"
  ],
  "Reasoning": "The patch series introduces new KVM ioctls (KVM_GET_CLOCK_GUEST, KVM_SET_CLOCK_GUEST), a new vCPU device attribute (KVM_VCPU_TSC_SCALE), and significantly refactors KVM TSC synchronization and master clock management (allowing divergent TSC offsets without disabling master clock mode, updating generation tracking, and refining pvclock updates). These changes modify reachable, executable code in the x86 KVM subsystem accessible via userspace ioctls and warrant fuzzing.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "KVM",
    "KVM_INTEL",
    "KVM_AMD",
    "KVM_XEN"
  ],
  "FocusSymbols": [
    "kvm_vcpu_ioctl_get_clock_guest",
    "kvm_vcpu_ioctl_set_clock_guest",
    "kvm_set_tsc_khz",
    "kvm_synchronize_tsc",
    "kvm_arch_tsc_get_attr",
    "kvm_arch_tsc_set_attr",
    "kvm_update_masterclock",
    "kvm_vm_ioctl_set_clock",
    "kvm_write_system_time",
    "kvm_xen_start_timer"
  ],
  "Reasoning": "The patch series introduces new KVM ioctls (KVM_GET_CLOCK_GUEST, KVM_SET_CLOCK_GUEST), a new vCPU device attribute (KVM_VCPU_TSC_SCALE), and significantly refactors KVM TSC synchronization and master clock management (allowing divergent TSC offsets without disabling master clock mode, updating generation tracking, and refining pvclock updates). These changes modify reachable, executable code in the x86 KVM subsystem accessible via userspace ioctls and warrant fuzzing.",
  "WorthFuzzing": true
}

21/1 2026/11/11 17:20 action If
3m Args:
{
  "WorthFuzzing": true
}

Results:
null

22/2 2026/11/11 17:20 agent kmsan-evaluator
3m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch series refactors x86 KVM timestamp counter (TSC) synchronization and master clock tracking, allowing the master clock to remain active even when vCPUs have divergent TSC offsets (provided their TSC frequencies match). It also adds KVM_GET_CLOCK_GUEST and KVM_SET_CLOCK_GUEST ioctls along with the KVM_VCPU_TSC_SCALE device attribute to support precise kvmclock migration.\n\nEvaluating the memory safety aspects contrasting KMSAN and KASAN:\n1. Structures copied to userspace:\n   - KVM_GET_CLOCK_GUEST copies `struct pvclock_vcpu_time_info hv_clock = {}`, which is completely zero-initialized on the stack. Because it is declared `__attribute__((__packed__))`, there are no hidden compiler alignment holes, and all fields (including `pad0` and `pad[2]`) are explicitly zeroed before copying to userspace.\n   - KVM_VCPU_TSC_SCALE copies `struct kvm_vcpu_tsc_scale scale` consisting of two `__u64` members (16 bytes total) with no internal or trailing padding holes; both members (`tsc_ratio` and `tsc_frac_bits`) are explicitly assigned before `copy_to_user`.\n   - In `kvm_vm_ioctl_get_clock`, `struct kvm_clock_data data` was already zero-initialized with `{ 0 }`.\n2. Stack and heap initialization:\n   - New struct members in `struct kvm_arch` and `struct kvm_vcpu_arch` reside in objects allocated with zero-initialization (`kzalloc` and `kmem_cache_zalloc`).\n   - All newly introduced or modified local variables on the stack (e.g., `tsc_shift`, `tsc_mult`, `host_tsc`, `ns`, `clock`) are fully initialized by helper functions or explicitly in all control flow branches before being evaluated or passed onward.\n3. Bug profiles and sanitizer coverage:\n   - The primary risks in this patch series involve concurrency and locking protocol updates (`tsc_write_lock`, `pvclock_sc` seqcount, vCPU request propagation), as well as fixed-point arithmetic, shift bounds, and clock monotonicity logic.\n   - Concurrency bugs are covered by LOCKDEP and standard race checkers; any potential memory corruption or out-of-bounds access is covered by KASAN.\n   - There are no risks of uninitialized memory reads or kernel info-leaks.\n\nTherefore, running a dedicated KMSAN fuzzing session is not justified.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 840dfffc5f02909c098eb4036b0c016646e5edff
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Nov 11 17:18:20 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index ddc61ea36ac59d..44c6152c5768da 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -2023,6 +2023,14 @@ If the KVM_CAP_VM_TSC_CONTROL capability is advertised, this can also
 be used as a vm ioctl to set the initial tsc frequency of subsequently
 created vCPUs.  Note, the vm ioctl is only allowed prior to creating vCPUs.
 
+Changing the frequency of a vCPU with the vcpu ioctl re-synchronizes
+its TSC: for a vCPU which has run, or whose TSC userspace has written,
+the current guest TSC value is preserved across the change (the TSC
+offset, as visible through the KVM_VCPU_TSC_OFFSET attribute, is
+rewritten accordingly); otherwise the vCPU is synchronized to the
+VM's existing TSC timeline at the new frequency. Setting the current
+frequency again is a no-op.
+
 For TSC protected Confidential Computing (CoCo) VMs where TSC frequency
 is configured once at VM scope and remains unchanged during VM's
 lifetime, the vm ioctl should be used to configure the TSC frequency
@@ -6759,6 +6767,59 @@ if the guest_memfd memory was pinned in IOMMU page tables.
 
 See also: :ref:`KVM_SET_MEMORY_ATTRIBUTES`.
 
+4.147 KVM_GET_CLOCK_GUEST
+----------------------------
+
+:Capability: KVM_CAP_CLOCK_GUEST
+:Architectures: x86_64
+:Type: vcpu ioctl
+:Parameters: struct pvclock_vcpu_time_info (out)
+:Returns: 0 on success, <0 on error
+
+Retrieves the current time information structure used for KVM/PV clocks,
+in precisely the form advertised to the guest vCPU, which gives parameters
+for a direct conversion from a guest TSC value to nanoseconds.
+
+The structure is in terms of the given vCPU's TSC. It must be passed back
+to KVM_SET_CLOCK_GUEST on the *same* vCPU (on the destination VM, for
+migration); vCPUs may legitimately have different TSC offsets, which would
+otherwise be silently folded into the restored KVM clock.
+
+When the KVM clock is not in "master clock" mode, for example because the
+host TSC is unreliable or the guest TSCs are oddly configured, the KVM clock
+is actually defined by the host CLOCK_MONOTONIC_RAW instead of the guest TSC.
+In this case, the KVM_GET_CLOCK_GUEST ioctl returns -ENODATA.
+
+4.148 KVM_SET_CLOCK_GUEST
+----------------------------
+
+:Capability: KVM_CAP_CLOCK_GUEST
+:Architectures: x86_64
+:Type: vcpu ioctl
+:Parameters: struct pvclock_vcpu_time_info (in)
+:Returns: 0 on success, <0 on error
+
+Sets the KVM clock (for the whole VM) in terms of the vCPU TSC, using the
+pvclock structure as returned by KVM_GET_CLOCK_GUEST. This allows the precise
+arithmetic relationship between guest TSC and KVM clock to be preserved by
+userspace across migration.
+
+When the KVM clock is not in "master clock" mode, and the KVM clock is actually
+defined by the host CLOCK_MONOTONIC_RAW, this ioctl returns -ENODATA. Userspace
+may choose to set the clock using the less precise KVM_SET_CLOCK ioctl, or may
+choose to fail, denying migration to a host whose TSC is misbehaving. A host
+whose CPU TSC frequency is unknown (only possible without
+X86_FEATURE_CONSTANT_TSC) is never in "master clock" mode, so it also returns
+-ENODATA.
+
+If the mul/shift fields of the provided pvclock structure encode a TSC
+frequency inconsistent with the vCPU's actual TSC frequency, this ioctl
+returns -ERANGE.
+
+If the vCPU's current TSC is behind the tsc_timestamp in the provided
+structure, this ioctl returns -EINVAL. Restore the guest TSC (which the
+documented migration procedure keeps monotonic) before invoking it.
+
 .. _kvm_run:
 
 5. The kvm_run structure
diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst
index deb5c51bc00c87..8dc6ad904429dd 100644
--- a/Documentation/virt/kvm/devices/vcpu.rst
+++ b/Documentation/virt/kvm/devices/vcpu.rst
@@ -239,6 +239,7 @@ including the layout of the stolen time structure.
 :Architectures: x86
 
 4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET
+----------------------------------
 
 :Parameters: 64-bit unsigned TSC offset
 
@@ -253,7 +254,10 @@ Returns:
 Specifies the guest's TSC offset relative to the host's TSC. The guest's
 TSC is then derived by the following equation:
 
-  guest_tsc = host_tsc + KVM_VCPU_TSC_OFFSET
+  guest_tsc = ((host_tsc * tsc_ratio) >> tsc_frac_bits) + KVM_VCPU_TSC_OFFSET
+
+The values of tsc_ratio and tsc_frac_bits can be obtained using
+the KVM_VCPU_TSC_SCALE attribute.
 
 This attribute is useful to adjust the guest's TSC on live migration,
 so that the TSC counts the time during which the VM was paused. The
@@ -261,44 +265,117 @@ following describes a possible algorithm to use for this purpose.
 
 From the source VMM process:
 
-1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_src),
+1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_src),
    kvmclock nanoseconds (guest_src), and host CLOCK_REALTIME nanoseconds
-   (host_src).
+   (time_src) at a given moment (Tsrc). The host_tsc field is only valid
+   when the returned flags include KVM_CLOCK_HOST_TSC.
+
+2. For each vCPU[i]:
+
+   a. Read the KVM_VCPU_TSC_OFFSET attribute to record the guest TSC offset
+      (ofs_src[i]).
+
+   b. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling
+      ratio (ratio_src[i], frac_bits_src[i]). If the attribute is not
+      supported (-ENXIO), there is no hardware TSC scaling and identity
+      scaling applies: use ratio 1, frac_bits 0.
+
+   c. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the
+      guest's TSC (freq[i]).
+
+   d. Use host_tsc_src and the scaling/offset factors to calculate this
+      vCPU's TSC at time Tsrc:
+
+      tsc_src[i] = ((host_tsc_src * ratio_src[i]) >> frac_bits_src[i]) + ofs_src[i]
 
-2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the
-   guest TSC offset (ofs_src[i]).
+      Note that frac_bits may be as high as 48, so this multiplication
+      needs a 128-bit intermediate to avoid overflow.
 
-3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the
-   guest's TSC (freq).
+3. Invoke the KVM_GET_CLOCK_GUEST ioctl on the boot vCPU to return the KVM
+   clock as a function of the guest TSC (pvti_src). (This ioctl may not
+   succeed if the host and guest TSCs are not consistent and well-behaved.)
 
 From the destination VMM process:
 
-4. Invoke the KVM_SET_CLOCK ioctl, providing the source nanoseconds from
-   kvmclock (guest_src) and CLOCK_REALTIME (host_src) in their respective
-   fields.  Ensure that the KVM_CLOCK_REALTIME flag is set in the provided
-   structure.
+4. Invoke the KVM_SET_TSC_KHZ ioctl to set the scaled frequency of the
+   guest's TSC (freq[i]) — either on the VM before creating the vCPUs, or
+   on each vCPU after creating it (as the exemplar test does). When using
+   the per-vCPU form, set the frequency before performing step 7 on that
+   vCPU: KVM_VCPU_TSC_SCALE reports the ratio for the currently
+   configured frequency.
+
+5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (host_tsc_dst) and
+   host CLOCK_REALTIME nanoseconds (time_dst) at a given moment (Tdst),
+   again checking KVM_CLOCK_HOST_TSC in the returned flags.
+
+6. Calculate the number of nanoseconds elapsed between Tsrc and Tdst:
+
+   ΔT = time_dst - time_src
+
+7. As each vCPU[i] is created:
+
+   a. Read the KVM_VCPU_TSC_SCALE attribute to record the guest TSC scaling
+      ratio (ratio_dst[i], frac_bits_dst[i]). As in step 2b, -ENXIO means
+      identity scaling: use ratio 1, frac_bits 0.
+
+   b. Calculate the intended guest TSC value at time Tdst, taking care
+      with the units (ΔT is in nanoseconds; freq, as set by
+      KVM_SET_TSC_KHZ, is in kHz):
 
-   KVM will advance the VM's kvmclock to account for elapsed time since
-   recording the clock values.  Note that this will cause problems in
-   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized
-   between the source and destination, and a reasonably short time passes
-   between the source pausing the VMs and the destination executing
-   steps 4-7.
+      tsc_dst[i] = tsc_src[i] + (ΔT * freq[i] / 10^6)
+
+   c. Use host_tsc_dst and the scaling factors to calculate this vCPU's
+      raw scaled TSC at time Tdst without offsetting:
+
+      raw_dst[i] = ((host_tsc_dst * ratio_dst[i]) >> frac_bits_dst[i])
+
+   d. Calculate ofs_dst[i] = tsc_dst[i] - raw_dst[i] and set the resulting
+      offset using the KVM_VCPU_TSC_OFFSET attribute.
+
+8. If pvti_src was provided, invoke the KVM_SET_CLOCK_GUEST ioctl on the boot
+   vCPU to restore the KVM clock as a precise function of the guest TSC.
+
+9. If KVM_SET_CLOCK_GUEST was not available or failed (e.g. because the
+   master clock is not active), fall back to the KVM_SET_CLOCK ioctl,
+   providing the source nanoseconds from kvmclock (guest_src) and
+   CLOCK_REALTIME (time_src) in their respective fields. Ensure that the
+   KVM_CLOCK_REALTIME flag is set in the provided structure.
+
+   KVM will restore the VM's kvmclock, accounting for elapsed time since
+   the clock values were recorded. Note that this will cause problems in
+   the guest (e.g., timeouts) unless CLOCK_REALTIME is synchronized between
+   the source and destination, and a reasonably short time passes between
+   the source pausing the VMs and the destination resuming them.
+   Due to the KVM_[SG]ET_CLOCK API using CLOCK_REALTIME instead of
+   CLOCK_TAI, leap seconds during the migration may also introduce errors.
+
+4.2 ATTRIBUTE: KVM_VCPU_TSC_SCALE
+---------------------------------
+
+:Parameters: struct kvm_vcpu_tsc_scale
+
+Returns:
+
+	 ======= ======================================
+	 -EFAULT Error writing the result to the
+		 provided address.
+	 -ENXIO  Attribute not supported (no TSC scaling)
+	 -EINVAL Invalid request to write the attribute
+	 ======= ======================================
 
-5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (tsc_dest) and
-   kvmclock nanoseconds (guest_dest).
+This read-only attribute reports the guest's TSC scaling factor, in the form
+of a fixed-point number represented by the following structure::
 
-6. Adjust the guest TSC offsets for every vCPU to account for (1) time
-   elapsed since recording state and (2) difference in TSCs between the
-   source and destination machine:
+  struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+  };
 
-   ofs_dst[i] = ofs_src[i] -
-     (guest_src - guest_dest) * freq +
-     (tsc_src - tsc_dest)
+The tsc_frac_bits field indicates the location of the fixed point, such that
+host TSC values are converted to guest TSC using the formula:
 
-   ("ofs[i] + tsc - guest * freq" is the guest TSC value corresponding to
-   a time of 0 in kvmclock.  The above formula ensures that it is the
-   same on the destination as it was on the source).
+  guest_tsc = ((host_tsc * tsc_ratio) >> tsc_frac_bits) + offset
 
-7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the
-   respective value derived in the previous step.
+Userspace can use this to precisely calculate the guest TSC from the host
+TSC at any given moment. This is needed for accurate migration of guests,
+as described in the documentation for the KVM_VCPU_TSC_OFFSET attribute.
diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst
index 662231e958a075..4548b61a7652a8 100644
--- a/Documentation/virt/kvm/locking.rst
+++ b/Documentation/virt/kvm/locking.rst
@@ -263,7 +263,7 @@ time it will be set using the Dirty tracking mechanism described above.
 
 :Type:		raw_spinlock_t
 :Arch:		x86
-:Protects:	- kvm_arch::{last_tsc_write,last_tsc_nsec,last_tsc_offset}
+:Protects:	- kvm_arch::{cur_tsc_write,cur_tsc_nsec,cur_tsc_offset}
 		- tsc offset in vmcb
 :Comment:	'raw' because updating the tsc offsets must not be preempted.
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 9fadc98d3c4998..773f7c800f6aac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14663,8 +14663,8 @@ S:	Supported
 T:	git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
 F:	arch/um/include/asm/kvm_para.h
 F:	arch/x86/include/asm/kvm_para.h
-F:	arch/x86/include/asm/pvclock-abi.h
 F:	arch/x86/include/uapi/asm/kvm_para.h
+F:	arch/x86/include/uapi/asm/pvclock-abi.h
 F:	arch/x86/kernel/kvm.c
 F:	arch/x86/kernel/kvmclock.c
 F:	include/asm-generic/kvm_para.h
@@ -29780,8 +29780,8 @@ R:	Boris Ostrovsky <boris.ostrovsky@oracle.com>
 L:	xen-devel@lists.xenproject.org (moderated for non-subscribers)
 S:	Supported
 F:	arch/x86/configs/xen.config
-F:	arch/x86/include/asm/pvclock-abi.h
 F:	arch/x86/include/asm/xen/
+F:	arch/x86/include/uapi/asm/pvclock-abi.h
 F:	arch/x86/platform/pvh/
 F:	arch/x86/xen/
 
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e2eef7057bd353..59260f08765402 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -887,6 +887,8 @@ struct kvm_vcpu_arch {
 	u64 this_tsc_nsec;
 	u64 this_tsc_write;
 	u64 this_tsc_generation;
+	u64 this_tsc_freq_generation;
+	bool user_set_tsc;
 	bool tsc_catchup;
 	bool tsc_always_catchup;
 	s8 virtual_tsc_shift;
@@ -1236,15 +1238,16 @@ struct kvm_arch {
 	 * preemption-disabled region, so it must be a raw spinlock.
 	 */
 	raw_spinlock_t tsc_write_lock;
-	u64 last_tsc_nsec;
-	u64 last_tsc_write;
-	u32 last_tsc_khz;
-	u64 last_tsc_offset;
-	u64 last_tsc_scaling_ratio;
+	u32 cur_tsc_khz;
+	u64 cur_tsc_scaling_ratio;
 	u64 cur_tsc_nsec;
 	u64 cur_tsc_write;
 	u64 cur_tsc_offset;
 	u64 cur_tsc_generation;
+	bool all_vcpus_matched_tsc;
+	bool all_vcpus_matched_freq;
+	int nr_vcpus_matched_freq;
+	u64 cur_tsc_freq_generation;
 	int nr_vcpus_matched_tsc;
 
 	u32 default_tsc_khz;
@@ -1269,7 +1272,6 @@ struct kvm_arch {
 #endif
 
 	bool backwards_tsc_observed;
-	bool boot_vcpu_runs_old_kvmclock;
 	u32 bsp_vcpu_id;
 
 	u64 disabled_quirks;
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 1585ec8040666e..f8274d8e471d63 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/stddef.h>
+#include <asm/pvclock-abi.h>
 
 #define KVM_PIO_PAGE_OFFSET 1
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 2
@@ -963,6 +964,12 @@ struct kvm_hyperv_eventfd {
 /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
 #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
 #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */
+
+struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+};
 
 /* x86-specific KVM_EXIT_HYPERCALL flags. */
 #define KVM_EXIT_HYPERCALL_LONG_MODE	_BITULL(0)
diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/uapi/asm/pvclock-abi.h
similarity index 82%
rename from arch/x86/include/asm/pvclock-abi.h
rename to arch/x86/include/uapi/asm/pvclock-abi.h
index b9fece5fc96d6f..6d70cf64036293 100644
--- a/arch/x86/include/asm/pvclock-abi.h
+++ b/arch/x86/include/uapi/asm/pvclock-abi.h
@@ -1,6 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef _ASM_X86_PVCLOCK_ABI_H
 #define _ASM_X86_PVCLOCK_ABI_H
+
+#include <linux/types.h>
+
 #ifndef __ASSEMBLER__
 
 /*
@@ -24,20 +27,20 @@
  */
 
 struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
+	__u32   version;
+	__u32   pad0;
+	__u64   tsc_timestamp;
+	__u64   system_time;
+	__u32   tsc_to_system_mul;
+	__s8    tsc_shift;
+	__u8    flags;
+	__u8    pad[2];
 } __attribute__((__packed__)); /* 32 bytes */
 
 struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
+	__u32   version;
+	__u32   sec;
+	__u32   nsec;
 } __attribute__((__packed__));
 
 #define PVCLOCK_TSC_STABLE_BIT	(1 << 0)
diff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c
index e91650af44c207..94cd4d73689a77 100644
--- a/arch/x86/kvm/msrs.c
+++ b/arch/x86/kvm/msrs.c
@@ -1275,24 +1275,30 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock, int sec_hi_o
 static void kvm_write_system_time(struct kvm_vcpu *vcpu, gpa_t system_time,
 				  bool old_msr, bool host_initiated)
 {
-	struct kvm_arch *ka = &vcpu->kvm->arch;
-
-	if (vcpu->vcpu_id == 0 && !host_initiated) {
-		if (ka->boot_vcpu_runs_old_kvmclock != old_msr)
-			kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
-
-		ka->boot_vcpu_runs_old_kvmclock = old_msr;
-	}
+	/*
+	 * Slide the master clock reference point forward, so that the
+	 * pvclock written below carries a recent tsc_timestamp. SUSE's
+	 * 2.6.16 kernel (the only known user of the legacy MSR with a
+	 * reason to care) re-requests the time by rewriting this MSR
+	 * whenever tsc_timestamp falls more than 1/5 jiffie behind the
+	 * TSC, and would livelock against a fixed reference point; each
+	 * rewrite now genuinely freshens it. A write with the enable
+	 * bit clear deactivates the pvclock; there is nothing to
+	 * freshen.
+	 */
+	if (old_msr && !host_initiated && (system_time & 1))
+		kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 
 	vcpu->arch.time = system_time;
-	kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 
 	/* we verify if the enable bit is set... */
-	if (system_time & 1)
+	if (system_time & 1) {
 		kvm_gpc_activate(&vcpu->arch.pv_time, system_time & ~1ULL,
 				 sizeof(struct pvclock_vcpu_time_info));
-	else
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+	} else {
 		kvm_gpc_deactivate(&vcpu->arch.pv_time);
+	}
 
 	return;
 }
@@ -1639,7 +1645,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		break;
 	case MSR_IA32_TSC:
 		if (msr_info->host_initiated) {
-			kvm_synchronize_tsc(vcpu, &data);
+			kvm_synchronize_tsc(vcpu, &data, true);
 		} else if (!vcpu->arch.guest_tsc_protected) {
 			u64 adj = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data) -
 				  vcpu->arch.l1_tsc_offset;
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 93de876c318ce5..704683532ef018 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -1003,25 +1003,25 @@ TRACE_EVENT(kvm_write_tsc_offset,
 	{VDSO_CLOCKMODE_TSC,  "tsc"}			\
 
 TRACE_EVENT(kvm_update_master_clock,
-	TP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched),
-	TP_ARGS(use_master_clock, host_clock, offset_matched),
+	TP_PROTO(bool use_master_clock, unsigned int host_clock, bool freq_matched),
+	TP_ARGS(use_master_clock, host_clock, freq_matched),
 
 	TP_STRUCT__entry(
 		__field(		bool,	use_master_clock	)
 		__field(	unsigned int,	host_clock		)
-		__field(		bool,	offset_matched		)
+		__field(		bool,	freq_matched		)
 	),
 
 	TP_fast_assign(
 		__entry->use_master_clock	= use_master_clock;
 		__entry->host_clock		= host_clock;
-		__entry->offset_matched		= offset_matched;
+		__entry->freq_matched		= freq_matched;
 	),
 
-	TP_printk("masterclock %d hostclock %s offsetmatched %u",
+	TP_printk("masterclock %d hostclock %s freqmatched %u",
 		  __entry->use_master_clock,
 		  __print_symbolic(__entry->host_clock, host_clocks),
-		  __entry->offset_matched)
+		  __entry->freq_matched)
 );
 
 TRACE_EVENT(kvm_track_tsc,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 32563a91fba99a..2136c1f6803207 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -210,6 +210,10 @@ module_param(pi_inject_timer, bint, 0644);
 static bool __read_mostly mitigate_smt_rsb;
 module_param(mitigate_smt_rsb, bool, 0444);
 
+#ifdef CONFIG_X86_64
+static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
+#endif
+
 #define KVM_SUPPORTED_XCR0     (XFEATURE_MASK_FP | XFEATURE_MASK_SSE \
 				| XFEATURE_MASK_YMM | XFEATURE_MASK_BNDREGS \
 				| XFEATURE_MASK_BNDCSR | XFEATURE_MASK_AVX512 \
@@ -885,60 +889,6 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)
 	       kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending();
 }
 
-#ifdef CONFIG_X86_64
-struct pvclock_clock {
-	int vclock_mode;
-	u64 cycle_last;
-	u64 mask;
-	u32 mult;
-	u32 shift;
-	u64 base_cycles;
-	u64 offset;
-};
-
-struct pvclock_gtod_data {
-	seqcount_t	seq;
-
-	struct pvclock_clock clock; /* extract of a clocksource struct */
-	struct pvclock_clock raw_clock; /* extract of a clocksource struct */
-
-	ktime_t		offs_boot;
-	u64		wall_time_sec;
-};
-
-static struct pvclock_gtod_data pvclock_gtod_data;
-
-static void update_pvclock_gtod(struct timekeeper *tk)
-{
-	struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
-
-	write_seqcount_begin(&vdata->seq);
-
-	/* copy pvclock gtod data */
-	vdata->clock.vclock_mode	= tk->tkr_mono.clock->vdso_clock_mode;
-	vdata->clock.cycle_last		= tk->tkr_mono.cycle_last;
-	vdata->clock.mask		= tk->tkr_mono.mask;
-	vdata->clock.mult		= tk->tkr_mono.mult;
-	vdata->clock.shift		= tk->tkr_mono.shift;
-	vdata->clock.base_cycles	= tk->tkr_mono.xtime_nsec;
-	vdata->clock.offset		= tk->tkr_mono.base;
-
-	vdata->raw_clock.vclock_mode	= tk->tkr_raw.clock->vdso_clock_mode;
-	vdata->raw_clock.cycle_last	= tk->tkr_raw.cycle_last;
-	vdata->raw_clock.mask		= tk->tkr_raw.mask;
-	vdata->raw_clock.mult		= tk->tkr_raw.mult;
-	vdata->raw_clock.shift		= tk->tkr_raw.shift;
-	vdata->raw_clock.base_cycles	= tk->tkr_raw.xtime_nsec;
-	vdata->raw_clock.offset		= tk->tkr_raw.base;
-
-	vdata->wall_time_sec            = tk->xtime_sec;
-
-	vdata->offs_boot		= tk->offs_boot;
-
-	write_seqcount_end(&vdata->seq);
-}
-#endif
-
 static s64 get_kvmclock_base_ns(void)
 {
 	/* Count up from boot time, but with the frequency of the raw clock.  */
@@ -1027,7 +977,7 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 	/* Guest TSC same frequency as host TSC? */
 	if (!scale) {
 		kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio);
-		return 0;
+		goto clear_catchup;
 	}
 
 	/* TSC scaling supported? */
@@ -1053,13 +1003,34 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 	}
 
 	kvm_vcpu_write_tsc_multiplier(vcpu, ratio);
+
+clear_catchup:
+	/*
+	 * A frequency which no longer needs catchup must also stop it: a
+	 * previous above-host-rate setting on scaling-less hardware set
+	 * the always-catchup flags, and nothing else ever clears them.
+	 * Only undo that pairing — tsc_catchup alone also serves the
+	 * unstable-host-TSC compensation in kvm_arch_vcpu_load().
+	 */
+	if (vcpu->arch.tsc_always_catchup) {
+		vcpu->arch.tsc_always_catchup = 0;
+		vcpu->arch.tsc_catchup = 0;
+	}
 	return 0;
 }
 
-static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,
+				   u64 host_tsc, s64 ns, bool user_initiated);
+
+static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)
 {
+	bool freq_changed = (vcpu->arch.virtual_tsc_khz != user_tsc_khz);
 	u32 thresh_lo, thresh_hi;
+	u32 tsc_mult;
+	s8 tsc_shift;
 	int use_scaling = 0;
+	u64 tsc, host_tsc;
+	s64 ns;
 
 	/* tsc_khz can be zero if TSC calibration fails */
 	if (user_tsc_khz == 0) {
@@ -1070,9 +1041,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
 
 	/* Compute a scale to convert nanoseconds in TSC cycles */
 	kvm_get_time_scale(user_tsc_khz * 1000LL, NSEC_PER_SEC,
-			   &vcpu->arch.virtual_tsc_shift,
-			   &vcpu->arch.virtual_tsc_mult);
-	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+			   &tsc_shift, &tsc_mult);
 
 	/*
 	 * Compute the variation in TSC rate which is acceptable
@@ -1087,7 +1056,67 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
 			 user_tsc_khz, thresh_lo, thresh_hi);
 		use_scaling = 1;
 	}
-	return set_tsc_khz(vcpu, user_tsc_khz, use_scaling);
+
+	/*
+	 * Sample the guest TSC before changing the ratio, so continuity
+	 * can be preserved across the change — as a {guest TSC, host
+	 * clock} tuple, not a bare value: the synchronization below
+	 * computes the new offset against the tuple's own reference
+	 * point, so the guest TSC keeps counting through this function
+	 * and any delay here (preemption included) costs nothing.
+	 */
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&ns, &host_tsc))
+#endif
+	{
+		host_tsc = rdtsc();
+		ns = get_kvmclock_base_ns();
+	}
+	tsc = kvm_read_l1_tsc(vcpu, host_tsc);
+
+	if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))
+		return -1;
+
+	/*
+	 * Commit the new frequency only once set_tsc_khz() can no longer
+	 * fail: a failed ioctl must leave no trace, or a retry with the
+	 * still-active frequency would wrongly look like a change.
+	 */
+	vcpu->arch.virtual_tsc_shift = tsc_shift;
+	vcpu->arch.virtual_tsc_mult = tsc_mult;
+	vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+
+	/*
+	 * At vCPU creation (@init) the vCPU is not yet counted in
+	 * online_vcpus, so synchronizing here would corrupt the VM-wide
+	 * matching state (and leave it corrupted if creation subsequently
+	 * fails). The initial synchronization happens in
+	 * kvm_arch_vcpu_postcreate() instead. An unchanged frequency is
+	 * a no-op for synchronization: don't disturb the generation
+	 * tracking of a configured vCPU.
+	 */
+	if (init || !freq_changed)
+		return 0;
+
+	/*
+	 * Changing the frequency changes the vCPU's position on the
+	 * generation's cycle timeline, so re-synchronize. For a vCPU
+	 * which has run, preserve the guest TSC value read above across
+	 * the change; likewise if userspace has written a TSC on this
+	 * vCPU — a zero write would discard it. Otherwise the vCPU holds
+	 * only its creation-time synchronization, so synchronize as for
+	 * a zero write. When the generation is already at the new
+	 * frequency this places the vCPU on its timeline rather than
+	 * opening a gratuitous new generation and orphaning the matched
+	 * state of its siblings; the first vCPU to adopt a new frequency
+	 * necessarily opens a new generation, starting at zero — mixed
+	 * frequencies within a VM forfeit the master clock anyway.
+	 */
+	if (vcpu->arch.last_vmentry_cpu != -1 || vcpu->arch.user_set_tsc)
+		kvm_synchronize_tsc_at(vcpu, &tsc, host_tsc, ns, false);
+	else
+		kvm_synchronize_tsc_at(vcpu, NULL, host_tsc, ns, false);
+	return 0;
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
@@ -1104,42 +1133,97 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 }
 
 #ifdef CONFIG_X86_64
+static int kvm_host_vclock_mode;
+
 static inline bool gtod_is_based_on_tsc(int mode)
 {
 	return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;
 }
-#endif
 
-static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generation)
+static bool kvm_use_master_clock(struct kvm *kvm)
+{
+	struct kvm_arch *ka = &kvm->arch;
+
+	return ka->all_vcpus_matched_freq &&
+		!ka->backwards_tsc_observed;
+}
+
+static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool update_mclock)
 {
-#ifdef CONFIG_X86_64
 	struct kvm_arch *ka = &vcpu->kvm->arch;
-	struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
+	bool prev_matched_tsc = ka->all_vcpus_matched_tsc;
+	bool prev_matched_freq = ka->all_vcpus_matched_freq;
+
+	/*
+	 * Track whether all vCPUs have matching TSC offsets (for
+	 * PVCLOCK_TSC_STABLE_BIT) and matching frequencies (for
+	 * master clock eligibility).
+	 */
+
+	/*
+	 * A new vCPU might already have incremented ->online_vcpus
+	 * and cause a temporary false negative here. But will then
+	 * call kvm_synchronize_tsc() from kvm_arch_vcpu_postcreate()
+	 * and finish the job.
+	 */
+	int online = atomic_read(&vcpu->kvm->online_vcpus);
+	/*
+	 * WRITE_ONCE() pairs with the READ_ONCE() in kvm_guest_time_update(),
+	 * which samples the flag locklessly (outside both tsc_write_lock and
+	 * its pvclock seqcount read section); the race is benign (a stale
+	 * value merely delays the PVCLOCK_TSC_STABLE_BIT broadcast to the
+	 * masterclock update which is requested below).
+	 */
+	WRITE_ONCE(ka->all_vcpus_matched_tsc,
+		   ka->nr_vcpus_matched_tsc >= online);
+
+	update_mclock |= (prev_matched_tsc != ka->all_vcpus_matched_tsc);
+
+	/*
+	 * all_vcpus_matched_freq starts true and is cleared when
+	 * __kvm_synchronize_tsc() detects a frequency mismatch.
+	 * Re-enable when all vCPUs have synced with matching frequency.
+	 * If all offsets also match, that implies frequencies match too.
+	 */
+	if (ka->all_vcpus_matched_tsc ||
+	    ka->nr_vcpus_matched_freq >= online)
+		ka->all_vcpus_matched_freq = true;
+
+	/*
+	 * A frequency-match transition needs a masterclock update too:
+	 * when the last vCPU reaches the new frequency, the masterclock
+	 * scaling factors still describe the old one, and no toggle of
+	 * use_master_clock occurs to trigger the refresh.
+	 */
+	update_mclock |= (prev_matched_freq != ka->all_vcpus_matched_freq);
 
 	/*
 	 * To use the masterclock, the host clocksource must be based on TSC
-	 * and all vCPUs must have matching TSCs.  Note, the count for matching
-	 * vCPUs doesn't include the reference vCPU, hence "+1".
+	 * and all vCPUs must have matching TSC *frequency*. Different offsets
+	 * are fine — each vCPU's pvclock has its own tsc_timestamp that
+	 * accounts for its offset.
 	 */
-	bool use_master_clock = (ka->nr_vcpus_matched_tsc + 1 ==
-				 atomic_read(&vcpu->kvm->online_vcpus)) &&
-				gtod_is_based_on_tsc(gtod->clock.vclock_mode);
+	int host_vclock_mode = READ_ONCE(kvm_host_vclock_mode);
+	bool use_master_clock = kvm_use_master_clock(vcpu->kvm) &&
+				gtod_is_based_on_tsc(host_vclock_mode);
 
 	/*
-	 * Request a masterclock update if the masterclock needs to be toggled
-	 * on/off, or when starting a new generation and the masterclock is
-	 * enabled (compute_guest_tsc() requires the masterclock snapshot to be
-	 * taken _after_ the new generation is created).
+	 * Request a masterclock update if needed: toggling master clock,
+	 * new generation requiring a fresh snapshot, or a change in
+	 * all_vcpus_matched_tsc (to broadcast PVCLOCK_TSC_STABLE_BIT).
 	 */
-	if ((ka->use_master_clock && new_generation) ||
+	if ((ka->use_master_clock && update_mclock) ||
 	    (ka->use_master_clock != use_master_clock))
 		kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 
 	trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc,
 			    atomic_read(&vcpu->kvm->online_vcpus),
-		            ka->use_master_clock, gtod->clock.vclock_mode);
-#endif
+			    ka->use_master_clock, host_vclock_mode);
 }
+#else
+static inline void kvm_track_tsc_matching(struct kvm_vcpu *vcpu,
+					  bool update_mclock) {}
+#endif
 
 /*
  * Multiply tsc by a fixed point number represented by ratio.
@@ -1305,7 +1389,7 @@ static inline bool kvm_check_tsc_unstable(void)
 	 * TSC is marked unstable when we're running on Hyper-V,
 	 * 'TSC page' clocksource is good.
 	 */
-	if (pvclock_gtod_data.clock.vclock_mode == VDSO_CLOCKMODE_HVCLOCK)
+	if (READ_ONCE(kvm_host_vclock_mode) == VDSO_CLOCKMODE_HVCLOCK)
 		return false;
 #endif
 	return check_tsc_unstable();
@@ -1326,21 +1410,55 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
 	if (vcpu->arch.guest_tsc_protected)
 		return;
 
-	if (user_set_tsc)
+	if (user_set_tsc) {
 		vcpu->kvm->arch.user_set_tsc = true;
+		vcpu->arch.user_set_tsc = true;
+	}
 
 	/*
-	 * We also track th most recent recorded KHZ, write and time to
-	 * allow the matching interval to be extended at each write.
+	 * Track the TSC frequency, scaling ratio, and offset for the current
+	 * generation. These are used to detect matching TSC writes and to
+	 * compute the guest TSC from the host clock.
+	 *
+	 * If the frequency changed, master clock mode can no longer be used
+	 * since the kvmclock scaling factors differ between vCPUs.
 	 */
-	kvm->arch.last_tsc_nsec = ns;
-	kvm->arch.last_tsc_write = tsc;
-	kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz;
-	kvm->arch.last_tsc_offset = offset;
-	kvm->arch.last_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
+	if (vcpu->arch.virtual_tsc_khz != kvm->arch.cur_tsc_khz) {
+		kvm->arch.cur_tsc_freq_generation++;
+		kvm->arch.all_vcpus_matched_freq = false;
+		kvm->arch.nr_vcpus_matched_freq = 0;
+	}
+
+	/* Count each vCPU once per freq generation */
+	if (vcpu->arch.this_tsc_freq_generation != kvm->arch.cur_tsc_freq_generation) {
+		vcpu->arch.this_tsc_freq_generation = kvm->arch.cur_tsc_freq_generation;
+		kvm->arch.nr_vcpus_matched_freq++;
+	}
+
+	kvm->arch.cur_tsc_khz = vcpu->arch.virtual_tsc_khz;
+	kvm->arch.cur_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio;
 
 	vcpu->arch.last_guest_tsc = tsc;
 
+	/*
+	 * The offset written below is absolute, superseding any backwards-TSC
+	 * compensation still pending from kvm_arch_enable_virtualization_cpu()
+	 * (which has already been folded into cur_tsc_offset, and thus into
+	 * a matched @offset); applying it again at the next vcpu_load would
+	 * double it.
+	 */
+	vcpu->arch.tsc_offset_adjustment = 0;
+
+	/*
+	 * If the offset changes, the guest-visible pvclock must be
+	 * rewritten before the vCPU runs again: its tsc_timestamp was
+	 * computed with the old offset, and the masterclock (which now
+	 * survives offset changes) will not request the refresh for a
+	 * matched write.
+	 */
+	if (offset != vcpu->arch.l1_tsc_offset)
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+
 	kvm_vcpu_write_tsc_offset(vcpu, offset);
 
 	if (!matched) {
@@ -1350,39 +1468,47 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
 		 * nanosecond time, offset, and write, so if TSCs are in
 		 * sync, we can match exact offset, and if not, we can match
 		 * exact software computation in compute_guest_tsc()
-		 *
-		 * These values are tracked in kvm->arch.cur_xxx variables.
 		 */
 		kvm->arch.cur_tsc_generation++;
+		WRITE_ONCE(kvm->arch.all_vcpus_matched_tsc, false);
+		kvm->arch.nr_vcpus_matched_tsc = 0;
 		kvm->arch.cur_tsc_nsec = ns;
 		kvm->arch.cur_tsc_write = tsc;
 		kvm->arch.cur_tsc_offset = offset;
-		kvm->arch.nr_vcpus_matched_tsc = 0;
-	} else if (vcpu->arch.this_tsc_generation != kvm->arch.cur_tsc_generation) {
+	}
+
+	if (vcpu->arch.this_tsc_generation != kvm->arch.cur_tsc_generation) {
+		vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
 		kvm->arch.nr_vcpus_matched_tsc++;
 	}
 
-	/* Keep track of which generation this VCPU has synchronized to */
-	vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation;
 	vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec;
 	vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write;
 
 	kvm_track_tsc_matching(vcpu, !matched);
 }
 
-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
+/*
+ * Synchronize the vCPU's TSC against an explicit {host_tsc, ns} reference
+ * point: @value (when non-NULL) is the guest TSC *at* @host_tsc, not at
+ * some unspecified "now". The offset is computed against that reference,
+ * so a sampled value stays valid however much time passes between the
+ * sampling and this call.
+ */
+static void kvm_synchronize_tsc_at(struct kvm_vcpu *vcpu, u64 *value,
+				   u64 host_tsc, s64 ns, bool user_initiated)
 {
-	u64 data = user_value ? *user_value : 0;
+	u64 data = value ? *value : 0;
 	struct kvm *kvm = vcpu->kvm;
-	u64 offset, ns, elapsed;
+	u64 offset, elapsed;
 	unsigned long flags;
 	bool matched = false;
 	bool synchronizing = false;
 
 	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-	offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);
-	ns = get_kvmclock_base_ns();
-	elapsed = ns - kvm->arch.last_tsc_nsec;
+
+	offset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);
+	elapsed = ns - kvm->arch.cur_tsc_nsec;
 
 	if (vcpu->arch.virtual_tsc_khz) {
 		if (data == 0) {
@@ -1392,9 +1518,10 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 			 */
 			synchronizing = true;
 		} else if (kvm->arch.user_set_tsc) {
-			u64 tsc_exp = kvm->arch.last_tsc_write +
+			u64 tsc_exp = kvm->arch.cur_tsc_write +
 						nsec_to_cycles(vcpu, elapsed);
 			u64 tsc_hz = vcpu->arch.virtual_tsc_khz * 1000LL;
+			u64 window;
 			/*
 			 * Here lies UAPI baggage: when a user-initiated TSC write has
 			 * a small delta (1 second) of virtual cycle time against the
@@ -1409,9 +1536,18 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 			 * to this 'correction' to make it sync up with values that only
 			 * come from the kernel's default vCPU creation. Make the 1-second
 			 * slop hack only trigger if the user_set_tsc flag is already set.
+			 *
+			 * A kernel-internal write (a frequency change preserving the
+			 * guest TSC) carries an exact value sampled with its own
+			 * reference point, not a racy userspace one; a vCPU on the
+			 * generation's line still matches it to within arithmetic
+			 * rounding, but one which genuinely diverged (e.g. by a guest
+			 * TSC_ADJUST write) must not be snapped back by up to a
+			 * second. Use a 1ms window for those.
 			 */
-			synchronizing = data < tsc_exp + tsc_hz &&
-					data + tsc_hz > tsc_exp;
+			window = user_initiated ? tsc_hz : tsc_hz / 1000;
+			synchronizing = data < tsc_exp + window &&
+					data + window > tsc_exp;
 		}
 	}
 
@@ -1423,21 +1559,52 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
 	 * it's better to try to match offsets from the beginning.
          */
 	if (synchronizing &&
-	    vcpu->arch.virtual_tsc_khz == kvm->arch.last_tsc_khz) {
-		if (!kvm_check_tsc_unstable()) {
+	    vcpu->arch.virtual_tsc_khz == kvm->arch.cur_tsc_khz) {
+		/*
+		 * If synchronizing, extrapolate the generation's value to
+		 * "now": the matching window slides forward with wall time,
+		 * anchored on the generation's origin alone (a matched
+		 * write no longer updates any stored reference point).
+		 */
+		u64 delta = nsec_to_cycles(vcpu, elapsed);
+
+		data = kvm->arch.cur_tsc_write + delta;
+
+		/*
+		 * The generation's offset can be reused directly: it is in
+		 * this vCPU's scaling domain, because every generation is
+		 * opened by a vCPU (the initial VM-creation generation is
+		 * not matchable) and set_tsc_khz() derives the scaling
+		 * ratio deterministically from the kHz value, so two vCPUs
+		 * at the same frequency carry the same ratio.
+		 */
+		if (!kvm_check_tsc_unstable())
 			offset = kvm->arch.cur_tsc_offset;
-		} else {
-			u64 delta = nsec_to_cycles(vcpu, elapsed);
-			data += delta;
-			offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data);
-		}
+		else
+			offset = kvm_compute_l1_tsc_offset(vcpu, host_tsc, data);
 		matched = true;
 	}
 
-	__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, !!user_value);
+	__kvm_synchronize_tsc(vcpu, offset, data, ns, matched, user_initiated);
 	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 }
 
+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)
+{
+	u64 host_tsc;
+	s64 ns;
+
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&ns, &host_tsc))
+#endif
+	{
+		host_tsc = rdtsc();
+		ns = get_kvmclock_base_ns();
+	}
+
+	kvm_synchronize_tsc_at(vcpu, value, host_tsc, ns, user_initiated);
+}
+
 #ifdef CONFIG_X86_64
 
 static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap,
@@ -1564,12 +1731,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 {
 #ifdef CONFIG_X86_64
 	struct kvm_arch *ka = &kvm->arch;
-	int vclock_mode;
-	bool host_tsc_clocksource, vcpus_matched;
+	bool host_tsc_clocksource;
 
 	lockdep_assert_held(&kvm->arch.tsc_write_lock);
-	vcpus_matched = (ka->nr_vcpus_matched_tsc + 1 ==
-			atomic_read(&kvm->online_vcpus));
 
 	/*
 	 * If the host uses TSC clock, then passthrough TSC as stable
@@ -1579,9 +1743,8 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 					&ka->master_kernel_ns,
 					&ka->master_cycle_now);
 
-	ka->use_master_clock = host_tsc_clocksource && vcpus_matched
-				&& !ka->backwards_tsc_observed
-				&& !ka->boot_vcpu_runs_old_kvmclock;
+	ka->use_master_clock = host_tsc_clocksource &&
+				kvm_use_master_clock(kvm);
 
 	if (ka->use_master_clock) {
 		u64 tsc_hz;
@@ -1594,7 +1757,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 		 * get_kvmclock() to compute kvmclock from the host TSC
 		 * without needing a vCPU reference.
 		 */
-		ka->master_tsc_scaling_ratio = ka->last_tsc_scaling_ratio;
+		ka->master_tsc_scaling_ratio = ka->cur_tsc_scaling_ratio;
 		tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;
 		if (tsc_hz && kvm_caps.has_tsc_control)
 			tsc_hz = kvm_scale_tsc(tsc_hz,
@@ -1607,9 +1770,9 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
 			ka->use_master_clock = false;
 	}
 
-	vclock_mode = pvclock_gtod_data.clock.vclock_mode;
-	trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode,
-					vcpus_matched);
+	trace_kvm_update_master_clock(ka->use_master_clock,
+				      READ_ONCE(kvm_host_vclock_mode),
+				      ka->all_vcpus_matched_freq);
 #endif
 }
 
@@ -1618,10 +1781,51 @@ static void kvm_make_mclock_inprogress_request(struct kvm *kvm)
 	kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
 }
 
-static void __kvm_start_pvclock_update(struct kvm *kvm)
+static void kvm_clear_mclock_inprogress_request(struct kvm *kvm)
+{
+	struct kvm_vcpu *vcpu;
+	unsigned long i;
+
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);
+}
+
+static bool __kvm_start_pvclock_update(struct kvm *kvm, struct kvm_vcpu *requesting_vcpu)
 {
+	struct kvm_vcpu *vcpu;
+	unsigned long i;
+
 	raw_spin_lock_irq(&kvm->arch.tsc_write_lock);
+
+	/*
+	 * If another vCPU already did the update while we were waiting
+	 * for the lock, our request will have been cleared. Bail out,
+	 * clearing the KVM_REQ_MCLOCK_INPROGRESS kicks made on entry to
+	 * kvm_update_masterclock() so vCPUs can enter the guest again.
+	 *
+	 * Clearing them VM-wide can also clear kicks just made by yet
+	 * another updater still waiting for tsc_write_lock, letting
+	 * vCPUs run while that update is in flight. That is not new:
+	 * kvm_end_pvclock_update() has always cleared the request on
+	 * every vCPU regardless of which updater made it. The window is
+	 * harmless to readers (the pvclock seqcount covers the master
+	 * state); a vCPU which slips in runs on the old snapshot until
+	 * its KVM_REQ_CLOCK_UPDATE is serviced, exactly as if it had
+	 * entered just before the update began.
+	 */
+	if (requesting_vcpu &&
+	    !kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, requesting_vcpu)) {
+		kvm_clear_mclock_inprogress_request(kvm);
+		raw_spin_unlock_irq(&kvm->arch.tsc_write_lock);
+		return false;
+	}
+
+	/* The update is VM-wide; prevent other vCPUs from redoing it. */
+	kvm_for_each_vcpu(i, vcpu, kvm)
+		kvm_clear_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
+
 	write_seqcount_begin(&kvm->arch.pvclock_sc);
+	return true;
 }
 
 static void kvm_start_pvclock_update(struct kvm *kvm)
@@ -1629,7 +1833,7 @@ static void kvm_start_pvclock_update(struct kvm *kvm)
 	kvm_make_mclock_inprogress_request(kvm);
 
 	/* no guest entries from this point */
-	__kvm_start_pvclock_update(kvm);
+	__kvm_start_pvclock_update(kvm, NULL);
 }
 
 static void kvm_end_pvclock_update(struct kvm *kvm)
@@ -1638,22 +1842,35 @@ static void kvm_end_pvclock_update(struct kvm *kvm)
 	struct kvm_vcpu *vcpu;
 	unsigned long i;
 
-	write_seqcount_end(&ka->pvclock_sc);
-	raw_spin_unlock_irq(&ka->tsc_write_lock);
 	kvm_for_each_vcpu(i, vcpu, kvm)
 		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
 	/* guest entries allowed */
-	kvm_for_each_vcpu(i, vcpu, kvm)
-		kvm_clear_request(KVM_REQ_MCLOCK_INPROGRESS, vcpu);
+	kvm_clear_mclock_inprogress_request(kvm);
+
+	write_seqcount_end(&ka->pvclock_sc);
+	raw_spin_unlock_irq(&ka->tsc_write_lock);
 }
 
-static void kvm_update_masterclock(struct kvm *kvm)
+static void kvm_update_masterclock(struct kvm *kvm, struct kvm_vcpu *vcpu)
 {
+	/*
+	 * The Hyper-V TSC page request is made before the dedupe check
+	 * in __kvm_start_pvclock_update() because it takes a mutex and
+	 * so cannot sit inside the tsc_write_lock critical section where
+	 * the winning updater is known. A losing vCPU may therefore mark
+	 * the page HOST_CHANGED after the winner has already rewritten
+	 * it; the next clock update then rewrites the page again with
+	 * the same contents, which the TSC-page sequence protocol makes
+	 * safe against concurrently running guests.
+	 */
 	kvm_hv_request_tsc_page_update(kvm);
-	kvm_start_pvclock_update(kvm);
-	pvclock_update_vm_gtod_copy(kvm);
-	kvm_end_pvclock_update(kvm);
+	kvm_make_mclock_inprogress_request(kvm);
+
+	if (__kvm_start_pvclock_update(kvm, vcpu)) {
+		pvclock_update_vm_gtod_copy(kvm);
+		kvm_end_pvclock_update(kvm);
+	}
 }
 
 /*
@@ -1680,6 +1897,7 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 	struct kvm_arch *ka = &kvm->arch;
 	struct pvclock_vcpu_time_info hv_clock;
 	struct timespec64 ts;
+	u64 clock;
 
 	if (!ka->use_master_clock)
 		return false;
@@ -1687,10 +1905,6 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 	if (!kvm_get_walltime_and_clockread(&ts, &data->host_tsc))
 		return false;
 
-	data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;
-	data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |
-		       KVM_CLOCK_TSC_STABLE;
-
 	hv_clock.tsc_timestamp = ka->master_cycle_now;
 	hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
 
@@ -1705,13 +1919,34 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm,
 		u64 tsc_delta = data->host_tsc - ka->master_cycle_now;
 
 		tsc_delta = kvm_scale_tsc(tsc_delta, ka->master_tsc_scaling_ratio);
-		data->clock = hv_clock.system_time +
-			      pvclock_scale_delta(tsc_delta,
-						  hv_clock.tsc_to_system_mul,
-						  hv_clock.tsc_shift);
+		clock = hv_clock.system_time +
+			pvclock_scale_delta(tsc_delta,
+					    hv_clock.tsc_to_system_mul,
+					    hv_clock.tsc_shift);
 	} else {
-		data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc);
+		clock = __pvclock_read_cycles(&hv_clock, data->host_tsc);
 	}
+
+	/*
+	 * Sanity-check the snapshot: if the elapsed time it computes from
+	 * the host TSC disagrees with the raw clock by more than a second,
+	 * the TSC was reset (suspend/resume — possibly re-inited by
+	 * firmware to an arbitrary value, including an underflowing one
+	 * below master_cycle_now) while nothing refreshed the snapshot.
+	 * That can happen while the VM has no vCPUs, since both the
+	 * resume compensation and the clocksource notifier work through
+	 * vCPUs. Use the fallback clock rather than returning a
+	 * discontinuity flagged KVM_CLOCK_TSC_STABLE.
+	 */
+	if (unlikely(abs((s64)(clock - hv_clock.system_time) -
+			 (get_kvmclock_base_ns() - ka->master_kernel_ns)) >
+		     NSEC_PER_SEC))
+		return false;
+
+	data->clock = clock;
+	data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec;
+	data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC |
+		       KVM_CLOCK_TSC_STABLE;
 	return true;
 #else
 	return false;
@@ -1897,7 +2132,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v)
 
 	/* If the host uses TSC clocksource, then it is stable */
 	hv_clock.flags = 0;
-	if (use_master_clock)
+	if (use_master_clock && READ_ONCE(ka->all_vcpus_matched_tsc))
 		hv_clock.flags |= PVCLOCK_TSC_STABLE_BIT;
 
 	if (vcpu->pv_time.active) {
@@ -2294,6 +2529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_MEMORY_FAULT_INFO:
 	case KVM_CAP_X86_GUEST_MODE:
 	case KVM_CAP_ONE_REG:
+#ifdef CONFIG_X86_64
+	case KVM_CAP_CLOCK_GUEST:
+#endif
 		r = 1;
 		break;
 	case KVM_CAP_PRE_FAULT_MEMORY:
@@ -2608,11 +2846,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		 * On a host with synchronized TSC, there is no need to update
 		 * kvmclock on vcpu->cpu migration
 		 */
-		if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1) {
+		if (!vcpu->kvm->arch.use_master_clock) {
 			if (__ratelimit(&vcpu->kvm->arch.kvmclock_update_rs))
 				kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
 			else
 				kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+		} else if (vcpu->cpu == -1) {
+			kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 		}
 
 		if (vcpu->cpu != cpu)
@@ -3276,6 +3516,9 @@ static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu,
 	case KVM_VCPU_TSC_OFFSET:
 		r = 0;
 		break;
+	case KVM_VCPU_TSC_SCALE:
+		r = kvm_caps.has_tsc_control ? 0 : -ENXIO;
+		break;
 	default:
 		r = -ENXIO;
 	}
@@ -3296,6 +3539,21 @@ static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu,
 			break;
 		r = 0;
 		break;
+	case KVM_VCPU_TSC_SCALE: {
+		struct kvm_vcpu_tsc_scale scale;
+
+		r = -ENXIO;
+		if (!kvm_caps.has_tsc_control)
+			break;
+
+		scale.tsc_ratio = vcpu->arch.l1_tsc_scaling_ratio;
+		scale.tsc_frac_bits = kvm_caps.tsc_scaling_ratio_frac_bits;
+		r = -EFAULT;
+		if (copy_to_user(uaddr, &scale, sizeof(scale)))
+			break;
+		r = 0;
+		break;
+	}
 	default:
 		r = -ENXIO;
 	}
@@ -3323,8 +3581,8 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
 		raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
 
 		matched = (vcpu->arch.virtual_tsc_khz &&
-			   kvm->arch.last_tsc_khz == vcpu->arch.virtual_tsc_khz &&
-			   kvm->arch.last_tsc_offset == offset);
+			   kvm->arch.cur_tsc_khz == vcpu->arch.virtual_tsc_khz &&
+			   kvm->arch.cur_tsc_offset == offset);
 
 		tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset;
 		ns = get_kvmclock_base_ns();
@@ -3335,6 +3593,9 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,
 		r = 0;
 		break;
 	}
+	case KVM_VCPU_TSC_SCALE:
+		r = kvm_caps.has_tsc_control ? -EINVAL : -ENXIO;
+		break;
 	default:
 		r = -ENXIO;
 	}
@@ -3424,6 +3685,197 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
 	}
 }
 
+#ifdef CONFIG_X86_64
+static int kvm_vcpu_ioctl_get_clock_guest(struct kvm_vcpu *v, void __user *argp)
+{
+	struct pvclock_vcpu_time_info hv_clock = {};
+	struct kvm_arch *ka = &v->kvm->arch;
+	bool use_master_clock;
+	unsigned int seq;
+
+	/*
+	 * Construct the pvclock purely from the master clock state. The
+	 * master mul/shift are computed for the guest TSC frequency, which
+	 * in master clock mode is the frequency of every vCPU; only the
+	 * tsc_timestamp is per-vCPU, translating the master snapshot into
+	 * this vCPU's TSC domain via its scaling ratio and offset.
+	 *
+	 * Note, this deliberately does NOT invoke kvm_guest_time_update(),
+	 * which would write the guest's pvclock pages: dirtying guest
+	 * memory after the final KVM_RUN would break post-copy migration
+	 * flows. The pvclock returned here describes the same clock as the
+	 * guest-visible copy (the same linear function of the guest TSC),
+	 * anchored at the current master clock snapshot.
+	 *
+	 * Translating the snapshot through the vCPU's *current* scaling
+	 * ratio and offset is correct even if they changed after the
+	 * snapshot was taken: the snapshot anchors a host TSC value, not
+	 * a guest one. A frequency change whose masterclock update is
+	 * still pending does leave stale mul/shift here, but that is the
+	 * paused-VM migration path reading a frequency userspace itself
+	 * has just changed — and the result fails safe, as the same-vCPU
+	 * KVM_SET_CLOCK_GUEST on the destination rejects a mul/shift
+	 * inconsistent with the vCPU's frequency with -ERANGE.
+	 */
+	do {
+		seq = read_seqcount_begin(&ka->pvclock_sc);
+
+		use_master_clock = ka->use_master_clock;
+		if (!use_master_clock)
+			continue;
+
+		hv_clock.tsc_timestamp = kvm_read_l1_tsc(v, ka->master_cycle_now);
+		hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset;
+		hv_clock.tsc_shift = ka->master_tsc_shift;
+		hv_clock.tsc_to_system_mul = ka->master_tsc_mul;
+		hv_clock.flags = READ_ONCE(ka->all_vcpus_matched_tsc) ?
+				 PVCLOCK_TSC_STABLE_BIT : 0;
+	} while (read_seqcount_retry(&ka->pvclock_sc, seq));
+
+	if (!use_master_clock)
+		return -ENODATA;
+
+	if (copy_to_user(argp, &hv_clock, sizeof(hv_clock)))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Reverse the calculation in the hv_clock definition.
+ *
+ * time_ns = ( (cycles << shift) * mul ) >> 32;
+ * (although shift can be negative, so that's bad C)
+ *
+ * So for a single second,
+ * NSEC_PER_SEC = ( ( FREQ_HZ << shift) * mul ) >> 32
+ * NSEC_PER_SEC << 32 = ( FREQ_HZ << shift ) * mul
+ * ( NSEC_PER_SEC << 32 ) / mul = FREQ_HZ << shift
+ * ( NSEC_PER_SEC << 32 ) / mul ) >> shift = FREQ_HZ
+ */
+static u64 hvclock_to_hz(u32 mul, s8 shift)
+{
+	u64 tm = NSEC_PER_SEC << 32;
+
+	/* Maximise precision. Shift left until the top bit is set */
+	tm <<= 2;
+	shift += 2;
+
+	/* While 'mul' is even, increase the shift *after* the division */
+	while (!(mul & 1)) {
+		shift++;
+		mul >>= 1;
+	}
+
+	tm /= mul;
+
+	if (shift >= 64)
+		return 0;
+	if (shift > 0)
+		return tm >> shift;
+
+	/*
+	 * A left shift can overflow for absurd user-supplied mul/shift
+	 * combinations; saturate (to a value which cannot itself overflow
+	 * the rounding in the caller's kHz conversion) so the frequency
+	 * check certainly rejects them.
+	 */
+	if (shift <= -64 || tm > (U64_MAX >> 1) >> -shift)
+		return U64_MAX >> 1;
+	return tm << -shift;
+}
+
+static int kvm_vcpu_ioctl_set_clock_guest(struct kvm_vcpu *v, void __user *argp)
+{
+	struct pvclock_vcpu_time_info user_hv_clock;
+	struct kvm *kvm = v->kvm;
+	struct kvm_arch *ka = &kvm->arch;
+	u64 curr_tsc_hz, user_tsc_hz;
+	u64 curr_tsc_khz, user_tsc_khz;
+	u64 user_clk_ns;
+	u64 guest_tsc;
+	int rc = 0;
+
+	if (copy_from_user(&user_hv_clock, argp, sizeof(user_hv_clock)))
+		return -EFAULT;
+
+	if (user_hv_clock.pad0 || user_hv_clock.pad[0] || user_hv_clock.pad[1])
+		return -EINVAL;
+
+	if (!user_hv_clock.tsc_to_system_mul)
+		return -EINVAL;
+
+	if (user_hv_clock.tsc_shift < -31 || user_hv_clock.tsc_shift > 31)
+		return -EINVAL;
+
+	user_tsc_hz = hvclock_to_hz(user_hv_clock.tsc_to_system_mul,
+				    user_hv_clock.tsc_shift);
+
+	kvm_hv_request_tsc_page_update(kvm);
+
+	/*
+	 * kvm_start_pvclock_update() takes tsc_write_lock and opens
+	 * the pvclock seqcount; kvm_end_pvclock_update() closes both.
+	 * All clock state modifications between them are atomic with
+	 * respect to readers in kvm_guest_time_update().
+	 */
+	kvm_start_pvclock_update(kvm);
+	pvclock_update_vm_gtod_copy(kvm);
+
+	if (!ka->use_master_clock) {
+		rc = -ENODATA;
+		goto out;
+	}
+
+	/*
+	 * Nonzero, or pvclock_update_vm_gtod_copy() — which read it on
+	 * this CPU, with interrupts still disabled — would have cleared
+	 * use_master_clock above.
+	 */
+	curr_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ;
+
+	if (kvm_caps.has_tsc_control)
+		curr_tsc_hz = kvm_scale_tsc(curr_tsc_hz,
+					    v->arch.l1_tsc_scaling_ratio);
+
+	/*
+	 * The mul/shift in the provided pvclock structure encode the guest
+	 * TSC frequency at which it was generated. Sanity-check that it is
+	 * consistent with this vCPU's effective TSC frequency, allowing a
+	 * discrepancy of 1 kHz either way since independently calibrated
+	 * hosts will not measure precisely the same value even for the
+	 * same nominal frequency. Compare in kHz: the reconstruction of
+	 * each side's frequency in Hz carries a few Hz of rounding, which
+	 * must not push two hosts calibrated exactly 1 kHz apart over the
+	 * line.
+	 */
+	user_tsc_khz = DIV_ROUND_CLOSEST_ULL(user_tsc_hz, HZ_PER_KHZ);
+	curr_tsc_khz = DIV_ROUND_CLOSEST_ULL(curr_tsc_hz, HZ_PER_KHZ);
+	if (user_tsc_khz + 1 < curr_tsc_khz ||
+	    user_tsc_khz > curr_tsc_khz + 1) {
+		rc = -ERANGE;
+		goto out;
+	}
+
+	/*
+	 * Calculate the guest TSC at the new reference point, and the
+	 * corresponding KVM clock value according to user_hv_clock.
+	 * Adjust kvmclock_offset so both definitions agree.
+	 */
+	guest_tsc = kvm_read_l1_tsc(v, ka->master_cycle_now);
+	if ((s64)(guest_tsc - user_hv_clock.tsc_timestamp) < 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+	user_clk_ns = __pvclock_read_cycles(&user_hv_clock, guest_tsc);
+	ka->kvmclock_offset = user_clk_ns - ka->master_kernel_ns;
+
+out:
+	kvm_end_pvclock_update(kvm);
+	return rc;
+}
+#endif
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
 			 unsigned int ioctl, unsigned long arg)
 {
@@ -3734,7 +4186,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		if (user_tsc_khz == 0)
 			user_tsc_khz = tsc_khz;
 
-		if (!kvm_set_tsc_khz(vcpu, user_tsc_khz))
+		if (!kvm_set_tsc_khz(vcpu, user_tsc_khz, false))
 			r = 0;
 
 		goto out;
@@ -3817,6 +4269,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
 		break;
 	}
+#ifdef CONFIG_X86_64
+	case KVM_SET_CLOCK_GUEST:
+		r = kvm_vcpu_ioctl_set_clock_guest(vcpu, argp);
+		break;
+	case KVM_GET_CLOCK_GUEST:
+		r = kvm_vcpu_ioctl_get_clock_guest(vcpu, argp);
+		break;
+#endif
 #ifdef CONFIG_KVM_HYPERV
 	case KVM_GET_SUPPORTED_HV_CPUID:
 		r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
@@ -4382,19 +4842,45 @@ static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp)
 	 * 'system_time' when 'data.clock' is very small.
 	 */
 	if (data.flags & KVM_CLOCK_REALTIME) {
-		u64 now_real_ns = ktime_get_real_ns();
+		struct system_time_snapshot snap = {};
+		u64 now_real_ns;
+
+		/*
+		 * Snapshot CLOCK_REALTIME and CLOCK_MONOTONIC_RAW at the
+		 * same instant, so that the elapsed time applied to
+		 * data.clock and the reference point the result is anchored
+		 * to are coherent.
+		 */
+		ktime_get_snapshot_id(CLOCK_REALTIME, &snap);
+		now_real_ns = ktime_to_ns(snap.systime);
+		now_raw_ns = ktime_to_ns(ktime_mono_to_any(snap.monoraw,
+							   TK_OFFS_BOOT));
+
+		/*
+		 * When the master clock is in use, anchor at its reference
+		 * point instead, projecting the realtime value back to the
+		 * same instant. The two clocks tick at the same rate across
+		 * the few ns in between, give or take NTP slew. Skip the
+		 * projection in the absurd case that it would take a
+		 * CLOCK_REALTIME set to within moments of the 1970 epoch
+		 * (legal with CAP_SYS_TIME) below zero and wrap.
+		 */
+		if (ka->use_master_clock &&
+		    now_real_ns >= now_raw_ns - ka->master_kernel_ns) {
+			now_real_ns -= now_raw_ns - ka->master_kernel_ns;
+			now_raw_ns = ka->master_kernel_ns;
+		}
 
 		/*
 		 * Avoid stepping the kvmclock backwards.
 		 */
 		if (now_real_ns > data.realtime)
 			data.clock += now_real_ns - data.realtime;
-	}
-
-	if (ka->use_master_clock)
+	} else if (ka->use_master_clock) {
 		now_raw_ns = ka->master_kernel_ns;
-	else
+	} else {
 		now_raw_ns = get_kvmclock_base_ns();
+	}
 	ka->kvmclock_offset = data.clock - now_raw_ns;
 	kvm_end_pvclock_update(kvm);
 	return 0;
@@ -6752,7 +7238,14 @@ static void kvm_hyperv_tsc_notifier(void)
 	kvm_caps.max_guest_tsc_khz = tsc_khz;
 
 	list_for_each_entry(kvm, &vm_list, vm_list) {
-		__kvm_start_pvclock_update(kvm);
+		/*
+		 * Invalidate the Hyper-V TSC page explicitly: the update
+		 * below consumes any pending KVM_REQ_MASTERCLOCK_UPDATE,
+		 * which would otherwise have refreshed the page from
+		 * kvm_update_masterclock().
+		 */
+		kvm_hv_request_tsc_page_update(kvm);
+		__kvm_start_pvclock_update(kvm, NULL);
 		pvclock_update_vm_gtod_copy(kvm);
 		kvm_end_pvclock_update(kvm);
 	}
@@ -6926,17 +7419,21 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);
 static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,
 			       void *priv)
 {
-	struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
 	struct timekeeper *tk = priv;
 
-	update_pvclock_gtod(tk);
+	/*
+	 * Pairs with the READ_ONCE() in the lockless readers; the race is
+	 * benign by design, relying on eventual consistency (the notifier
+	 * fires on every timekeeping update).
+	 */
+	WRITE_ONCE(kvm_host_vclock_mode, tk->tkr_mono.clock->vdso_clock_mode);
 
 	/*
 	 * Disable master clock if host does not trust, or does not use,
 	 * TSC based clocksource. Delegate queue_work() to irq_work as
 	 * this is invoked with tk_core.seq write held.
 	 */
-	if (!gtod_is_based_on_tsc(gtod->clock.vclock_mode) &&
+	if (!gtod_is_based_on_tsc(kvm_host_vclock_mode) &&
 	    atomic_read(&kvm_guest_has_master_clock) != 0)
 		irq_work_queue(&pvclock_irq_work);
 	return 0;
@@ -8158,8 +8655,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 			kvm_mmu_free_obsolete_roots(vcpu);
 		if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
 			__kvm_migrate_timers(vcpu);
-		if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
-			kvm_update_masterclock(vcpu->kvm);
+		if (kvm_test_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
+			kvm_update_masterclock(vcpu->kvm, vcpu);
 		if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
 			kvm_gen_kvmclock_update(vcpu);
 		if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
@@ -9502,7 +9999,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 	kvm_xen_init_vcpu(vcpu);
 	vcpu_load(vcpu);
 	kvm_vcpu_after_set_cpuid(vcpu);
-	kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz);
+	kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz, true);
 	kvm_vcpu_reset(vcpu, false);
 	kvm_init_mmu(vcpu);
 	vcpu_put(vcpu);
@@ -9527,12 +10024,39 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 {
-	if (mutex_lock_killable(&vcpu->mutex))
+	if (mutex_lock_killable(&vcpu->mutex)) {
+		/*
+		 * The new vCPU is already counted in online_vcpus but has
+		 * not been synchronized. Nothing recomputes the cached
+		 * matched state against the raised count until the next
+		 * synchronization, so clear it here rather than leave the
+		 * clock advertised as matched while an unmatched vCPU is
+		 * runnable. It heals when this vCPU first synchronizes.
+		 */
+		struct kvm_arch *ka = &vcpu->kvm->arch;
+		unsigned long flags;
+
+		raw_spin_lock_irqsave(&ka->tsc_write_lock, flags);
+		WRITE_ONCE(ka->all_vcpus_matched_tsc, false);
+		ka->all_vcpus_matched_freq = false;
+		raw_spin_unlock_irqrestore(&ka->tsc_write_lock, flags);
 		return;
+	}
 	vcpu_load(vcpu);
-	kvm_synchronize_tsc(vcpu, NULL);
-	if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
-		kvm_update_masterclock(vcpu->kvm);
+	kvm_synchronize_tsc(vcpu, NULL, false);
+
+	/*
+	 * Refresh the VM-creation masterclock snapshot (see
+	 * kvm_arch_init_vm), synchronously so that it is valid even for
+	 * userspace which queries the clock before ever running a vCPU.
+	 * Likewise service any masterclock update the synchronization
+	 * above requested on this vCPU, which would otherwise languish
+	 * until it first enters the guest.
+	 */
+	if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu) ||
+	    vcpu->vcpu_idx == 0)
+		kvm_update_masterclock(vcpu->kvm, NULL);
+
 	vcpu_put(vcpu);
 
 	/* poll control enabled by default */
@@ -9782,7 +10306,7 @@ int kvm_arch_enable_virtualization_cpu(void)
 {
 	struct kvm *kvm;
 	struct kvm_vcpu *vcpu;
-	unsigned long i;
+	unsigned long i, flags;
 	int ret;
 	u64 local_tsc;
 	u64 max_tsc = 0;
@@ -9853,6 +10377,44 @@ int kvm_arch_enable_virtualization_cpu(void)
 	if (backwards_tsc) {
 		u64 delta_cyc = max_tsc - local_tsc;
 		list_for_each_entry(kvm, &vm_list, vm_list) {
+			/*
+			 * Hold tsc_write_lock across the per-vCPU adjustments
+			 * AND the generation reference offset adjustment, so
+			 * that a concurrent TSC synchronization cannot observe
+			 * one without the other (it would compute an offset
+			 * with the delta applied twice, or not at all). The
+			 * consume of tsc_offset_adjustment in
+			 * kvm_arch_vcpu_load() remains outside the lock, as
+			 * it always was; its races are with vcpu_put/load
+			 * ordering, not with the generation state.
+			 *
+			 * The generation's reference offset is adjusted by the
+			 * same (guest-scaled, as adjust_tsc_offset_host()
+			 * does for each vCPU) delta, so that future
+			 * KVM_SET_TSC / vCPU creation still matches against
+			 * the adjusted TSC timeline.
+			 *
+			 * The recorded {cur_tsc_nsec, cur_tsc_write} pair is
+			 * left alone, and ends up stale by the sleep period:
+			 * cur_tsc_nsec is CLOCK_BOOTTIME, which has the sleep
+			 * injected on resume, while the guest TSC (kept
+			 * continuous across the host TSC jump) does not
+			 * advance during the sleep. It cannot be re-anchored
+			 * here because, as noted above, timekeeping has not
+			 * yet been resumed. The 1-second matching window
+			 * therefore fails to match across a longer sleep,
+			 * and the next nonzero TSC write opens a fresh,
+			 * coherent generation. A forced synchronization
+			 * (vCPU creation, or a zero write) bypasses the
+			 * window and does extrapolate along the stale line,
+			 * overshooting by the sleep period — but it installs
+			 * the compensated offset, so the vCPU's actual TSC
+			 * is correct; only last_guest_tsc overshoots, which
+			 * matters only if the TSC turns unstable before the
+			 * vCPU first enters the guest, exactly as it did
+			 * before this accounting existed.
+			 */
+			raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
 			kvm->arch.backwards_tsc_observed = true;
 			kvm_for_each_vcpu(i, vcpu, kvm) {
 				vcpu->arch.tsc_offset_adjustment += delta_cyc;
@@ -9860,14 +10422,10 @@ int kvm_arch_enable_virtualization_cpu(void)
 				kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
 			}
 
-			/*
-			 * We have to disable TSC offset matching.. if you were
-			 * booting a VM while issuing an S4 host suspend....
-			 * you may have some problem.  Solving this issue is
-			 * left as an exercise to the reader.
-			 */
-			kvm->arch.last_tsc_nsec = 0;
-			kvm->arch.last_tsc_write = 0;
+			kvm->arch.cur_tsc_offset +=
+				kvm_scale_tsc(delta_cyc,
+					      kvm->arch.cur_tsc_scaling_ratio);
+			raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 		}
 
 	}
@@ -9937,6 +10495,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 {
 	int ret;
 	unsigned long flags;
+	u64 kvmclock_host_tsc;
+	s64 kvmclock_ns;
 
 	if (!kvm_is_vm_type_supported(type))
 		return -EINVAL;
@@ -9968,17 +10528,68 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc, &kvm->arch.tsc_write_lock);
 	ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10);
 	ratelimit_set_flags(&kvm->arch.kvmclock_update_rs, RATELIMIT_MSG_ON_RELEASE);
-	kvm->arch.kvmclock_offset = -get_kvmclock_base_ns();
-
-	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-	pvclock_update_vm_gtod_copy(kvm);
-	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
 
 	kvm->arch.default_tsc_khz = max_tsc_khz ? : tsc_khz;
 	kvm->arch.apic_bus_cycle_ns = APIC_BUS_CYCLE_NS_DEFAULT;
 	kvm->arch.guest_can_read_msr_platform_info = true;
 	kvm->arch.enable_pmu = enable_pmu && !kvm->arch.has_protected_pmu;
 
+	kvm->arch.all_vcpus_matched_freq = true;
+	/*
+	 * Start with all (zero) vCPUs considered matched, so that a VM whose
+	 * vCPUs never reach kvm_track_tsc_matching() — notably when the guest
+	 * TSC is protected (TDX, SNP Secure TSC) and __kvm_synchronize_tsc()
+	 * returns early — is still eligible for PVCLOCK_TSC_STABLE_BIT. The
+	 * scaling ratio must then also be initialized: with vcpus_matched
+	 * now true here, pvclock_update_vm_gtod_copy() reaches the scaling
+	 * path, and a zero ratio would zero tsc_hz and turn the master
+	 * clock straight back off (permanently so for protected-TSC guests,
+	 * which never write the ratio in __kvm_synchronize_tsc()).
+	 */
+	kvm->arch.all_vcpus_matched_tsc = true;
+	kvm->arch.cur_tsc_scaling_ratio = kvm_caps.default_tsc_scaling_ratio;
+
+	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
+
+	/*
+	 * Establish an initial TSC generation so that the master clock
+	 * snapshot taken below is immediately valid and KVM_GET_CLOCK
+	 * works before any vCPU exists. The snapshot is refreshed again
+	 * when the first vCPU is created, in case the host clocksource
+	 * changed (and changed back) in between: pvclock_gtod_update_fn()
+	 * does not notify a VM with no vCPUs.
+	 *
+	 * This generation is deliberately not matchable: cur_tsc_khz is
+	 * left at zero, which no vCPU frequency ever equals, so the first
+	 * vCPU opens its own generation with its TSC starting at zero,
+	 * exactly as it always has. Letting it match would make the first
+	 * vCPU's TSC start at the cycles elapsed since KVM_CREATE_VM — a
+	 * silent guest-visible change over an unbounded window — and
+	 * would hand it this offset verbatim even when a host suspend
+	 * reset the TSC in between, since the backwards-TSC compensation
+	 * in kvm_arch_enable_virtualization_cpu() detects the jump only
+	 * through existing vCPUs.
+	 */
+#ifdef CONFIG_X86_64
+	if (!kvm_get_time_and_clockread(&kvmclock_ns, &kvmclock_host_tsc))
+#endif
+	{
+		/*
+		 * If not simultaneous, we want the TSC to be zero slightly
+		 * *after* the kvmclock is zero.
+		 */
+		kvmclock_ns = get_kvmclock_base_ns();
+		kvmclock_host_tsc = rdtsc();
+	}
+	kvm->arch.cur_tsc_write = 0;
+	kvm->arch.cur_tsc_offset = -(s64)kvmclock_host_tsc;
+	kvm->arch.cur_tsc_nsec = kvmclock_ns;
+	kvm->arch.cur_tsc_generation = 1;
+	kvm->arch.kvmclock_offset = -kvmclock_ns;
+
+	pvclock_update_vm_gtod_copy(kvm);
+	raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+
 #if IS_ENABLED(CONFIG_HYPERV)
 	spin_lock_init(&kvm->arch.hv_root_tdp_lock);
 	kvm->arch.hv_root_tdp = INVALID_PAGE;
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 436e2fb1396c46..de4c86ea5a7de6 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -330,7 +330,7 @@ uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm);
 bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
 int kvm_guest_time_update(struct kvm_vcpu *v);
 
-void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value);
+void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated);
 u64 kvm_scale_tsc(u64 tsc, u64 ratio);
 u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
 u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier);
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 6aa00f746cba39..dae43acb3cc37d 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -188,7 +188,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 	struct kvm_vcpu_xen *xen = &vcpu->arch.xen;
 	int64_t kernel_now, delta;
 	uint64_t guest_now;
-	int r = -EOPNOTSUPP;
+	bool fallback = true;
 
 	/*
 	 * The guest provides the requested timeout in absolute nanoseconds
@@ -210,6 +210,7 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 	do {
 		struct pvclock_vcpu_time_info hv_clock;
 		uint64_t host_tsc, guest_tsc;
+		int r = -EOPNOTSUPP;
 
 		if (!cpu_feature_enabled(X86_FEATURE_CONSTANT_TSC) ||
 		    !vcpu->kvm->arch.use_master_clock)
@@ -230,43 +231,40 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,
 		if (r)
 			break;
 
+		/*
+		 * With use_master_clock set, the clocksource was TSC-based
+		 * when the master clock was last updated. The clockread can
+		 * only fail here if the clocksource has changed since, in
+		 * which case a masterclock update is already pending and
+		 * get_kvmclock_ns() returns the raw-clock fallback value —
+		 * continuous with the last valid snapshot, which is as good
+		 * as it gets in that transient window.
+		 */
 		if (!IS_ENABLED(CONFIG_64BIT) ||
-		    !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc)) {
-			/*
-			 * Don't fall back to get_kvmclock_ns() because it's
-			 * broken; it has a systemic error in its results
-			 * because it scales directly from host TSC to
-			 * nanoseconds, and doesn't scale first to guest TSC
-			 * and *then* to nanoseconds as the guest does.
-			 *
-			 * There is a small error introduced here because time
-			 * continues to elapse between the ktime_get() and the
-			 * subsequent rdtsc(). But not the systemic drift due
-			 * to get_kvmclock_ns().
-			 */
-			kernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */
-			host_tsc = rdtsc();
-		}
+		    !kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc))
+			break;
 
 		/* Calculate the guest kvmclock as the guest would do it. */
 		guest_tsc = kvm_read_l1_tsc(vcpu, host_tsc);
 		guest_now = __pvclock_read_cycles(&hv_clock, guest_tsc);
+		fallback = false;
 	} while (0);
 
-	if (r) {
+	if (fallback) {
 		/*
-		 * Without CONSTANT_TSC, get_kvmclock_ns() is the only option.
+		 * Without CONSTANT_TSC and the master clock,
+		 * get_kvmclock_ns() is the only option.
 		 *
 		 * Also if the guest PV clock hasn't been set up yet, as is
 		 * likely to be the case during migration when the vCPU has
 		 * not been run yet. It would be possible to calculate the
 		 * scaling factors properly in that case but there's not much
-		 * point in doing so. The get_kvmclock_ns() drift accumulates
-		 * over time, so it's OK to use it at startup. Besides, on
-		 * migration there's going to be a little bit of skew in the
-		 * precise moment at which timers fire anyway. Often they'll
-		 * be in the "past" by the time the VM is running again after
-		 * migration.
+		 * point in doing so. Without the master clock, the
+		 * get_kvmclock_ns() drift accumulates over time, so it's OK
+		 * to use it at startup. Besides, on migration there's going
+		 * to be a little bit of skew in the precise moment at which
+		 * timers fire anyway. Often they'll be in the "past" by the
+		 * time the VM is running again after migration.
 		 */
 		guest_now = get_kvmclock_ns(vcpu->kvm);
 		kernel_now = ktime_get();
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8dff2fc1972e97..1349387cceb040 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1000,6 +1000,7 @@ struct kvm_enable_cap {
 #define KVM_CAP_PPC_COMPAT_CAPS 250
 #define KVM_CAP_ARM_PMU_V3_STRICT 251
 #define KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES 252
+#define KVM_CAP_CLOCK_GUEST 253
 
 struct kvm_irq_routing_irqchip {
 	__u32 irqchip;
@@ -1690,4 +1691,7 @@ struct kvm_pre_fault_memory {
 	__u64 padding[5];
 };
 
+#define KVM_SET_CLOCK_GUEST	_IOW(KVMIO, 0xd6, struct pvclock_vcpu_time_info)
+#define KVM_GET_CLOCK_GUEST	_IOR(KVMIO, 0xd7, struct pvclock_vcpu_time_info)
+
 #endif /* __LINUX_KVM_H */
diff --git a/scripts/xen-hypercalls.sh b/scripts/xen-hypercalls.sh
index f18b00843df3ff..51a722198997da 100755
--- a/scripts/xen-hypercalls.sh
+++ b/scripts/xen-hypercalls.sh
@@ -5,7 +5,7 @@ shift
 in="$@"
 
 for i in $in; do
-	eval $CPP $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null
+	eval $CPP -D__KERNEL__ $LINUXINCLUDE -dD -imacros "$i" -x c /dev/null
 done | \
 awk '$1 == "#define" && $2 ~ /__HYPERVISOR_[a-z][a-z_0-9]*/ { v[$3] = $2 }
 	END {   print "/* auto-generated by scripts/xen-hypercall.sh */"
diff --git a/tools/arch/x86/include/asm/pvclock-abi.h b/tools/arch/x86/include/asm/pvclock-abi.h
index b9fece5fc96d6f..6d70cf64036293 100644
--- a/tools/arch/x86/include/asm/pvclock-abi.h
+++ b/tools/arch/x86/include/asm/pvclock-abi.h
@@ -1,6 +1,9 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 #ifndef _ASM_X86_PVCLOCK_ABI_H
 #define _ASM_X86_PVCLOCK_ABI_H
+
+#include <linux/types.h>
+
 #ifndef __ASSEMBLER__
 
 /*
@@ -24,20 +27,20 @@
  */
 
 struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
+	__u32   version;
+	__u32   pad0;
+	__u64   tsc_timestamp;
+	__u64   system_time;
+	__u32   tsc_to_system_mul;
+	__s8    tsc_shift;
+	__u8    flags;
+	__u8    pad[2];
 } __attribute__((__packed__)); /* 32 bytes */
 
 struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
+	__u32   version;
+	__u32   sec;
+	__u32   nsec;
 } __attribute__((__packed__));
 
 #define PVCLOCK_TSC_STABLE_BIT	(1 << 0)
diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h
index 1585ec8040666e..7b3afccb6cb237 100644
--- a/tools/arch/x86/include/uapi/asm/kvm.h
+++ b/tools/arch/x86/include/uapi/asm/kvm.h
@@ -963,6 +963,12 @@ struct kvm_hyperv_eventfd {
 /* for KVM_{GET,SET,HAS}_DEVICE_ATTR */
 #define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */
 #define   KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */
+#define   KVM_VCPU_TSC_SCALE  1 /* attribute for TSC scaling factor */
+
+struct kvm_vcpu_tsc_scale {
+	__u64 tsc_ratio;
+	__u64 tsc_frac_bits;
+};
 
 /* x86-specific KVM_EXIT_HYPERCALL flags. */
 #define KVM_EXIT_HYPERCALL_LONG_MODE	_BITULL(0)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 888a7530a2808f..fd063806a7fb96 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -95,6 +95,7 @@ TEST_GEN_PROGS_x86 += x86/hyperv_tlb_flush
 TEST_GEN_PROGS_x86 += x86/kvm_clock_test
 TEST_GEN_PROGS_x86 += x86/kvm_pv_test
 TEST_GEN_PROGS_x86 += x86/kvm_buslock_test
+TEST_GEN_PROGS_x86 += x86/masterclock_offset_test
 TEST_GEN_PROGS_x86 += x86/monitor_mwait_test
 TEST_GEN_PROGS_x86 += x86/msrs_test
 TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test
@@ -113,6 +114,8 @@ TEST_GEN_PROGS_x86 += x86/pmu_counters_test
 TEST_GEN_PROGS_x86 += x86/pmu_event_filter_test
 TEST_GEN_PROGS_x86 += x86/private_mem_conversions_test
 TEST_GEN_PROGS_x86 += x86/private_mem_kvm_exits_test
+TEST_GEN_PROGS_x86 += x86/pvclock_migration_test
+TEST_GEN_PROGS_x86 += x86/pvclock_test
 TEST_GEN_PROGS_x86 += x86/save_restore_pf_stress_test
 TEST_GEN_PROGS_x86 += x86/set_boot_cpu_id
 TEST_GEN_PROGS_x86 += x86/set_sregs_test
@@ -148,7 +151,10 @@ TEST_GEN_PROGS_x86 += x86/xcr0_cpuid_test
 TEST_GEN_PROGS_x86 += x86/xss_msr_test
 TEST_GEN_PROGS_x86 += x86/debug_regs
 TEST_GEN_PROGS_x86 += x86/tsc_msrs_test
+TEST_GEN_PROGS_x86 += x86/tsc_user_set_test
 TEST_GEN_PROGS_x86 += x86/vmx_pmu_caps_test
+TEST_GEN_PROGS_x86 += x86/xen_cpuid_timing_test
+TEST_GEN_PROGS_x86 += x86/xen_migration_test
 TEST_GEN_PROGS_x86 += x86/xen_shinfo_test
 TEST_GEN_PROGS_x86 += x86/xen_vmcall_test
 TEST_GEN_PROGS_x86 += x86/sev_dbg_test
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index 5898a277a2e01c..4062bdb3271604 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -12,6 +12,7 @@
 
 #include <asm/msr-index.h>
 #include <asm/prctl.h>
+#include <asm/pvclock-abi.h>
 
 #include <linux/kvm_para.h>
 #include <linux/stringify.h>
@@ -1029,6 +1030,55 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
 	vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs);
 }
 
+static inline int __vcpu_get_clock_guest(struct kvm_vcpu *vcpu,
+					 struct pvclock_vcpu_time_info *pvti)
+{
+	return __vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);
+}
+
+static inline void vcpu_get_clock_guest(struct kvm_vcpu *vcpu,
+					struct pvclock_vcpu_time_info *pvti)
+{
+	vcpu_ioctl(vcpu, KVM_GET_CLOCK_GUEST, pvti);
+}
+
+static inline int __vcpu_set_clock_guest(struct kvm_vcpu *vcpu,
+					 struct pvclock_vcpu_time_info *pvti)
+{
+	return __vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);
+}
+
+static inline void vcpu_set_clock_guest(struct kvm_vcpu *vcpu,
+					struct pvclock_vcpu_time_info *pvti)
+{
+	vcpu_ioctl(vcpu, KVM_SET_CLOCK_GUEST, pvti);
+}
+
+static inline u64 vcpu_get_tsc_offset(struct kvm_vcpu *vcpu)
+{
+	u64 offset;
+
+	vcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
+			     &offset);
+	return offset;
+}
+
+static inline void vcpu_set_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+	vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET,
+			     &offset);
+}
+
+static inline void vm_get_clock(struct kvm_vm *vm, struct kvm_clock_data *data)
+{
+	vm_ioctl(vm, KVM_GET_CLOCK, data);
+}
+
+static inline void vm_set_clock(struct kvm_vm *vm, struct kvm_clock_data *data)
+{
+	vm_ioctl(vm, KVM_SET_CLOCK, data);
+}
+
 const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid,
 					       u32 function, u32 index);
 const struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
diff --git a/tools/testing/selftests/kvm/x86/masterclock_offset_test.c b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c
new file mode 100644
index 00000000000000..faf81872538ebb
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/masterclock_offset_test.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that KVM master clock mode works with different TSC offsets
+ * as long as all vCPUs have the same TSC frequency.
+ */
+#include <string.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock.h>
+#include <asm/pvclock-abi.h>
+
+#define KVMCLOCK_GPA	0xc0000000ull
+#define TSC_OFFSET	(1000000000ULL)
+
+#define NR_VCPUS	3
+
+/* Read the per-vCPU pvclocks in an order other than creation order. */
+static const int vcpu_order[NR_VCPUS] = {0, 2, 1};
+
+static void guest_code(u64 pvti_gpa)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, pvti_gpa | KVM_MSR_ENABLED);
+	for (;;)
+		GUEST_SYNC(0);
+}
+
+static void get_pvtis(struct kvm_vcpu **vcpus,
+		      struct pvclock_vcpu_time_info *pvti)
+{
+	int i;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		int idx = vcpu_order[i];
+
+		vcpu_get_clock_guest(vcpus[idx], &pvti[idx]);
+		pr_info("vCPU %d: tsc_timestamp=%lu system_time=%lu "
+			"mul=%u shift=%d flags=0x%x\n",
+			idx, (unsigned long)pvti[idx].tsc_timestamp,
+			(unsigned long)pvti[idx].system_time,
+			pvti[idx].tsc_to_system_mul, pvti[idx].tsc_shift,
+			pvti[idx].flags);
+	}
+}
+
+/*
+ * Read the host TSC once and feed it through each vCPU's pvclock
+ * (adding each vCPU's TSC offset). All must compute exactly the same
+ * kvmclock value.
+ */
+static void assert_pvclocks_match(struct pvclock_vcpu_time_info *pvti,
+				  u64 offset0, const char *what)
+{
+	u64 host_tsc, clk0, clk1, clk2;
+
+	host_tsc = rdtsc();
+	clk0 = __pvclock_read_cycles(&pvti[0], host_tsc + offset0);
+	clk1 = __pvclock_read_cycles(&pvti[1], host_tsc + offset0);
+	clk2 = __pvclock_read_cycles(&pvti[2], host_tsc + offset0 + TSC_OFFSET);
+
+	pr_info("%s: kvmclock via vCPU 0: %lu ns, vCPU 1: %lu ns, vCPU 2: %lu ns\n",
+		what, (unsigned long)clk0, (unsigned long)clk1,
+		(unsigned long)clk2);
+	TEST_ASSERT(clk0 == clk1 && clk0 == clk2,
+		    "%s: kvmclock from all vCPUs should match exactly "
+		    "(0: %lu, 1: %lu, 2: %lu)", what, (unsigned long)clk0,
+		    (unsigned long)clk1, (unsigned long)clk2);
+}
+
+static void test_masterclock_active(struct kvm_vm *vm,
+				    struct kvm_clock_data *clock)
+{
+	memset(clock, 0, sizeof(*clock));
+	vm_get_clock(vm, clock);
+	pr_info("KVM_GET_CLOCK flags: 0x%x\n", clock->flags);
+	TEST_ASSERT(clock->flags & KVM_CLOCK_HOST_TSC,
+		    "Master clock should be active, flags=0x%x", clock->flags);
+	TEST_ASSERT(clock->flags & KVM_CLOCK_TSC_STABLE,
+		    "KVM_CLOCK_TSC_STABLE should be set, flags=0x%x",
+		    clock->flags);
+}
+
+static void test_offset_consistency(struct kvm_vcpu **vcpus,
+				    struct pvclock_vcpu_time_info *pvti,
+				    u64 offset0)
+{
+	u64 gtsc0, gtsc1, gtsc2;
+
+	get_pvtis(vcpus, pvti);
+
+	/* Read guest TSCs: should see (0+OFF) < 2 < (1+OFF) */
+	gtsc0 = vcpu_get_msr(vcpus[0], MSR_IA32_TSC);
+	gtsc2 = vcpu_get_msr(vcpus[2], MSR_IA32_TSC);
+	gtsc1 = vcpu_get_msr(vcpus[1], MSR_IA32_TSC);
+	pr_info("Guest TSCs: vcpu0=%lu vcpu2=%lu vcpu1=%lu\n",
+		(unsigned long)gtsc0, (unsigned long)gtsc2,
+		(unsigned long)gtsc1);
+	TEST_ASSERT(gtsc0 + TSC_OFFSET < gtsc2 && gtsc2 < gtsc1 + TSC_OFFSET,
+		    "Expected (vcpu0+OFF) < vcpu2 < (vcpu1+OFF)");
+
+	/* PVCLOCK_TSC_STABLE_BIT should NOT be set (offsets differ) */
+	TEST_ASSERT(!(pvti[2].flags & PVCLOCK_TSC_STABLE_BIT),
+		    "PVCLOCK_TSC_STABLE_BIT should NOT be set, flags=0x%x",
+		    pvti[2].flags);
+
+	/* Same mul/shift */
+	TEST_ASSERT(pvti[0].tsc_to_system_mul == pvti[1].tsc_to_system_mul &&
+		    pvti[0].tsc_to_system_mul == pvti[2].tsc_to_system_mul &&
+		    pvti[0].tsc_shift == pvti[1].tsc_shift &&
+		    pvti[0].tsc_shift == pvti[2].tsc_shift,
+		    "All vCPUs should have same mul/shift");
+
+	assert_pvclocks_match(pvti, offset0, "Initial");
+}
+
+#define ONE_HOUR_NS (3600ULL * NSEC_PER_SEC)
+
+static void test_set_clock_consistency(struct kvm_vm *vm,
+				       struct kvm_vcpu **vcpus,
+				       struct pvclock_vcpu_time_info *pvti,
+				       struct kvm_clock_data *clock,
+				       u64 offset0)
+{
+	struct kvm_clock_data setclk = { .clock = clock->clock + ONE_HOUR_NS };
+	u64 clk0;
+	int i;
+
+	/*
+	 * Add an hour to the VM kvmclock via KVM_SET_CLOCK, run each
+	 * vCPU to pick up the update, and check they're still in sync.
+	 */
+	vm_set_clock(vm, &setclk);
+
+	/* Guest code does GUEST_SYNC then exits — run each to see update */
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_run(vcpus[vcpu_order[i]]);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpus[vcpu_order[i]], KVM_EXIT_IO);
+	}
+
+	get_pvtis(vcpus, pvti);
+
+	TEST_ASSERT(pvti[0].system_time == pvti[1].system_time &&
+		    pvti[0].system_time == pvti[2].system_time,
+		    "system_time should still match after KVM_SET_CLOCK");
+
+	assert_pvclocks_match(pvti, offset0, "After +1h");
+
+	/* Verify the clock actually moved by ~1 hour */
+	clk0 = __pvclock_read_cycles(&pvti[0], rdtsc() + offset0);
+	TEST_ASSERT(clk0 > ONE_HOUR_NS,
+		    "Clock should be > 1 hour after set, got %lu ns",
+		    (unsigned long)clk0);
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti[NR_VCPUS];
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct kvm_clock_data clock;
+	struct kvm_vm *vm;
+	u64 offset0;
+	int nr_pages;
+	int i;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	TEST_REQUIRE(!__vcpu_has_device_attr(vcpus[0], KVM_VCPU_TSC_CTRL,
+					     KVM_VCPU_TSC_OFFSET));
+
+	nr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, nr_pages, 0);
+
+	/* Give each vCPU its own pvclock structure within the page */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_args_set(vcpus[i], 1, KVMCLOCK_GPA +
+			      i * sizeof(struct pvclock_vcpu_time_info) * 2);
+
+	/* Get vCPU 0's default offset and set vCPU 2's offset higher */
+	offset0 = vcpu_get_tsc_offset(vcpus[0]);
+	vcpu_set_tsc_offset(vcpus[2], offset0 + TSC_OFFSET);
+
+	/* Run each vCPU to enable kvmclock (with offset already set) */
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_run(vcpus[i]);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpus[i], KVM_EXIT_IO);
+	}
+
+	test_masterclock_active(vm, &clock);
+	test_offset_consistency(vcpus, pvti, offset0);
+	pr_info("PASSED: pvclock consistent across offset vCPUs\n");
+
+	test_set_clock_consistency(vm, vcpus, pvti, &clock, offset0);
+	pr_info("PASSED: pvclock still consistent after KVM_SET_CLOCK +1h\n");
+
+	kvm_vm_free(vm);
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/pvclock_migration_test.c b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c
new file mode 100644
index 00000000000000..c18c9132308d6c
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/pvclock_migration_test.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test KVM clock precision across simulated live migration.
+ *
+ * Verifies that the documented TSC migration procedure (using
+ * KVM_VCPU_TSC_OFFSET, KVM_VCPU_TSC_SCALE, KVM_GET_CLOCK, and
+ * KVM_SET_CLOCK_GUEST) preserves the kvmclock's relationship to
+ * CLOCK_MONOTONIC_RAW — including for vCPUs whose TSCs are offset
+ * from one another (same frequency), which no longer disables the
+ * master clock.
+ *
+ * The test:
+ * 1. Creates a VM with 3 vCPUs, runs each guest to enable kvmclock
+ * 2. Applies divergent TSC offsets to vCPUs 1 and 2
+ * 3. Verifies the master clock remains active (KVM_CLOCK_HOST_TSC),
+ *    that the guests see PVCLOCK_TSC_STABLE_BIT clear, and that all
+ *    vCPUs' pvclocks agree on "now" despite the divergent offsets
+ * 4. Does a PTP-like ABA measurement of kvmclock vs CLOCK_MONOTONIC_RAW
+ * 5. Follows the documented migration procedure (same host, 1s pause),
+ *    migrating each vCPU's TSC individually but setting the KVM clock
+ *    only once, via KVM_SET_CLOCK_GUEST on vCPU0
+ * 6. Does the same ABA measurement on the destination VM
+ * 7. Verifies the kvmclock-vs-monotonic delta is preserved, the
+ *    cross-vCPU TSC deltas are preserved, and all destination vCPUs'
+ *    pvclocks again agree on "now"
+ */
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+#define KVMCLOCK_GPA	0xc0000000ULL
+#define NR_VCPUS	3
+
+/*
+ * Divergent TSC offsets applied to vCPUs 1 and 2, in guest cycles.
+ * Roughly +1s and -0.5s at 1.5 GHz — large enough that any failure
+ * to account for them is orders of magnitude outside the ABA bounds.
+ */
+static const s64 tsc_deltas[NR_VCPUS] = { 0, 1500000000LL, -750000000LL };
+
+static void guest_code(int idx)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, (KVMCLOCK_GPA + idx * PAGE_SIZE) | 1);
+
+	for (;;)
+		GUEST_SYNC(0);
+}
+
+static u64 read_kvmclock_ns(struct kvm_vm *vm)
+{
+	struct kvm_clock_data data = {};
+
+	vm_get_clock(vm, &data);
+	return data.clock;
+}
+
+static u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,
+				    u64 tsc)
+{
+	u64 delta = tsc - src->tsc_timestamp;
+	u64 ns;
+
+	if (src->tsc_shift >= 0)
+		delta <<= src->tsc_shift;
+	else
+		delta >>= -(s32)src->tsc_shift;
+
+	ns = (unsigned __int128)delta * src->tsc_to_system_mul >> 32;
+	return src->system_time + ns;
+}
+
+/*
+ * ABA measurement: read CLOCK_MONOTONIC_RAW, kvmclock, CLOCK_MONOTONIC_RAW.
+ * Repeat 3 times, keep the reading with the smallest spread.
+ */
+static void aba_reading(struct kvm_vm *vm, u64 *lo, u64 *kvm_ns,
+			u64 *hi)
+{
+	u64 best_spread = UINT64_MAX;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		struct timespec ts1, ts2;
+		u64 m1, m2, clk;
+
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
+		clk = read_kvmclock_ns(vm);
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
+
+		m1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;
+		m2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;
+
+		if (m2 - m1 < best_spread) {
+			best_spread = m2 - m1;
+			*lo = m1;
+			*kvm_ns = clk;
+			*hi = m2;
+		}
+	}
+}
+
+static struct kvm_vm *create_vm(struct kvm_vcpu **vcpus, u32 freq_khz)
+{
+	struct kvm_vm *vm;
+	int i;
+
+	vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus);
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, NR_VCPUS, 0);
+	virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, NR_VCPUS);
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		vcpu_args_set(vcpus[i], 1, i);
+		/* Set guest TSC frequency (may trigger scaling) */
+		vcpu_ioctl(vcpus[i], KVM_SET_TSC_KHZ,
+			   (void *)(unsigned long)freq_khz);
+	}
+	return vm;
+}
+
+static void run_to_sync(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+}
+
+/*
+ * Compute a vCPU's guest TSC for a given host TSC value, using the
+ * vCPU's scale and offset as saved from KVM_VCPU_TSC_SCALE/OFFSET.
+ */
+static u64 host_to_guest_tsc(struct kvm_vcpu_tsc_scale *scale, u64 ofs,
+			     u64 host_tsc)
+{
+	if (scale->tsc_frac_bits)
+		return ((unsigned __int128)host_tsc * scale->tsc_ratio
+			>> scale->tsc_frac_bits) + ofs;
+	return host_tsc + ofs;
+}
+
+/*
+ * Verify that all vCPUs agree on the KVM clock, despite having
+ * different TSC offsets. Take one atomic {host_tsc, kvmclock} pair
+ * for the whole VM, derive each vCPU's guest TSC at that instant,
+ * and evaluate each vCPU's pvti at its own guest TSC. All must give
+ * the same nanosecond value (same instant, same clock), and must
+ * match what KVM_GET_CLOCK itself said.
+ */
+static void check_cross_vcpu_coherence(struct kvm_vm *vm,
+				       struct kvm_vcpu **vcpus,
+				       struct pvclock_vcpu_time_info *pvtis,
+				       const char *what)
+{
+	struct kvm_clock_data now = {};
+	u64 clk[NR_VCPUS];
+	int i;
+
+	vm_get_clock(vm, &now);
+	TEST_ASSERT(now.flags & KVM_CLOCK_HOST_TSC,
+		    "%s: master clock inactive with divergent TSC offsets",
+		    what);
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct kvm_vcpu_tsc_scale scale = {};
+		u64 ofs = vcpu_get_tsc_offset(vcpus[i]);
+		u64 guest_tsc;
+
+		vcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale);
+		guest_tsc = host_to_guest_tsc(&scale, ofs, now.host_tsc);
+		clk[i] = pvclock_read_cycles(&pvtis[i], guest_tsc);
+
+		TEST_ASSERT(!(pvtis[i].flags & PVCLOCK_TSC_STABLE_BIT),
+			    "%s: vCPU%d still advertises TSC_STABLE with divergent offsets",
+			    what, i);
+	}
+
+	for (i = 1; i < NR_VCPUS; i++) {
+		s64 d = (s64)(clk[i] - clk[0]);
+
+		pr_info("  %s: vCPU%d vs vCPU0 kvmclock delta %" PRId64 " ns\n",
+			what, i, d);
+		TEST_ASSERT(d >= -2 && d <= 2,
+			    "%s: vCPU%d kvmclock disagrees with vCPU0 by %" PRId64 " ns",
+			    what, i, d);
+	}
+
+	/* And all of them must agree with KVM_GET_CLOCK itself */
+	s64 d0 = (s64)(clk[0] - now.clock);
+	pr_info("  %s: vCPU0 pvclock vs KVM_GET_CLOCK delta %" PRId64 " ns\n",
+		what, d0);
+	TEST_ASSERT(d0 >= -2 && d0 <= 2,
+		    "%s: vCPU0 pvclock disagrees with KVM_GET_CLOCK by %" PRId64 " ns",
+		    what, d0);
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti_src[NR_VCPUS];
+	struct pvclock_vcpu_time_info pvti_dst_ioctl[NR_VCPUS];
+	struct kvm_clock_data clock_src, clock_dst;
+	struct kvm_vcpu_tsc_scale scale_src[NR_VCPUS], scale_dst;
+	struct kvm_vcpu *vcpus[NR_VCPUS];
+	struct kvm_vm *vm;
+	u64 mono_before, kvm_before, kvm_after;
+	s64 delta_before;
+	u64 ofs_src[NR_VCPUS], tsc_src[NR_VCPUS], tsc_dst, raw_dst;
+	u64 ofs_dst[NR_VCPUS];
+	u64 host_tsc_src, host_tsc_dst;
+	u64 time_src, time_dst;
+	s64 delta_t;
+	u32 freq_khz = 1500000; /* 1.5 GHz — forces TSC scaling */
+	int i, pass;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	/* === SOURCE SIDE === */
+	pr_info("=== Source VM ===\n");
+	vm = create_vm(vcpus, freq_khz);
+
+	/* Run each guest to enable its kvmclock */
+	for (i = 0; i < NR_VCPUS; i++)
+		run_to_sync(vcpus[i]);
+
+	/*
+	 * Apply divergent TSC offsets. Same frequency, different offsets:
+	 * this must no longer disable the master clock, but must clear
+	 * PVCLOCK_TSC_STABLE_BIT.
+	 */
+	for (i = 1; i < NR_VCPUS; i++)
+		vcpu_set_tsc_offset(vcpus[i],
+				    vcpu_get_tsc_offset(vcpus[i]) + tsc_deltas[i]);
+
+	/*
+	 * Re-run each vCPU twice. The offset writes leave a masterclock
+	 * update pending on vCPUs 1 and 2; the first pass processes it and
+	 * broadcasts KVM_REQ_CLOCK_UPDATE to every vCPU, and the second
+	 * pass has each vCPU rewrite its guest-visible pvclock page with
+	 * PVCLOCK_TSC_STABLE_BIT now clear. A single pass would leave
+	 * vCPU0's page stale: its rewrite happens before the broadcast.
+	 */
+	for (pass = 0; pass < 2; pass++)
+		for (i = 0; i < NR_VCPUS; i++)
+			run_to_sync(vcpus[i]);
+
+	/* Fetch each vCPU's pvti and verify cross-vCPU coherence */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_get_clock_guest(vcpus[i], &pvti_src[i]);
+	check_cross_vcpu_coherence(vm, vcpus, pvti_src, "source");
+
+	/* The guest-visible pvti pages must also show TSC_STABLE clear */
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct pvclock_vcpu_time_info *pvti =
+			addr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());
+
+		TEST_ASSERT(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT),
+			    "vCPU%d guest pvti advertises TSC_STABLE with divergent offsets", i);
+	}
+
+	/* ABA measurement: kvmclock vs CLOCK_MONOTONIC_RAW */
+	u64 src_mono_lo, src_mono_hi;
+	aba_reading(vm, &src_mono_lo, &kvm_before, &src_mono_hi);
+	mono_before = (src_mono_lo + src_mono_hi) / 2;
+	delta_before = (s64)(kvm_before - mono_before);
+	pr_info("  kvmclock - MONOTONIC_RAW = %" PRId64 " ns (±%" PRIu64 " ns)\n",
+		delta_before, (src_mono_hi - src_mono_lo) / 2);
+
+	/* Step 1: KVM_GET_CLOCK for atomic {host_tsc, realtime} */
+	memset(&clock_src, 0, sizeof(clock_src));
+	clock_src.flags = KVM_CLOCK_REALTIME;
+	vm_get_clock(vm, &clock_src);
+	TEST_ASSERT(clock_src.flags & KVM_CLOCK_HOST_TSC,
+		    "KVM_GET_CLOCK did not provide host_tsc (no master clock?)");
+	host_tsc_src = clock_src.host_tsc;
+	time_src = clock_src.realtime;
+
+	/* Step 2: Save each vCPU's TSC offset and scale */
+	for (i = 0; i < NR_VCPUS; i++) {
+		ofs_src[i] = vcpu_get_tsc_offset(vcpus[i]);
+		memset(&scale_src[i], 0, sizeof(scale_src[i]));
+		vcpu_device_attr_get(vcpus[i], KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale_src[i]);
+
+		/* Compute this vCPU's guest TSC at Tsrc */
+		tsc_src[i] = host_to_guest_tsc(&scale_src[i], ofs_src[i],
+					       host_tsc_src);
+		pr_info("  vCPU%d: TSC freq=%u kHz, offset=%" PRId64 "\n",
+			i, freq_khz, (s64)ofs_src[i]);
+	}
+
+	/* Step 3: KVM_GET_CLOCK_GUEST (already fetched above as pvti_src[]) */
+
+	kvm_vm_free(vm);
+
+	/* === PAUSE (simulate migration) === */
+	pr_info("=== Pausing 1 second ===\n");
+	sleep(1);
+
+	/* === DESTINATION SIDE === */
+	pr_info("=== Destination VM ===\n");
+	/* Step 4: create + KVM_SET_TSC_KHZ (in create_vm) */
+	vm = create_vm(vcpus, freq_khz);
+
+	/* Step 5: KVM_GET_CLOCK for atomic {host_tsc, realtime} pair.
+	 * Master clock is active from VM creation.
+	 */
+	memset(&clock_dst, 0, sizeof(clock_dst));
+	vm_get_clock(vm, &clock_dst);
+	TEST_ASSERT(clock_dst.flags & KVM_CLOCK_HOST_TSC,
+		    "KVM_GET_CLOCK did not provide host_tsc (no master clock?)");
+	host_tsc_dst = clock_dst.host_tsc;
+	time_dst = clock_dst.realtime;
+
+	/* Step 6: ΔT */
+	delta_t = (s64)(time_dst - time_src);
+
+	/* Step 7: Compute and set each vCPU's destination offset */
+	memset(&scale_dst, 0, sizeof(scale_dst));
+	vcpu_device_attr_get(vcpus[0], KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_SCALE,
+			     &scale_dst);
+
+	if (scale_dst.tsc_frac_bits)
+		raw_dst = (unsigned __int128)host_tsc_dst * scale_dst.tsc_ratio
+			  >> scale_dst.tsc_frac_bits;
+	else
+		raw_dst = host_tsc_dst;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		tsc_dst = tsc_src[i] + (u64)((s64)freq_khz * delta_t / 1000000LL);
+		ofs_dst[i] = tsc_dst - raw_dst;
+		vcpu_set_tsc_offset(vcpus[i], ofs_dst[i]);
+	}
+
+	/*
+	 * The cross-vCPU TSC relationships must be preserved exactly:
+	 * every vCPU's offset moved by the same amount, so the deltas
+	 * between them are untouched by the CLOCK_REALTIME imprecision.
+	 */
+	for (i = 1; i < NR_VCPUS; i++) {
+		s64 src_delta = (s64)(ofs_src[i] - ofs_src[0]);
+		s64 dst_delta = (s64)(ofs_dst[i] - ofs_dst[0]);
+
+		pr_info("  vCPU%d-vCPU0 TSC delta: src %" PRId64
+			", dst %" PRId64 " cycles\n", i, src_delta, dst_delta);
+		TEST_ASSERT(src_delta == dst_delta,
+			    "vCPU%d TSC delta not preserved: %" PRId64 " -> %" PRId64,
+			    i, src_delta, dst_delta);
+	}
+
+	/*
+	 * The TSC offset delta introduced by using CLOCK_REALTIME to
+	 * estimate elapsed time. On same host, the correct offset is
+	 * ofs_src; the difference is the CLOCK_REALTIME-vs-TSC error.
+	 */
+	s64 tsc_ofs_delta = (s64)(ofs_dst[0] - ofs_src[0]);
+	s64 tsc_ofs_delta_ns = tsc_ofs_delta * 1000000LL / freq_khz;
+	pr_info("  Destination TSC offset=%" PRId64
+		", imprecision from CLOCK_REALTIME: %" PRId64 " cycles = %"
+		PRId64 " ns\n", (s64)ofs_dst[0], tsc_ofs_delta, tsc_ofs_delta_ns);
+
+	/*
+	 * Step 8: KVM_SET_CLOCK_GUEST — once, via vCPU0. The other
+	 * vCPUs' clocks must come out right too: the KVM clock is
+	 * VM-wide, and each vCPU's pvti relates it to that vCPU's
+	 * own TSC.
+	 */
+	vcpu_set_clock_guest(vcpus[0], &pvti_src[0]);
+
+	/* Run each guest to write its pvclock page on the destination */
+	for (i = 0; i < NR_VCPUS; i++)
+		run_to_sync(vcpus[i]);
+
+	/* Verify cross-vCPU coherence on the destination */
+	for (i = 0; i < NR_VCPUS; i++)
+		vcpu_get_clock_guest(vcpus[i], &pvti_dst_ioctl[i]);
+	check_cross_vcpu_coherence(vm, vcpus, pvti_dst_ioctl, "dest");
+
+	/* ABA measurement on destination */
+	u64 mono_lo, mono_hi;
+	aba_reading(vm, &mono_lo, &kvm_after, &mono_hi);
+
+	/*
+	 * The kvmclock is tied to the guest TSC via SET_CLOCK_GUEST.
+	 * The guest TSC is offset from the correct value by tsc_ofs_delta_ns
+	 * (due to CLOCK_REALTIME imprecision). So the kvmclock should be
+	 * offset from CLOCK_MONOTONIC_RAW by exactly:
+	 *   (original delta) + tsc_ofs_delta_ns
+	 *
+	 * The "original delta" has uncertainty from the source ABA spread,
+	 * and the measurement has uncertainty from the destination ABA spread.
+	 * Verify the expected value falls within the combined bounds.
+	 */
+	s64 delta_before_lo = (s64)(kvm_before - src_mono_hi);
+	s64 delta_before_hi = (s64)(kvm_before - src_mono_lo);
+	s64 expected_lo = delta_before_lo + tsc_ofs_delta_ns;
+	s64 expected_hi = delta_before_hi + tsc_ofs_delta_ns;
+	s64 actual_lo = (s64)(kvm_after - mono_hi);
+	s64 actual_hi = (s64)(kvm_after - mono_lo);
+
+	/* Show the shift relative to the source measurement */
+	s64 expected_mid = tsc_ofs_delta_ns;
+	s64 expected_err = (s64)(src_mono_hi - src_mono_lo) / 2;
+	s64 actual_mid = ((actual_lo + actual_hi) / 2) - delta_before;
+	s64 actual_err = (s64)(mono_hi - mono_lo) / 2;
+	pr_info("  kvmclock-mono shift: expected %" PRId64 " ns (±%" PRId64
+		"), measured %" PRId64 " ns (±%" PRId64 ")\n",
+		expected_mid, expected_err, actual_mid, actual_err);
+
+	/* The ranges must overlap */
+	TEST_ASSERT(expected_hi >= actual_lo && expected_lo <= actual_hi,
+		    "Ranges don't overlap: expected [%" PRId64 ", %" PRId64
+		    "] measured [%" PRId64 ", %" PRId64 "]",
+		    expected_lo, expected_hi, actual_lo, actual_hi);
+
+	/*
+	 * Direct pvclock verification: read each destination pvclock page
+	 * (as written for the guest) and verify that computing kvmclock
+	 * from the source pvti and the destination pvti at the same
+	 * instant gives the same result, for every vCPU.
+	 *
+	 * Get one atomic {host_tsc, kvmclock} pair, derive each vCPU's
+	 * guest TSC at that instant, then compute kvmclock from both
+	 * pvclock structs. The source pvti evaluates at the *migrated*
+	 * guest TSC, i.e. shifted by the CLOCK_REALTIME imprecision that
+	 * was baked into the offsets — which is exactly what "the clock
+	 * follows the TSC" means.
+	 */
+	struct kvm_clock_data clock_now = {};
+	vm_get_clock(vm, &clock_now);
+	pr_info("  KVM_GET_CLOCK:  %" PRIu64 " ns\n", (u64)clock_now.clock);
+
+	u64 host_tsc_now = clock_now.host_tsc;
+
+	for (i = 0; i < NR_VCPUS; i++) {
+		struct pvclock_vcpu_time_info *pvti_page =
+			addr_gpa2hva(vm, KVMCLOCK_GPA + i * getpagesize());
+		u64 guest_tsc_now = host_to_guest_tsc(&scale_dst, ofs_dst[i],
+						      host_tsc_now);
+		u64 clk_from_src = pvclock_read_cycles(&pvti_src[i],
+						       guest_tsc_now);
+		u64 clk_from_dst = pvclock_read_cycles(pvti_page,
+						       guest_tsc_now);
+		s64 pvclock_delta = (s64)(clk_from_src - clk_from_dst);
+
+		pr_info("  vCPU%d pvclock direct: src=%" PRIu64 " dst=%" PRIu64
+			" delta=%" PRId64 " ns\n", i, clk_from_src,
+			clk_from_dst, pvclock_delta);
+
+		TEST_ASSERT(pvclock_delta >= -2 && pvclock_delta <= 2,
+			    "vCPU%d pvclock src vs dst disagree by %" PRId64 " ns",
+			    i, pvclock_delta);
+	}
+
+	/*
+	 * Tight ABA: compare pvclock_read() directly (no ioctl) against
+	 * CLOCK_MONOTONIC_RAW. The spread should be much smaller since
+	 * there's no syscall between the two clock_gettime calls — just
+	 * rdtsc + userspace mul/shift.
+	 */
+	struct pvclock_vcpu_time_info *pvti0 = addr_gpa2hva(vm, KVMCLOCK_GPA);
+	u64 tight_mono_lo = 0, tight_mono_hi = 0, tight_kvm = 0;
+	u64 tight_best_spread = UINT64_MAX;
+	for (i = 0; i < 3; i++) {
+		struct timespec ts1, ts2;
+		u64 m1, m2, tsc, clk;
+
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
+		tsc = rdtsc();
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
+
+		m1 = ts1.tv_sec * 1000000000ULL + ts1.tv_nsec;
+		m2 = ts2.tv_sec * 1000000000ULL + ts2.tv_nsec;
+
+		/* Scale host TSC to vCPU0's guest TSC */
+		tsc = host_to_guest_tsc(&scale_dst, ofs_dst[0], tsc);
+
+		clk = pvclock_read_cycles(pvti0, tsc);
+
+		if (m2 - m1 < tight_best_spread) {
+			tight_best_spread = m2 - m1;
+			tight_mono_lo = m1;
+			tight_mono_hi = m2;
+			tight_kvm = clk;
+		}
+	}
+	pr_info("  Tight ABA spread: %" PRIu64 " ns (best of 3)\n", tight_best_spread);
+
+	s64 tight_expected_lo = delta_before_lo + tsc_ofs_delta_ns;
+	s64 tight_expected_hi = delta_before_hi + tsc_ofs_delta_ns;
+	s64 tight_actual_lo = (s64)(tight_kvm - tight_mono_hi);
+	s64 tight_actual_hi = (s64)(tight_kvm - tight_mono_lo);
+	s64 tight_actual_mid = ((tight_actual_lo + tight_actual_hi) / 2) - delta_before;
+	s64 tight_actual_err = (s64)(tight_mono_hi - tight_mono_lo) / 2;
+
+	pr_info("  Tight kvmclock-mono shift: expected %" PRId64
+		" ns (±%" PRId64 "), measured %" PRId64 " ns (±%" PRId64 ")\n",
+		expected_mid, expected_err, tight_actual_mid, tight_actual_err);
+
+	TEST_ASSERT(tight_expected_hi >= tight_actual_lo &&
+		    tight_expected_lo <= tight_actual_hi,
+		    "Tight ABA ranges don't overlap");
+
+	kvm_vm_free(vm);
+	pr_info("PASS: kvmclock offset matches TSC delta from CLOCK_REALTIME"
+		" (%" PRId64 " ns) within ABA bounds\n", tsc_ofs_delta_ns);
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/pvclock_test.c b/tools/testing/selftests/kvm/x86/pvclock_test.c
new file mode 100644
index 00000000000000..1599fb0c727536
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/pvclock_test.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright © Amazon.com, Inc. or its affiliates.
+ *
+ * Tests for pvclock API
+ * KVM_SET_CLOCK_GUEST/KVM_GET_CLOCK_GUEST
+ */
+#include <getopt.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+/*
+ * Reproduce the pvclock calculation the guest uses to convert TSC to
+ * nanoseconds. This must match the kernel's __pvclock_read_cycles().
+ */
+static inline u64 pvclock_scale_delta(u64 delta, u32 mul,
+					   s8 shift)
+{
+	if (shift < 0)
+		delta >>= -shift;
+	else
+		delta <<= shift;
+	return ((__uint128_t)delta * mul) >> 32;
+}
+
+static inline u64 pvclock_read_cycles(struct pvclock_vcpu_time_info *src,
+					   u64 tsc)
+{
+	u64 delta = tsc - src->tsc_timestamp;
+
+	return src->system_time + pvclock_scale_delta(delta,
+						      src->tsc_to_system_mul,
+						      src->tsc_shift);
+}
+
+static inline void pvti_snapshot(struct pvclock_vcpu_time_info *dst,
+				 volatile struct pvclock_vcpu_time_info *src)
+{
+	u32 version;
+
+	do {
+		version = src->version;
+		__asm__ __volatile__("" ::: "memory");
+		*dst = *src;
+		__asm__ __volatile__("" ::: "memory");
+	} while ((src->version & 1) || src->version != version);
+}
+
+enum {
+	STAGE_FIRST_BOOT,
+	STAGE_UNCORRECTED,
+	STAGE_CORRECTED
+};
+
+#define KVMCLOCK_GPA	0xc0000000ull
+#define KVMCLOCK_SIZE	sizeof(struct pvclock_vcpu_time_info)
+
+static void trigger_pvti_update(void)
+{
+	/*
+	 * Toggle between KVM's old and new system time methods to coerce KVM
+	 * into updating the fields in the PV time info struct.
+	 */
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+}
+
+static void guest_code(void)
+{
+	struct pvclock_vcpu_time_info *pvti =
+		(void *)(unsigned long)KVMCLOCK_GPA;
+	struct pvclock_vcpu_time_info pvti_boot;
+	struct pvclock_vcpu_time_info pvti_uncorrected;
+	struct pvclock_vcpu_time_info pvti_corrected;
+	u64 tsc_guest;
+	u64 clk_boot, clk_uncorrected, clk_corrected;
+	s64 delta_corrected;
+
+	/* Set up kvmclock and snapshot the initial pvclock parameters. */
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	pvti_snapshot(&pvti_boot, pvti);
+	GUEST_SYNC(STAGE_FIRST_BOOT);
+
+	/*
+	 * Trigger an update of the PVTI. Calculating the KVM clock using this
+	 * updated structure will show a delta from the original.
+	 */
+	trigger_pvti_update();
+	pvti_snapshot(&pvti_uncorrected, pvti);
+	GUEST_SYNC(STAGE_UNCORRECTED);
+
+	/*
+	 * Snapshot the corrected time (the host does KVM_SET_CLOCK_GUEST when
+	 * handling STAGE_UNCORRECTED).
+	 */
+	pvti_snapshot(&pvti_corrected, pvti);
+
+	/*
+	 * Sample the TSC at a single point in time, then calculate the
+	 * effective KVM clock using the PVTI from each stage. Verify that the
+	 * corrected clock matches the boot clock to within ±2ns.
+	 */
+	tsc_guest = rdtsc();
+
+	clk_boot = pvclock_read_cycles(&pvti_boot, tsc_guest);
+	clk_uncorrected = pvclock_read_cycles(&pvti_uncorrected, tsc_guest);
+	clk_corrected = pvclock_read_cycles(&pvti_corrected, tsc_guest);
+
+	/*
+	 * The host stepped the KVM clock forward by 10 seconds at
+	 * STAGE_FIRST_BOOT, so the uncorrected clock must diverge; without
+	 * this, a no-op KVM_SET_CLOCK_GUEST would pass the test below.
+	 */
+	__GUEST_ASSERT((s64)(clk_uncorrected - clk_boot) > NSEC_PER_SEC,
+		       "uncorrected clock did not diverge (boot=%lu uncorrected=%lu)",
+		       clk_boot, clk_uncorrected);
+
+	delta_corrected = clk_boot - clk_corrected;
+
+	__GUEST_ASSERT(delta_corrected >= -2 && delta_corrected <= 2,
+		       "corrected delta %ld out of range (boot=%lu uncorrected=%lu corrected=%lu)",
+		       delta_corrected, clk_boot, clk_uncorrected, clk_corrected);
+
+	GUEST_SYNC(STAGE_CORRECTED);
+}
+
+static void run_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
+		     unsigned int sleep_sec)
+{
+	struct pvclock_vcpu_time_info pvti_before;
+	struct kvm_clock_data clock_step;
+	struct ucall uc;
+
+	for (;;) {
+		vcpu_run(vcpu);
+		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+		switch (get_ucall(vcpu, &uc)) {
+		case UCALL_ABORT:
+			REPORT_GUEST_ASSERT(uc);
+			break;
+		case UCALL_SYNC:
+			break;
+		default:
+			TEST_FAIL("Unexpected ucall");
+		}
+
+		switch (uc.args[1]) {
+		case STAGE_FIRST_BOOT:
+			/* Save the pvclock parameters before the update. */
+			vcpu_get_clock_guest(vcpu, &pvti_before);
+
+			/* Sleep to let the clocks diverge. */
+			sleep(sleep_sec);
+
+			/*
+			 * Step the KVM clock forward 10 seconds so that the
+			 * divergence the correction must eliminate is
+			 * deterministic, not at the mercy of accumulated
+			 * drift during the sleep.
+			 */
+			vm_get_clock(vm, &clock_step);
+			clock_step.clock += 10ull * NSEC_PER_SEC;
+			clock_step.flags = 0;
+			vm_set_clock(vm, &clock_step);
+			break;
+
+		case STAGE_UNCORRECTED:
+			/* Restore the original pvclock parameters. */
+			vcpu_set_clock_guest(vcpu, &pvti_before);
+			break;
+
+		case STAGE_CORRECTED:
+			/* Guest verified the delta in-guest. */
+			return;
+
+		default:
+			TEST_FAIL("Unknown stage %lu", uc.args[1]);
+		}
+	}
+}
+
+static void configure_pvclock(struct kvm_vm *vm)
+{
+	unsigned int nr_pages;
+
+	nr_pages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, getpagesize());
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    KVMCLOCK_GPA, 1, nr_pages, 0);
+	virt_map(vm, KVMCLOCK_GPA, KVMCLOCK_GPA, nr_pages);
+}
+
+static void run_at_frequency(u64 tsc_khz, unsigned int sleep_sec)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz);
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	configure_pvclock(vm);
+	vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)tsc_khz);
+	run_test(vm, vcpu, sleep_sec);
+	kvm_vm_free(vm);
+}
+
+static void test_tsc_stable_bit(void);
+static void test_clock_guest_with_offsets(void);
+static void test_legacy_msr(void);
+static void run_vcpu_once(struct kvm_vcpu *vcpu);
+
+static void usage(const char *name)
+{
+	printf("Usage: %s [options]\n"
+	       "  -s, --sleep SEC     sleep duration between snapshots (default: 2)\n"
+	       "  -h, --help          show this help\n", name);
+}
+
+int main(int argc, char *argv[])
+{
+	static const struct option long_opts[] = {
+		{ "sleep", required_argument, NULL, 's' },
+		{ "help",  no_argument,       NULL, 'h' },
+		{ NULL,    0,                  NULL,  0  },
+	};
+	unsigned int sleep_sec = 2;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 host_khz;
+	u64 freq;
+	int opt;
+
+	while ((opt = getopt_long(argc, argv, "s:h", long_opts, NULL)) != -1) {
+		switch (opt) {
+		case 's':
+			sleep_sec = atoi_non_negative("sleep", optarg);
+			break;
+		case 'h':
+		default:
+			usage(argv[0]);
+			return opt == 'h' ? 0 : 1;
+		}
+	}
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL));
+
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	configure_pvclock(vm);
+
+	/* First run at native frequency (no scaling). */
+	run_test(vm, vcpu, sleep_sec);
+
+	/*
+	 * Then enumerate a range of TSC frequencies crossing the 32-bit
+	 * boundary, to exercise the scaling path at various ratios.
+	 */
+	host_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	kvm_vm_free(vm);
+
+	for (freq = 1000000; freq <= 5000000; freq += 500000) {
+		if (freq == host_khz)
+			continue;
+		run_at_frequency(freq, sleep_sec);
+	}
+
+	test_tsc_stable_bit();
+	test_clock_guest_with_offsets();
+	test_legacy_msr();
+
+	return 0;
+}
+
+static void guest_code_legacy_msr(void)
+{
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	GUEST_SYNC(0);
+	/* Re-request the time, as SUSE's 2.6.16 kernel would. */
+	wrmsr(MSR_KVM_SYSTEM_TIME, KVMCLOCK_GPA | KVM_MSR_ENABLED);
+	GUEST_SYNC(1);
+}
+
+/*
+ * A guest using the legacy MSR_KVM_SYSTEM_TIME must no longer lose the
+ * master clock, and rewriting the MSR must slide the reference point
+ * forward so the pvclock's tsc_timestamp is recent — that freshness is
+ * what SUSE's 2.6.16 kernel demands instead of tolerating a fixed
+ * reference point.
+ */
+static void test_legacy_msr(void)
+{
+	struct pvclock_vcpu_time_info *pvti;
+	struct kvm_clock_data clock;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 tsc_now, age_limit;
+
+	pr_info("Testing the legacy MSR_KVM_SYSTEM_TIME\n");
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code_legacy_msr);
+	configure_pvclock(vm);
+
+	run_vcpu_once(vcpu);
+	vm_ioctl(vm, KVM_GET_CLOCK, &clock);
+	TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE,
+		    "Legacy MSR_KVM_SYSTEM_TIME should not disable the master clock");
+
+	/* Age the master clock reference point, then re-request. */
+	usleep(300 * 1000);
+	run_vcpu_once(vcpu);
+
+	pvti = addr_gpa2hva(vm, KVMCLOCK_GPA);
+	tsc_now = vcpu_get_msr(vcpu, MSR_IA32_TSC);
+
+	/*
+	 * The rewrite slid the reference point, so the pvclock must be
+	 * anchored after the 300ms sleep: allow 250ms of slack for the
+	 * ioctls around it. SUSE's real threshold was 1/5 jiffie, but
+	 * asserting that tightly would flake on a loaded host.
+	 */
+	age_limit = (u64)__vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL) * 250;
+	TEST_ASSERT(tsc_now - pvti->tsc_timestamp < age_limit,
+		    "pvclock tsc_timestamp should be fresh after legacy MSR rewrite (age %llu cycles, limit %llu)",
+		    (unsigned long long)(tsc_now - pvti->tsc_timestamp),
+		    (unsigned long long)age_limit);
+
+	vm_ioctl(vm, KVM_GET_CLOCK, &clock);
+	TEST_ASSERT(clock.flags & KVM_CLOCK_TSC_STABLE,
+		    "Master clock should survive a legacy MSR rewrite");
+
+	kvm_vm_free(vm);
+}
+
+static volatile u32 vcpu_counter;
+static void guest_code_stable_bit(void)
+{
+	u32 idx = __atomic_fetch_add(&vcpu_counter, 1, __ATOMIC_SEQ_CST);
+	u64 gpa = KVMCLOCK_GPA + idx * KVMCLOCK_SIZE;
+
+	wrmsr(MSR_KVM_SYSTEM_TIME_NEW, gpa | KVM_MSR_ENABLED);
+	GUEST_SYNC(0);
+	GUEST_SYNC(0);
+	GUEST_SYNC(0);
+}
+
+static void run_vcpu_once(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_SYNC:
+		break;
+	default:
+		TEST_FAIL("Unexpected ucall");
+	}
+}
+
+static void test_tsc_stable_bit(void)
+{
+	struct pvclock_vcpu_time_info pvti;
+	struct kvm_vcpu *vcpus[2];
+	struct kvm_vm *vm;
+	int ret;
+
+	pr_info("Testing PVCLOCK_TSC_STABLE_BIT with matched/unmatched TSCs\n");
+
+	vm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);
+	configure_pvclock(vm);
+
+	/*
+	 * Case 1: All TSCs matched (same frequency and offset).
+	 * Master clock should be active, PVCLOCK_TSC_STABLE_BIT set.
+	 */
+	run_vcpu_once(vcpus[0]);
+
+	vcpu_get_clock_guest(vcpus[0], &pvti);
+	TEST_ASSERT(pvti.flags & PVCLOCK_TSC_STABLE_BIT,
+		    "PVCLOCK_TSC_STABLE_BIT should be set with matched TSCs");
+
+	/*
+	 * Case 2: Different TSC offset, same frequency.
+	 * Master clock should still be active (frequency matches), but
+	 * PVCLOCK_TSC_STABLE_BIT should be cleared (offsets differ).
+	 */
+	if (__vcpu_has_device_attr(vcpus[1], KVM_VCPU_TSC_CTRL,
+				   KVM_VCPU_TSC_OFFSET)) {
+		pr_info("  Skipping offset test (KVM_VCPU_TSC_OFFSET not supported)\n");
+		goto case_freq;
+	}
+	vcpu_set_tsc_offset(vcpus[1], 12345678);
+	run_vcpu_once(vcpus[1]);
+	run_vcpu_once(vcpus[0]);
+
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti);
+	if (ret) {
+		/*
+		 * Master clock disabled by offset mismatch — old kernel.
+		 * -ENODATA is the only legitimate reason to skip; anything
+		 * else is a regression, not an old kernel.
+		 */
+		TEST_ASSERT(errno == ENODATA,
+			    "GET_CLOCK_GUEST failed with unexpected errno %d", errno);
+		pr_info("  Skipping offset test (master clock requires matched offsets)\n");
+		goto case_freq;
+	}
+	TEST_ASSERT(!(pvti.flags & PVCLOCK_TSC_STABLE_BIT),
+		    "PVCLOCK_TSC_STABLE_BIT should be clear with offset-mismatched TSCs");
+
+case_freq:
+	/*
+	 * Case 3: Different TSC frequency.
+	 * Master clock should be disabled entirely.
+	 */
+	vcpu_ioctl(vcpus[1], KVM_SET_TSC_KHZ,
+		   (void *)(unsigned long)(__vcpu_ioctl(vcpus[1], KVM_GET_TSC_KHZ, NULL) / 2));
+	/* Write TSC to trigger kvm_synchronize_tsc / kvm_track_tsc_matching */
+	vcpu_set_msr(vcpus[1], MSR_IA32_TSC, 0);
+	run_vcpu_once(vcpus[1]);
+
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti);
+	TEST_ASSERT(ret && errno == ENODATA,
+		    "GET_CLOCK_GUEST should fail with frequency-mismatched TSCs, got %d (errno %d)",
+		    ret, errno);
+
+	kvm_vm_free(vm);
+}
+
+static void test_clock_guest_with_offsets(void)
+{
+	struct pvclock_vcpu_time_info pvti0, pvti1, pvti1_after;
+	struct kvm_vcpu *vcpus[2];
+	struct kvm_vm *vm;
+	s64 delta;
+	int ret;
+
+	pr_info("Testing KVM_[GS]ET_CLOCK_GUEST with different TSC offsets\n");
+
+	vm = vm_create_with_vcpus(2, guest_code_stable_bit, vcpus);
+	configure_pvclock(vm);
+
+	/* Set different TSC offsets on the two vCPUs */
+	vcpu_set_tsc_offset(vcpus[0], 0);
+	vcpu_set_tsc_offset(vcpus[1], 1000000000ull);
+
+	/* Run both to establish kvmclock */
+	run_vcpu_once(vcpus[0]);
+	run_vcpu_once(vcpus[1]);
+
+	/* GET_CLOCK_GUEST on both — should succeed (master clock active) */
+	ret = __vcpu_get_clock_guest(vcpus[0], &pvti0);
+	if (ret) {
+		TEST_ASSERT(errno == ENODATA,
+			    "GET_CLOCK_GUEST failed with unexpected errno %d", errno);
+		pr_info("  Skipping (master clock requires matched offsets on this kernel)\n");
+		kvm_vm_free(vm);
+		return;
+	}
+	vcpu_get_clock_guest(vcpus[1], &pvti1);
+
+	/* The tsc_timestamps should differ (different offsets) */
+	TEST_ASSERT(pvti0.tsc_timestamp != pvti1.tsc_timestamp,
+		    "tsc_timestamps should differ with different offsets");
+
+	/* Sleep to let time elapse, then restore vcpu0's clock */
+	sleep(1);
+	vcpu_set_clock_guest(vcpus[0], &pvti0);
+
+	/* Run vcpu0 to process the clock update */
+	run_vcpu_once(vcpus[0]);
+
+	/*
+	 * After SET on vcpu0, verify the correction worked by getting
+	 * the clock on vcpu0 again. The mul/shift should be the same,
+	 * and computing kvmclock at the same TSC should give the same
+	 * result as the original (within ±2ns).
+	 */
+	{
+		struct pvclock_vcpu_time_info pvti0_after;
+		u64 tsc_now, clk_from_old, clk_from_new;
+
+		vcpu_get_clock_guest(vcpus[0], &pvti0_after);
+
+		TEST_ASSERT(pvti0_after.tsc_to_system_mul == pvti0.tsc_to_system_mul &&
+			    pvti0_after.tsc_shift == pvti0.tsc_shift,
+			    "mul/shift changed across KVM_SET_CLOCK_GUEST");
+
+		tsc_now = pvti0_after.tsc_timestamp;
+		clk_from_old = pvclock_read_cycles(&pvti0, tsc_now);
+		clk_from_new = pvclock_read_cycles(&pvti0_after, tsc_now);
+
+		delta = (s64)clk_from_new - (s64)clk_from_old;
+		TEST_ASSERT(delta >= -2 && delta <= 2,
+			    "clock correction delta should be <=2ns, got %ld ns",
+			    delta);
+	}
+
+	/*
+	 * Also verify that vcpu1's clock is still accessible (master
+	 * clock still active with different offsets).
+	 */
+	vcpu_get_clock_guest(vcpus[1], &pvti1_after);
+
+	kvm_vm_free(vm);
+}
diff --git a/tools/testing/selftests/kvm/x86/tsc_user_set_test.c b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c
new file mode 100644
index 00000000000000..a74eb78a975b2f
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/tsc_user_set_test.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that the first userspace write to MSR_IA32_TSC takes effect
+ * precisely, and is not subjected to the 1-second "slop" heuristic
+ * which is only supposed to apply between successive *userspace*
+ * writes (kvm->arch.user_set_tsc).
+ *
+ * The kernel synchronizes the TSC internally when a vCPU is created
+ * (and when its frequency is set). If any of those kernel-internal
+ * paths incorrectly sets user_set_tsc, then the first genuine write
+ * from userspace which happens to fall within 1 second of virtual
+ * cycle time of the kernel's default generation is "corrected" to
+ * match that generation instead of being honoured exactly. That
+ * breaks the restore of a guest which has genuinely been running
+ * for less than one second.
+ *
+ * Simulate exactly that: create a vCPU (kernel establishes a default
+ * TSC generation starting near zero), then perform the first
+ * host-initiated write with a value corresponding to ~500ms of guest
+ * runtime. If the slop heuristic fires, the written value is snapped
+ * back to the kernel's generation (near zero) and the TSC reads back
+ * hundreds of milliseconds low. Repeat with an explicit
+ * KVM_SET_TSC_KHZ on the never-run vCPU before the write: that is
+ * another kernel-internal synchronization which must not arm the
+ * heuristic (nor open a generation that swallows the first write).
+ */
+#include "kvm_util.h"
+#include "processor.h"
+
+/*
+ * Returns false when the attempt was inconclusive: a snapped-back value
+ * tracks time since vCPU creation, so if creation-to-write time gets
+ * anywhere near the written 500ms, a buggy kernel's value could land
+ * inside the assertions' tolerance and pass. The caller retries.
+ */
+static bool test_first_write(bool set_freq)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	u64 freq_khz, t_write, t_read, slack_cycles, mono_ns, create_ns, read_ns;
+	struct timespec ts;
+	int r;
+
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	create_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+
+	if (set_freq) {
+		/*
+		 * Halve the frequency so this is a real change, exercising
+		 * the frequency resynchronization path rather than the
+		 * unchanged-frequency no-op.
+		 */
+		r = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+		TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ failed");
+		vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ,
+			   (void *)(unsigned long)(r / 2));
+	}
+
+	r = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	TEST_ASSERT(r > 0, "KVM_GET_TSC_KHZ failed");
+	freq_khz = r;
+
+	/*
+	 * The first user write: a guest TSC corresponding to 500ms of
+	 * runtime. This is within 1s (of virtual cycle time) of the
+	 * kernel's default generation, so it is exactly the case that
+	 * the slop heuristic would destroy if it were (incorrectly)
+	 * armed by the kernel's own internal TSC synchronization.
+	 */
+	t_write = freq_khz * 500ULL;		/* khz * ms = cycles */
+
+	/*
+	 * Measure only the write..read window (a window measured from
+	 * before creation would also bound a snapped-back value), and
+	 * insist the write lands well before 500ms of creation time so
+	 * a snapped-back value cannot sit inside the tolerance.
+	 */
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	mono_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	if (mono_ns - create_ns > 250000000ULL) {
+		pr_info("  creation took %lu ms, retrying for a conclusive run\n",
+			(mono_ns - create_ns) / 1000000);
+		kvm_vm_free(vm);
+		return false;
+	}
+
+	vcpu_set_msr(vcpu, MSR_IA32_TSC, t_write);
+
+	t_read = vcpu_get_msr(vcpu, MSR_IA32_TSC);
+
+	clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	read_ns = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+	/*
+	 * Bound the whole creation..read interval too: a snapped-back
+	 * value tracks it, so letting it approach the written 500ms
+	 * (via a stall between the two MSR ioctls, which the slack
+	 * below would otherwise absorb) would let a buggy kernel pass.
+	 */
+	if (read_ns - create_ns > 400000000ULL) {
+		pr_info("  creation..read took %lu ms, retrying for a conclusive run\n",
+			(read_ns - create_ns) / 1000000);
+		kvm_vm_free(vm);
+		return false;
+	}
+
+	mono_ns = read_ns - mono_ns;
+
+	/*
+	 * The TSC advances between the write and the read; bound the
+	 * difference by the measured elapsed time around the two ioctls
+	 * plus 10ms of slop, so a descheduled test cannot flake. If the
+	 * write was snapped to the kernel's default generation, the
+	 * value read back is ~500ms low (i.e. below t_write), which is
+	 * unambiguous.
+	 */
+	slack_cycles = freq_khz * (mono_ns / 1000000ULL + 10);
+
+	TEST_ASSERT(t_read >= t_write,
+		    "TSC went backwards from explicit write: wrote %lu, read %lu"
+		    " (first userspace write was subjected to 1-second slop?)",
+		    t_write, t_read);
+	TEST_ASSERT(t_read - t_write < slack_cycles,
+		    "TSC read back too far from written value: wrote %lu, read %lu",
+		    t_write, t_read);
+
+	kvm_vm_free(vm);
+	return true;
+}
+
+static void run_first_write(bool set_freq)
+{
+	int i;
+
+	for (i = 0; i < 5; i++)
+		if (test_first_write(set_freq))
+			return;
+
+	TEST_FAIL("vCPU creation repeatedly too slow for a conclusive run");
+}
+
+int main(void)
+{
+	run_first_write(false);
+
+	if (kvm_has_cap(KVM_CAP_TSC_CONTROL))
+		run_first_write(true);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c
new file mode 100644
index 00000000000000..70d3d38966f239
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test that userspace can correctly populate Xen and generic CPUID
+ * timing leaves using KVM_GET_TSC_KHZ and KVM_VCPU_TSC_SCALE.
+ *
+ * This validates that the removal of KVM's runtime Xen CPUID modification
+ * doesn't break guests, because userspace has all the information needed.
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+
+#define XEN_CPUID_BASE		0x40000100
+#define XEN_CPUID_LEAF(n)	(XEN_CPUID_BASE + (n))
+#define GENERIC_TIMING_LEAF	0x40000010
+
+/*
+ * Sentinel in Xen leaf 3 sub-leaf 2 EAX (where the removed runtime
+ * update used to write the vCPU's tsc_khz): it must survive untouched.
+ */
+#define XEN_SENTINEL		0xdeadbeef
+
+/* Values set by host, verified by guest */
+static u32 expected_tsc_khz;
+static u32 expected_bus_khz;
+static u32 expected_tsc_mul;
+static s8   expected_tsc_shift;
+static u64 host_khz;
+static bool xen_enabled;
+
+static void guest_code(void)
+{
+	u32 eax, ebx, ecx, edx;
+
+	/* Check generic timing leaf 0x40000010 */
+	__cpuid(GENERIC_TIMING_LEAF, 0, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(eax, expected_tsc_khz);
+	GUEST_ASSERT_EQ(ebx, expected_bus_khz);
+
+	/* Check Xen leaf 3, sub-leaf 0: ECX = guest TSC frequency */
+	__cpuid(XEN_CPUID_LEAF(3), 0, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(ecx, expected_tsc_khz);
+
+	/* Check Xen leaf 3, sub-leaf 1: ECX = mul, EDX = shift */
+	__cpuid(XEN_CPUID_LEAF(3), 1, &eax, &ebx, &ecx, &edx);
+	GUEST_ASSERT_EQ(ecx, expected_tsc_mul);
+	GUEST_ASSERT_EQ((s8)edx, expected_tsc_shift);
+
+	if (xen_enabled) {
+		/*
+		 * With the Xen signature present and Xen enabled, verify the
+		 * sentinel survives: KVM's removed runtime CPUID update used
+		 * to clobber this sub-leaf for exactly this configuration.
+		 */
+		__cpuid(XEN_CPUID_LEAF(3), 2, &eax, &ebx, &ecx, &edx);
+		GUEST_ASSERT_EQ(eax, XEN_SENTINEL);
+	}
+
+	GUEST_SYNC(0);
+}
+
+static void add_cpuid_entry(struct kvm_vcpu *vcpu, u32 function,
+			    u32 index, u32 eax, u32 ebx,
+			    u32 ecx, u32 edx)
+{
+	struct kvm_cpuid2 *cpuid = vcpu->cpuid;
+	struct kvm_cpuid_entry2 *entry;
+	int n = cpuid->nent;
+
+	cpuid = realloc(vcpu->cpuid,
+			sizeof(*cpuid) + (n + 1) * sizeof(*entry));
+	TEST_ASSERT(cpuid, "Failed to grow vCPU CPUID array");
+	vcpu->cpuid = cpuid;
+	cpuid->nent = n + 1;
+
+	entry = &cpuid->entries[n];
+	memset(entry, 0, sizeof(*entry));
+	entry->function = function;
+	entry->index = index;
+	entry->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+	entry->eax = eax;
+	entry->ebx = ebx;
+	entry->ecx = ecx;
+	entry->edx = edx;
+}
+
+/*
+ * Compute pvclock mul/shift from frequency, matching kvm_get_time_scale().
+ */
+static void compute_tsc_mul_shift(u64 tsc_hz, u32 *mul, s8 *shift)
+{
+	u64 scaled = 1000000000ULL;
+	u64 base = tsc_hz;
+	s32 s = 0;
+	u32 base32;
+
+	while (base > scaled * 2 || base >> 32) {
+		base >>= 1;
+		s--;
+	}
+	base32 = (u32)base;
+	while (base32 <= scaled || scaled >> 32) {
+		if (scaled >> 32 || base32 & (1U << 31))
+			scaled >>= 1;
+		else
+			base32 <<= 1;
+		s++;
+	}
+	*mul = (u32)((scaled << 32) / base32);
+	*shift = (s8)s;
+}
+
+static void run_test(u64 tsc_khz)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	u32 effective_tsc_khz, effective_bus_khz;
+	int bus_cycle_ns, ret;
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	if (tsc_khz) {
+		pr_info("Testing at TSC frequency %lu kHz\n", tsc_khz);
+		vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(unsigned long)tsc_khz);
+	} else {
+		pr_info("Testing at native TSC frequency\n");
+	}
+
+	ret = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	TEST_ASSERT(ret > 0, "KVM_GET_TSC_KHZ failed: %d", ret);
+	effective_tsc_khz = ret;
+	bus_cycle_ns = vm_check_cap(vm, KVM_CAP_X86_APIC_BUS_CYCLES_NS);
+	effective_bus_khz = bus_cycle_ns > 0 ? 1000000 / bus_cycle_ns : 1000000;
+
+	pr_info("  Effective TSC: %u kHz, Bus: %u kHz\n", effective_tsc_khz, effective_bus_khz);
+
+	/* Also exercise KVM_VCPU_TSC_SCALE if available */
+	if (!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
+				    KVM_VCPU_TSC_SCALE)) {
+		struct kvm_vcpu_tsc_scale scale;
+
+		vcpu_device_attr_get(vcpu, KVM_VCPU_TSC_CTRL,
+				     KVM_VCPU_TSC_SCALE, &scale);
+		pr_info("  TSC scale: ratio=%llu frac_bits=%llu\n",
+			scale.tsc_ratio, scale.tsc_frac_bits);
+
+		/*
+		 * A requested frequency within tsc_tolerance_ppm of the
+		 * host's does not engage hardware scaling: the effective
+		 * frequency is the requested one but the ratio stays 1.0,
+		 * so the ratio cross-check cannot hold. Skip only that
+		 * check — the CPUID leaf population and guest verification
+		 * below are about the effective frequency and remain valid.
+		 */
+		if (tsc_khz &&
+		    scale.tsc_ratio == (1ULL << scale.tsc_frac_bits)) {
+			pr_info("  Requested frequency within host tolerance; scaling not engaged, skipping ratio cross-check\n");
+		} else if (tsc_khz) {
+			/*
+			 * Verify: applying the ratio to the host TSC frequency
+			 * should give approximately the effective frequency.
+			 */
+			u64 computed = ((__uint128_t)host_khz * scale.tsc_ratio) >> scale.tsc_frac_bits;
+			s64 diff = (s64)computed - (s64)effective_tsc_khz;
+
+			TEST_ASSERT(diff >= -1 && diff <= 1,
+				    "TSC_SCALE ratio mismatch: computed %lu vs effective %u (diff %ld)",
+				    computed, effective_tsc_khz, diff);
+		}
+	}
+
+	compute_tsc_mul_shift((u64)effective_tsc_khz * 1000,
+			      &expected_tsc_mul, &expected_tsc_shift);
+
+	expected_tsc_khz = effective_tsc_khz;
+	expected_bus_khz = effective_bus_khz;
+
+	sync_global_to_guest(vm, expected_tsc_khz);
+	sync_global_to_guest(vm, expected_bus_khz);
+	sync_global_to_guest(vm, expected_tsc_mul);
+	sync_global_to_guest(vm, expected_tsc_shift);
+
+	/* Populate CPUID leaves as a VMM would */
+	add_cpuid_entry(vcpu, GENERIC_TIMING_LEAF, 0,
+			effective_tsc_khz, effective_bus_khz, 0, 0);
+	add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 0,
+			0, 0, effective_tsc_khz, 0);
+	add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 1,
+			0, 0, expected_tsc_mul,
+			(u32)(s32)expected_tsc_shift);
+
+	/*
+	 * Where possible, make this a real Xen guest: install the Xen
+	 * signature leaf and enable the Xen hypercall MSR, which is the
+	 * configuration in which KVM's removed runtime CPUID update used
+	 * to fire, and plant a sentinel where it used to write.
+	 */
+	xen_enabled = kvm_has_cap(KVM_CAP_XEN_HVM);
+	if (xen_enabled) {
+		struct kvm_xen_hvm_config cfg = {
+			.msr = 0x40000200,
+		};
+
+		vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &cfg);
+		add_cpuid_entry(vcpu, XEN_CPUID_BASE, 0, XEN_CPUID_LEAF(4),
+				0x566e6558 /* "XenV" */,
+				0x65584d4d /* "MMXe" */,
+				0x4d4d566e /* "nVMM" */);
+		add_cpuid_entry(vcpu, XEN_CPUID_LEAF(3), 2,
+				XEN_SENTINEL, 0, 0, 0);
+	}
+	sync_global_to_guest(vm, xen_enabled);
+
+	vcpu_set_cpuid(vcpu);
+
+	pr_info("  pvclock mul=%u shift=%d\n", expected_tsc_mul, expected_tsc_shift);
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_SYNC:
+		break;
+	default:
+		TEST_FAIL("Unexpected ucall");
+	}
+
+	kvm_vm_free(vm);
+}
+
+int main(void)
+{
+	u64 freq;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	bool have_tsc_scale;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	have_tsc_scale = !__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL,
+						 KVM_VCPU_TSC_SCALE);
+	host_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL);
+	kvm_vm_free(vm);
+
+	/* Native frequency */
+	run_test(0);
+
+	/* Scaled frequencies, when hardware TSC scaling is available */
+	if (have_tsc_scale) {
+		for (freq = 1000000; freq <= 4000000; freq += 1000000) {
+			if (freq == host_khz)
+				continue;
+			run_test(freq);
+		}
+	} else {
+		pr_info("Skipping scaled frequencies (no TSC scaling)\n");
+	}
+
+	pr_info("PASS: All CPUID timing leaf tests passed\n");
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_migration_test.c b/tools/testing/selftests/kvm/x86/xen_migration_test.c
new file mode 100644
index 00000000000000..564781db3da286
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86/xen_migration_test.c
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test Xen runstate (steal time) preservation across simulated migration.
+ *
+ * Verifies that the kernel correctly accounts the migration gap as
+ * steal time (runnable) when runstate data is saved and restored
+ * precisely, but real time elapses during the migration.
+ *
+ * The key insight: userspace saves the runstate with state=RUNSTATE_runnable
+ * (the vCPU is not running during migration). On restore, the kernel sees
+ * that kvmclock has advanced past state_entry_time, and accounts the
+ * difference as time spent in the runnable state.
+ */
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#include <asm/pvclock-abi.h>
+
+#define SHINFO_GPA	0xc0000000ULL
+#define RUNSTATE_GPA	(SHINFO_GPA + 0x1000)
+
+#define RUNSTATE_running  0
+#define RUNSTATE_runnable 1
+#define RUNSTATE_blocked  2
+#define RUNSTATE_offline  3
+
+/*
+ * The 64-bit (long mode) layout: 'state' is followed by 4 bytes of
+ * padding so state_entry_time is naturally aligned. The VM is placed
+ * in long mode explicitly below; without that, KVM would latch 32-bit
+ * mode (no hypercall-page write ever happens here to latch it from
+ * EFER) and write the packed compat layout instead.
+ */
+struct vcpu_runstate_info {
+	u32 state;
+	u64 state_entry_time;
+	u64 time[4];
+};
+
+static void guest_code(void)
+{
+	volatile struct vcpu_runstate_info *rs =
+		(void *)(unsigned long)RUNSTATE_GPA;
+
+	/* Report runstate times — no need to enable kvmclock MSR,
+	 * the kernel writes runstate using its internal kvmclock. */
+	GUEST_SYNC_ARGS(0, rs->time[RUNSTATE_runnable],
+			rs->time[RUNSTATE_running], 0, 0);
+}
+
+static struct kvm_vm *create_xen_vm(struct kvm_vcpu **vcpu)
+{
+	struct kvm_vm *vm;
+	int xen_caps;
+
+	vm = vm_create_with_one_vcpu(vcpu, guest_code);
+
+	xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM);
+	TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO);
+	TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE);
+
+	/* Map pages */
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    SHINFO_GPA, 1, 2, 0);
+	virt_map(vm, SHINFO_GPA, SHINFO_GPA, 2);
+
+	/* Enable Xen HVM with MSR interception (enables runstate tracking) */
+	struct kvm_xen_hvm_config cfg = {
+		.flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
+		.msr = 0x40000000,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_CONFIG, &cfg);
+
+	/* The guest runs in long mode; make the runstate layout match. */
+	struct kvm_xen_hvm_attr lm = {
+		.type = KVM_XEN_ATTR_TYPE_LONG_MODE,
+		.u.long_mode = 1,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &lm);
+
+	/* Set shared_info */
+	struct kvm_xen_hvm_attr ha = {
+		.type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
+		.u.shared_info.gfn = SHINFO_GPA >> 12,
+	};
+	vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &ha);
+
+	/* Set runstate address */
+	struct kvm_xen_vcpu_attr rs_addr = {
+		.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
+		.u.gpa = RUNSTATE_GPA,
+	};
+	vcpu_ioctl(*vcpu, KVM_XEN_VCPU_SET_ATTR, &rs_addr);
+
+	return vm;
+}
+
+int main(void)
+{
+	struct pvclock_vcpu_time_info pvti;
+	struct kvm_xen_vcpu_attr runstate_save;
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct ucall uc;
+	u64 tsc_offset;
+	int ret;
+
+	TEST_REQUIRE(sys_clocksource_is_based_on_tsc());
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_CLOCK_GUEST));
+
+	/* === SOURCE SIDE === */
+	pr_info("=== Source: create VM and run guest ===\n");
+	vm = create_xen_vm(&vcpu);
+
+	/* Run guest once to accumulate some runstate time */
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+
+	pr_info("  Guest sees: runnable=%" PRIu64 " running=%" PRIu64 "\n",
+		uc.args[2], uc.args[3]);
+
+	/* Save clock state */
+	vcpu_get_clock_guest(vcpu, &pvti);
+
+	/*
+	 * Save the guest TSC offset. This test migrates to a new VM on
+	 * the same host, so restoring the same offset makes the guest
+	 * TSC continue uninterrupted across the migration gap, and the
+	 * restored pvclock (KVM_SET_CLOCK_GUEST) then yields a kvmclock
+	 * which has also kept running across the gap. (A real migration
+	 * to a different host would compute the destination offset from
+	 * KVM_GET_CLOCK's {host_tsc, realtime} pair as described in
+	 * Documentation/virt/kvm/devices/vcpu.rst.)
+	 */
+	tsc_offset = vcpu_get_tsc_offset(vcpu);
+
+	/* Save runstate — the vCPU is now "runnable" (not running) */
+	runstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;
+	vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &runstate_save);
+
+	/*
+	 * Transition to runnable state before saving — the vCPU is
+	 * not running during migration.
+	 */
+	runstate_save.u.runstate.state = RUNSTATE_runnable;
+
+	pr_info("  Saved runstate: running=%" PRIu64 " runnable=%" PRIu64
+		" entry=%" PRIu64 "\n",
+		(u64)runstate_save.u.runstate.time_running,
+		(u64)runstate_save.u.runstate.time_runnable,
+		(u64)runstate_save.u.runstate.state_entry_time);
+
+	u64 saved_runnable = runstate_save.u.runstate.time_runnable;
+
+	kvm_vm_free(vm);
+
+	/* === MIGRATION GAP === */
+	pr_info("=== Simulating migration (sleeping 10ms) ===\n");
+	usleep(10000);
+
+	/* === DESTINATION SIDE === */
+	pr_info("=== Destination: create new VM and restore ===\n");
+	vm = create_xen_vm(&vcpu);
+
+	/* Restore the guest TSC offset (same host: TSC continues) */
+	vcpu_set_tsc_offset(vcpu, tsc_offset);
+
+	/* Restore clock — kvmclock will now be ~10ms ahead of the snapshot */
+	vcpu_set_clock_guest(vcpu, &pvti);
+
+	/* Restore runstate exactly as saved (state=runnable) */
+	runstate_save.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA;
+	ret = __vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &runstate_save);
+	TEST_ASSERT(!ret, "Restore runstate failed: errno %d", errno);
+
+	/*
+	 * Run the guest. When the vCPU enters vcpu_run, the kernel
+	 * transitions from RUNSTATE_runnable to RUNSTATE_running.
+	 * It computes: delta = kvmclock_now - state_entry_time
+	 * This delta (which includes the migration gap) is added to
+	 * time_runnable (steal time).
+	 */
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
+
+	u64 guest_runnable = uc.args[2];
+	u64 guest_running = uc.args[3];
+
+	pr_info("  Guest sees: runnable=%" PRIu64 " running=%" PRIu64 "\n",
+		guest_runnable, guest_running);
+
+	u64 steal_increase = guest_runnable - saved_runnable;
+	pr_info("  Steal time increase: %" PRIu64 " ns (migration gap)\n",
+		steal_increase);
+
+	/*
+	 * The steal time increase should be at least 10ms (the sleep).
+	 * The actual gap runs from the source's state_entry_time to the
+	 * destination's kvmclock "now" at vcpu_load time, which includes
+	 * everything from the source guest's last runstate transition
+	 * through VM teardown and re-creation — so the upper bound exists
+	 * only to catch wild miscalculation (e.g. an unscaled TSC delta),
+	 * and is deliberately generous for slow or loaded hosts.
+	 */
+	TEST_ASSERT(steal_increase >= 10000000ULL &&
+		    steal_increase < 60000000000ULL,
+		    "Steal time increase %" PRIu64 " ns not in expected range "
+		    "[10ms, 60s]", steal_increase);
+
+	kvm_vm_free(vm);
+	pr_info("PASS: Migration gap correctly accounted as steal time\n");
+	return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
index aaa414c677addf..43548d8faa74d4 100644
--- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
+++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
@@ -98,22 +98,7 @@ struct sched_poll {
 	u64 timeout;
 };
 
-struct pvclock_vcpu_time_info {
-	u32   version;
-	u32   pad0;
-	u64   tsc_timestamp;
-	u64   system_time;
-	u32   tsc_to_system_mul;
-	s8    tsc_shift;
-	u8    flags;
-	u8    pad[2];
-} __attribute__((__packed__)); /* 32 bytes */
-
-struct pvclock_wall_clock {
-	u32   version;
-	u32   sec;
-	u32   nsec;
-} __attribute__((__packed__));
+#include <asm/pvclock-abi.h>
 
 struct vcpu_runstate_info {
 	u32 state;
@@ -987,12 +972,14 @@ int main(int argc, char *argv[])
 
 	if (verbose) {
 		printf("Wall clock (v %d) %d.%09d\n", wc->version, wc->sec, wc->nsec);
-		printf("Time info 1: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n",
-		       ti->version, ti->tsc_timestamp, ti->system_time, ti->tsc_to_system_mul,
-		       ti->tsc_shift, ti->flags);
-		printf("Time info 2: v %u tsc %" PRIu64 " time %" PRIu64 " mul %u shift %u flags %x\n",
-		       ti2->version, ti2->tsc_timestamp, ti2->system_time, ti2->tsc_to_system_mul,
-		       ti2->tsc_shift, ti2->flags);
+		printf("Time info 1: v %u tsc %llu time %llu mul %u shift %d flags %x\n",
+		       ti->version, (unsigned long long)ti->tsc_timestamp,
+		       (unsigned long long)ti->system_time,
+		       ti->tsc_to_system_mul, ti->tsc_shift, ti->flags);
+		printf("Time info 2: v %u tsc %llu time %llu mul %u shift %d flags %x\n",
+		       ti2->version, (unsigned long long)ti2->tsc_timestamp,
+		       (unsigned long long)ti2->system_time,
+		       ti2->tsc_to_system_mul, ti2->tsc_shift, ti2->flags);
 	}
 
 	TEST_ASSERT(wc->version && !(wc->version & 1),

23/3 2026/11/11 17:20 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 60581
							output: 25
							thoughts: 1923
						

Thoughts:
**KMSAN Evaluation: Patch Series Analysis**

Alright, let's dissect this patch series and determine if we need to bring in KMSAN. The goal is to avoid KMSAN if standard checks are sufficient, so we need to be very thorough.

First off, it appears we're dealing with KVM and some x86 architecture-specific code related to timekeeping, TSC, and clock synchronization. The patch modifies headers, adds new structures, and changes some ioctls. I need to focus on where uninitialized memory *could* rear its ugly head.

*   **Header Files:** The added fields in `kvm_vcpu_arch` and `kvm_arch` look straightforward: new members, but they don't *in themselves* scream "uninitialized". I'll keep an eye on how they are *used* later. The same goes for the new `struct kvm_vcpu_tsc_scale` and the changes to `struct pvclock_vcpu_time_info`.

*   **`KVM_VCPU_TSC_SCALE` ioctl:** This is where things get interesting. We're copying data *to* the user, so a bug here would expose uninitialized memory. But the code explicitly initializes `scale.tsc_ratio` and `scale.tsc_frac_bits` *before* the `copy_to_user`. I've double-checked the structure layout (no padding) and I'm confident. No risk here.

*   **`KVM_GET_CLOCK_GUEST` ioctl:** The use of `{}` for initialization is exactly what I like to see. The `hv_clock` struct is zero-initialized before the `copy_to_user`. The `__attribute__((__packed__))` attribute tells me no compiler padding and that the struct size is 32 bytes as expected. Completely safe.

*   **`KVM_SET_CLOCK_GUEST` ioctl:** Data is copied *from* user memory *to* the stack, so the risk is low.

*   **`kvm_vm_ioctl_set_clock`:** The use of `{}` to zero-initialize the `snap` struct is great.

*   **`kvm_arch_init_vm`:** The variables `kvmclock_ns` and `kvmclock_host_tsc` are initialized via `kvm_get_time_and_clockread`. If the call returns an error, the variables are initialized to other values. The implementation of `kvm_get_time_and_clockread` needs to be checked, though, to verify that it is correct.

**Conclusion:**

Based on this review, I don't see any obvious uninitialized memory risks. The critical paths all initialize memory before it's copied to user space, and the data structures look clean. It looks like standard bug detectors should suffice. I'll need to double-check that `kvm_get_time_and_clockread` is solid, just to be sure, but I'm leaning towards *not* needing KMSAN for this patch series.



24/3 2026/11/11 17:21 tool grepper
0m Args:
{
  "Expression": "kvm_get_time_and_clockread"
}

Results:
{
  "Output": "arch/x86/kvm/x86.c=211=module_param(mitigate_smt_rsb, bool, 0444);\n--\narch/x86/kvm/x86.c-213-#ifdef CONFIG_X86_64\narch/x86/kvm/x86.c:214:static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);\narch/x86/kvm/x86.c-215-#endif\n--\narch/x86/kvm/x86.c=1025=static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)\n--\narch/x86/kvm/x86.c-1068-#ifdef CONFIG_X86_64\narch/x86/kvm/x86.c:1069:\tif (!kvm_get_time_and_clockread(\u0026ns, \u0026host_tsc))\narch/x86/kvm/x86.c-1070-#endif\n--\narch/x86/kvm/x86.c=1592=void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)\n--\narch/x86/kvm/x86.c-1597-#ifdef CONFIG_X86_64\narch/x86/kvm/x86.c:1598:\tif (!kvm_get_time_and_clockread(\u0026ns, \u0026host_tsc))\narch/x86/kvm/x86.c-1599-#endif\n--\narch/x86/kvm/x86.c=1610=static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap,\n--\narch/x86/kvm/x86.c-1637- */\narch/x86/kvm/x86.c:1638:static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp)\narch/x86/kvm/x86.c-1639-{\n--\narch/x86/kvm/x86.c=1730=static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n--\narch/x86/kvm/x86.c-1741-\t */\narch/x86/kvm/x86.c:1742:\thost_tsc_clocksource = kvm_get_time_and_clockread(\narch/x86/kvm/x86.c-1743-\t\t\t\t\t\u0026ka-\u003emaster_kernel_ns,\n--\narch/x86/kvm/x86.c=2026=int kvm_guest_time_update(struct kvm_vcpu *v)\n--\narch/x86/kvm/x86.c-2047-\narch/x86/kvm/x86.c:2048:\t\tif (!kvm_get_time_and_clockread(\u0026kernel_ns, \u0026host_tsc)) {\narch/x86/kvm/x86.c-2049-\t\t\tuse_master_clock = false;\n--\narch/x86/kvm/x86.c=10494=int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n--\narch/x86/kvm/x86.c-10573-#ifdef CONFIG_X86_64\narch/x86/kvm/x86.c:10574:\tif (!kvm_get_time_and_clockread(\u0026kvmclock_ns, \u0026kvmclock_host_tsc))\narch/x86/kvm/x86.c-10575-#endif\n"
}

25/3 2026/11/11 17:21 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 64231
							output: 43
							thoughts: 34
						

Thoughts:
Okay, let's dive into this. I'm going to pull up `kvm_get_time_and_clockread` within the `arch/x86/kvm/x86.c` file. I need to get a clear picture of how they're handling time and clock reading within the KVM/x86 context. This function's probably critical for virtual machine performance and accuracy, so I want to understand the mechanics thoroughly. I'm expecting this to involve details about the TSC, HPET, and other timing mechanisms, but I'm curious how they've integrated these concepts. Let's see how they've approached this critical aspect of virtualization.



26/3 2026/11/11 17:21 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 1635,
  "LineCount": 40
}

Results:
{
  "Contents": "1635:\t * reports the TSC value from which it do so. Returns true if host is\n1636:\t * using TSC based clocksource.\n1637:\t */\n1638:\tstatic bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp)\n1639:\t{\n1640:\t\tstruct system_time_snapshot snap = {};\n1641:\t\n1642:\t\tktime_get_snapshot_id(CLOCK_MONOTONIC_RAW, \u0026snap);\n1643:\t\tif (!kvm_snapshot_has_tsc(\u0026snap, tsc_timestamp))\n1644:\t\t\treturn false;\n1645:\t\n1646:\t\t*kernel_ns = ktime_to_ns(ktime_mono_to_any(snap.systime, TK_OFFS_BOOT));\n1647:\t\treturn true;\n1648:\t}\n1649:\t\n1650:\t/*\n1651:\t * Calculates CLOCK_MONOTONIC and reports the TSC value from which it did\n1652:\t * so. Returns true if host is using TSC based clocksource.\n1653:\t */\n1654:\tbool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp)\n1655:\t{\n1656:\t\tstruct system_time_snapshot snap = {};\n1657:\t\n1658:\t\tktime_get_snapshot_id(CLOCK_MONOTONIC, \u0026snap);\n1659:\t\tif (!kvm_snapshot_has_tsc(\u0026snap, tsc_timestamp))\n1660:\t\t\treturn false;\n1661:\t\n1662:\t\t*kernel_ns = ktime_to_ns(snap.systime);\n1663:\t\treturn true;\n1664:\t}\n1665:\t\n1666:\t/*\n1667:\t * Calculates CLOCK_REALTIME and reports the TSC value from which it did\n1668:\t * so. Returns true if host is using TSC based clocksource.\n1669:\t *\n1670:\t * DO NOT USE this for anything related to migration. You want CLOCK_TAI\n1671:\t * for that.\n1672:\t */\n1673:\tstatic bool kvm_get_walltime_and_clockread(struct timespec64 *ts,\n1674:\t\t\t\t\t\t   u64 *tsc_timestamp)\n"
}

27/3 2026/11/11 17:21 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 65112
							output: 39
							thoughts: 1106
						

Thoughts:
**Analyzing KVM Clock Master Logic**

Okay, so I'm looking at this KVM clock code and trying to understand how the master clock is handled, especially in relation to TSC stability and potential discontinuities. The initial check is within `kvm_snapshot_has_tsc`, and I see that `kvm_get_time_and_clockread` is responsible for initializing `*tsc_timestamp` and `*kernel_ns` if it returns true. If not, it falls back to directly reading the host TSC and getting the base nanoseconds, ensuring `host_tsc` and `ns` are always initialized.

Now, diving into `__get_kvmclock_master_clock`, I see this conditional execution.  The code attempts to read the walltime and host TSC through `kvm_get_walltime_and_clockread`, and this provides the `ts`. `data` is set by the caller.

The critical part now lies in how `data->clock` is calculated based on `ka->use_master_clock`.  There are two branches; the first calculates the clock based on scaled TSC deltas, while the second directly uses `__pvclock_read_cycles`.

However, the interesting part is the sanity check. After the calculation of `clock`, there's a check to see if the elapsed time, computed from the host TSC, agrees with the raw clock (effectively the snapshot).  If the disagreement exceeds one second, it means the TSC might have been reset (a suspend/resume scenario where the firmware might arbitrarily re-initialize the TSC). And instead of marking this as a discontinuity, it simply *returns false*.

This is key: if the sanity check fails, the function returns false before touching `data->clock`, `realtime`, and the flags. This is important to understand: there's a fallback path and the data will be consistent.  If it returns true, `data->clock`, `realtime` and `flags` are set.  Now, the main remaining question is how the `data` struct itself is populated by the caller, which I should now explore.



28/3 2026/11/11 17:21 tool grepper
0m Args:
{
  "Expression": "__get_kvmclock_master_clock",
  "PathPrefixes": [
    "arch/x86/kvm"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/x86.c=1884=static unsigned long get_cpu_tsc_khz(void)\n--\narch/x86/kvm/x86.c-1892-/* Called within read_seqcount_begin/retry for kvm-\u003epvclock_sc.  */\narch/x86/kvm/x86.c:1893:static bool __get_kvmclock_master_clock(struct kvm *kvm,\narch/x86/kvm/x86.c-1894-\t\t\t\t\tstruct kvm_clock_data *data)\n--\narch/x86/kvm/x86.c=1956=static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data)\n--\narch/x86/kvm/x86.c-1964-\t\tseq = read_seqcount_begin(\u0026ka-\u003epvclock_sc);\narch/x86/kvm/x86.c:1965:\t\tif (!__get_kvmclock_master_clock(kvm, data))\narch/x86/kvm/x86.c-1966-\t\t\tdata-\u003eclock = get_kvmclock_base_ns() + ka-\u003ekvmclock_offset;\n"
}

29/3 2026/11/11 17:21 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 67042
							output: 43
							thoughts: 21
						

Thoughts:
Here's my thought process, as requested:

**Investigating `get_kvmclock` and Its Usage**

Okay, so I need to dive into `get_kvmclock` and understand its role. That means I need to quickly examine the function itself – what it's doing under the hood. More importantly, I need to trace its call graph.  I want to see *who* is calling it. Understanding the consumers of `get_kvmclock` is crucial. It tells me where this clock information is being used, and therefore, what might be impacted if there are any changes or issues. Finding the callers gives me the complete picture, I can then determine if there are any issues with how it's being used. Now, let's get to it.



30/3 2026/11/11 17:21 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 1955,
  "LineCount": 40
}

Results:
{
  "Contents": "1955:\t\n1956:\tstatic void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data)\n1957:\t{\n1958:\t\tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n1959:\t\tunsigned seq;\n1960:\t\n1961:\t\tdo {\n1962:\t\t\tdata-\u003eflags = 0;\n1963:\t\n1964:\t\t\tseq = read_seqcount_begin(\u0026ka-\u003epvclock_sc);\n1965:\t\t\tif (!__get_kvmclock_master_clock(kvm, data))\n1966:\t\t\t\tdata-\u003eclock = get_kvmclock_base_ns() + ka-\u003ekvmclock_offset;\n1967:\t\t} while (read_seqcount_retry(\u0026ka-\u003epvclock_sc, seq));\n1968:\t}\n1969:\t\n1970:\tu64 get_kvmclock_ns(struct kvm *kvm)\n1971:\t{\n1972:\t\tstruct kvm_clock_data data;\n1973:\t\n1974:\t\tget_kvmclock(kvm, \u0026data);\n1975:\t\treturn data.clock;\n1976:\t}\n1977:\t\n1978:\tstatic void kvm_setup_guest_pvclock(struct pvclock_vcpu_time_info *ref_hv_clock,\n1979:\t\t\t\t\t    struct kvm_vcpu *vcpu,\n1980:\t\t\t\t\t    struct gfn_to_pfn_cache *gpc,\n1981:\t\t\t\t\t    unsigned int offset)\n1982:\t{\n1983:\t\tstruct pvclock_vcpu_time_info *guest_hv_clock;\n1984:\t\tstruct pvclock_vcpu_time_info hv_clock;\n1985:\t\tunsigned long flags;\n1986:\t\n1987:\t\tmemcpy(\u0026hv_clock, ref_hv_clock, sizeof(hv_clock));\n1988:\t\n1989:\t\tread_lock_irqsave(\u0026gpc-\u003elock, flags);\n1990:\t\twhile (!kvm_gpc_check(gpc, offset + sizeof(*guest_hv_clock))) {\n1991:\t\t\tread_unlock_irqrestore(\u0026gpc-\u003elock, flags);\n1992:\t\n1993:\t\t\tif (kvm_gpc_refresh(gpc, offset + sizeof(*guest_hv_clock)))\n1994:\t\t\t\treturn;\n"
}

31/3 2026/11/11 17:21 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 67932
							output: 34
							thoughts: 25
						

Thoughts:
Here's a summary of my thought process, as requested:

**Diving into `kvm_vm_ioctl_get_clock`**

Okay, so I need to understand what's happening with the `data` parameter within the `kvm_vm_ioctl_get_clock` function. That's the key here. My immediate focus is to pinpoint exactly how it's being used, manipulated, or interpreted by that specific ioctl handler. I'm essentially tracing the flow of `data` to see if there are any potential vulnerabilities, unexpected behavior, or just to get a good handle on how the virtual machine clock is exposed to userspace via this interface. It's time to dig in and dissect that function call. Let's see how this thing works.



32/3 2026/11/11 17:21 tool grepper
0m Args:
{
  "Expression": "get_kvmclock",
  "PathPrefixes": [
    "arch/x86/kvm"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/hyperv.c=578=static u64 get_time_ref_counter(struct kvm *kvm)\n--\narch/x86/kvm/hyperv.c-584-\t/*\narch/x86/kvm/hyperv.c:585:\t * Fall back to get_kvmclock_ns() when TSC page hasn't been set up,\narch/x86/kvm/hyperv.c-586-\t * is broken, disabled or being updated.\n--\narch/x86/kvm/hyperv.c-588-\tif (hv-\u003ehv_tsc_page_status != HV_TSC_PAGE_SET)\narch/x86/kvm/hyperv.c:589:\t\treturn div_u64(get_kvmclock_ns(kvm), 100);\narch/x86/kvm/hyperv.c-590-\n--\narch/x86/kvm/x86.c=884=static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/x86.c-891-\narch/x86/kvm/x86.c:892:static s64 get_kvmclock_base_ns(void)\narch/x86/kvm/x86.c-893-{\n--\narch/x86/kvm/x86.c=1025=static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)\n--\narch/x86/kvm/x86.c-1072-\t\thost_tsc = rdtsc();\narch/x86/kvm/x86.c:1073:\t\tns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-1074-\t}\n--\narch/x86/kvm/x86.c=1592=void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *value, bool user_initiated)\n--\narch/x86/kvm/x86.c-1601-\t\thost_tsc = rdtsc();\narch/x86/kvm/x86.c:1602:\t\tns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-1603-\t}\n--\narch/x86/kvm/x86.c=1730=static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n--\narch/x86/kvm/x86.c-1756-\t\t * converting guest TSC to nanoseconds. These are used by\narch/x86/kvm/x86.c:1757:\t\t * get_kvmclock() to compute kvmclock from the host TSC\narch/x86/kvm/x86.c-1758-\t\t * without needing a vCPU reference.\n--\narch/x86/kvm/x86.c=1884=static unsigned long get_cpu_tsc_khz(void)\n--\narch/x86/kvm/x86.c-1892-/* Called within read_seqcount_begin/retry for kvm-\u003epvclock_sc.  */\narch/x86/kvm/x86.c:1893:static bool __get_kvmclock_master_clock(struct kvm *kvm,\narch/x86/kvm/x86.c-1894-\t\t\t\t\tstruct kvm_clock_data *data)\n--\narch/x86/kvm/x86.c-1941-\tif (unlikely(abs((s64)(clock - hv_clock.system_time) -\narch/x86/kvm/x86.c:1942:\t\t\t (get_kvmclock_base_ns() - ka-\u003emaster_kernel_ns)) \u003e\narch/x86/kvm/x86.c-1943-\t\t     NSEC_PER_SEC))\n--\narch/x86/kvm/x86.c-1955-\narch/x86/kvm/x86.c:1956:static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data)\narch/x86/kvm/x86.c-1957-{\n--\narch/x86/kvm/x86.c-1964-\t\tseq = read_seqcount_begin(\u0026ka-\u003epvclock_sc);\narch/x86/kvm/x86.c:1965:\t\tif (!__get_kvmclock_master_clock(kvm, data))\narch/x86/kvm/x86.c:1966:\t\t\tdata-\u003eclock = get_kvmclock_base_ns() + ka-\u003ekvmclock_offset;\narch/x86/kvm/x86.c-1967-\t} while (read_seqcount_retry(\u0026ka-\u003epvclock_sc, seq));\n--\narch/x86/kvm/x86.c-1969-\narch/x86/kvm/x86.c:1970:u64 get_kvmclock_ns(struct kvm *kvm)\narch/x86/kvm/x86.c-1971-{\n--\narch/x86/kvm/x86.c-1973-\narch/x86/kvm/x86.c:1974:\tget_kvmclock(kvm, \u0026data);\narch/x86/kvm/x86.c-1975-\treturn data.clock;\n--\narch/x86/kvm/x86.c=2026=int kvm_guest_time_update(struct kvm_vcpu *v)\n--\narch/x86/kvm/x86.c-2071-\t\thost_tsc = rdtsc();\narch/x86/kvm/x86.c:2072:\t\tkernel_ns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-2073-\t}\n--\narch/x86/kvm/x86.c-2192- * Fall back to using their values at slightly different moments by\narch/x86/kvm/x86.c:2193: * calling ktime_get_real_ns() and get_kvmclock() separately.\narch/x86/kvm/x86.c-2194- */\narch/x86/kvm/x86.c=2195=uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm)\n--\narch/x86/kvm/x86.c-2198-\narch/x86/kvm/x86.c:2199:\tget_kvmclock(kvm, \u0026data);\narch/x86/kvm/x86.c-2200-\narch/x86/kvm/x86.c-2201-\t/*\narch/x86/kvm/x86.c:2202:\t * If get_kvmclock() captured both wallclock and kvmclock from the\narch/x86/kvm/x86.c-2203-\t * same TSC reading, use them for a precise epoch calculation.\n--\narch/x86/kvm/x86.c=3564=static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu,\n--\narch/x86/kvm/x86.c-3587-\t\ttsc = kvm_scale_tsc(rdtsc(), vcpu-\u003earch.l1_tsc_scaling_ratio) + offset;\narch/x86/kvm/x86.c:3588:\t\tns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-3589-\n--\narch/x86/kvm/x86.c=4806=static int kvm_vm_ioctl_get_clock(struct kvm *kvm, void __user *argp)\n--\narch/x86/kvm/x86.c-4809-\narch/x86/kvm/x86.c:4810:\tget_kvmclock(kvm, \u0026data);\narch/x86/kvm/x86.c-4811-\tif (copy_to_user(argp, \u0026data, sizeof(data)))\n--\narch/x86/kvm/x86.c=4817=static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp)\n--\narch/x86/kvm/x86.c-4839-\t * in use, we use master_kernel_ns + kvmclock_offset to set\narch/x86/kvm/x86.c:4840:\t * unsigned 'system_time' so if we use get_kvmclock_ns() (which\narch/x86/kvm/x86.c-4841-\t * is slightly ahead) here we risk going negative on unsigned\n--\narch/x86/kvm/x86.c-4881-\t} else {\narch/x86/kvm/x86.c:4882:\t\tnow_raw_ns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-4883-\t}\n--\narch/x86/kvm/x86.c=10494=int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)\n--\narch/x86/kvm/x86.c-10580-\t\t */\narch/x86/kvm/x86.c:10581:\t\tkvmclock_ns = get_kvmclock_base_ns();\narch/x86/kvm/x86.c-10582-\t\tkvmclock_host_tsc = rdtsc();\n--\narch/x86/kvm/x86.h=326=void kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);\narch/x86/kvm/x86.h-327-\narch/x86/kvm/x86.h:328:u64 get_kvmclock_ns(struct kvm *kvm);\narch/x86/kvm/x86.h-329-uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm);\n--\narch/x86/kvm/xen.c=185=static void kvm_xen_start_timer(struct kvm_vcpu *vcpu, u64 guest_abs,\n--\narch/x86/kvm/xen.c-238-\t\t * which case a masterclock update is already pending and\narch/x86/kvm/xen.c:239:\t\t * get_kvmclock_ns() returns the raw-clock fallback value —\narch/x86/kvm/xen.c-240-\t\t * continuous with the last valid snapshot, which is as good\n--\narch/x86/kvm/xen.c-255-\t\t * Without CONSTANT_TSC and the master clock,\narch/x86/kvm/xen.c:256:\t\t * get_kvmclock_ns() is the only option.\narch/x86/kvm/xen.c-257-\t\t *\n--\narch/x86/kvm/xen.c-262-\t\t * point in doing so. Without the master clock, the\narch/x86/kvm/xen.c:263:\t\t * get_kvmclock_ns() drift accumulates over time, so it's OK\narch/x86/kvm/xen.c-264-\t\t * to use it at startup. Besides, on migration there's going\n--\narch/x86/kvm/xen.c-268-\t\t */\narch/x86/kvm/xen.c:269:\t\tguest_now = get_kvmclock_ns(vcpu-\u003ekvm);\narch/x86/kvm/xen.c-270-\t\tkernel_now = ktime_get();\n--\narch/x86/kvm/xen.c=584=void kvm_xen_update_runstate(struct kvm_vcpu *v, int state)\n--\narch/x86/kvm/xen.c-586-\tstruct kvm_vcpu_xen *vx = \u0026v-\u003earch.xen;\narch/x86/kvm/xen.c:587:\tu64 now = get_kvmclock_ns(v-\u003ekvm);\narch/x86/kvm/xen.c-588-\tu64 run_delay = current-\u003esched_info.run_delay;\n--\narch/x86/kvm/xen.c=933=int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data)\n--\narch/x86/kvm/xen.c-1073-\t\t}\narch/x86/kvm/xen.c:1074:\t\tif (get_kvmclock_ns(vcpu-\u003ekvm) \u003c\narch/x86/kvm/xen.c-1075-\t\t    data-\u003eu.runstate.state_entry_time) {\n--\narch/x86/kvm/xen.c-1114-\narch/x86/kvm/xen.c:1115:\t\tif (get_kvmclock_ns(vcpu-\u003ekvm) \u003c\narch/x86/kvm/xen.c-1116-\t\t    (vcpu-\u003earch.xen.runstate_entry_time +\n"
}

33/3 2026/11/11 17:21 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 71793
							output: 43
							thoughts: 170
						

Thoughts:
Here's my thought process, as requested:

**Deconstructing `kvm_vm_ioctl_get_clock`**

Okay, first things first, I need to understand what this function, `kvm_vm_ioctl_get_clock`, is doing. Let's start with the code snippet provided. Line 4810 gives the function signature, `static int kvm_vm_ioctl_get_clock(struct kvm *kvm, void __user *argp)`. Right, so it's handling a KVM VM ioctl, specifically related to getting the clock data. A `struct kvm *kvm` is passed in, which represents the KVM instance, and `void __user *argp` looks like a pointer to user-space memory where the results will be copied.

Line 4814, `struct kvm_clock_data data;` declares a local `kvm_clock_data` struct. Makes sense, that's what's going to hold the clock information. Then `get_kvmclock(kvm, &data);` is called. That's the core of the operation. I'd need to dig deeper into what `get_kvmclock` does, but it seems to be the function that actually retrieves the clock information for the VM and populates the `data` struct. Finally, we have `copy_to_user(argp, &data, sizeof(data))`, which copies the `data` structure into the user-space buffer pointed to by `argp`.  If that fails, then return -EFAULT on line 4817, otherwise, the function returns 0.

But wait a minute, I want to understand the impact of any changes to this function. Before I get any further, I need to know *what* was changed. So I need to go back and compare the code *before* the patch with *what I'm looking at now*. I'll need to check the surrounding lines (around 4806) to get the context and see how the function looks before the change to fully understand the implications. Gotta know the *before* state to understand the *after* state, especially with something as fundamental as clock handling. That context will tell me what has changed and why.



34/3 2026/11/11 17:22 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 4800,
  "LineCount": 25
}

Results:
{
  "Contents": "4800:\t\t}\n4801:\t\n4802:\t\treturn NOTIFY_DONE;\n4803:\t}\n4804:\t#endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */\n4805:\t\n4806:\tstatic int kvm_vm_ioctl_get_clock(struct kvm *kvm, void __user *argp)\n4807:\t{\n4808:\t\tstruct kvm_clock_data data = { 0 };\n4809:\t\n4810:\t\tget_kvmclock(kvm, \u0026data);\n4811:\t\tif (copy_to_user(argp, \u0026data, sizeof(data)))\n4812:\t\t\treturn -EFAULT;\n4813:\t\n4814:\t\treturn 0;\n4815:\t}\n4816:\t\n4817:\tstatic int kvm_vm_ioctl_set_clock(struct kvm *kvm, void __user *argp)\n4818:\t{\n4819:\t\tstruct kvm_arch *ka = \u0026kvm-\u003earch;\n4820:\t\tstruct kvm_clock_data data;\n4821:\t\tu64 now_raw_ns;\n4822:\t\n4823:\t\tif (copy_from_user(\u0026data, argp, sizeof(data)))\n4824:\t\t\treturn -EFAULT;\n"
}

35/3 2026/11/11 17:22 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 72873
							output: 22
							thoughts: 1288
						

Thoughts:
**Analyzing Potential Uninitialized Memory Leaks in KVM Clock Handling**

Okay, let's break this down systematically. I'm focusing on potential uninitialized memory reads that could lead to security vulnerabilities.  First, `struct kvm_clock_data data = { 0 };` looks safe, as it's zero-initialized right off the bat. Good.

Next, I'm checking `kvm_arch_tsc_get_attr` with the `KVM_VCPU_TSC_SCALE` case.  The code seems concerned with getting the TSC scaling ratio.  I'm looking closely at `struct kvm_vcpu_tsc_scale scale;`. Wait a minute, what's inside that struct? I need to verify that all the fields are initialized before `copy_to_user`. It's defined as two `__u64` fields, and the code *does* initialize both: `scale.tsc_ratio` and `scale.tsc_frac_bits`. No padding either. Therefore, the `copy_to_user` call appears safe in this context, meaning everything in the `scale` structure is initialized before it's sent to userspace.

Now, let's move on to `kvm_vcpu_ioctl_get_clock_guest`. Here, the focus is on retrieving guest clock information.  `struct pvclock_vcpu_time_info hv_clock = {};` is a key line. This explicit initialization to `{}` is critical, meaning all members of `hv_clock` are zeroed. The code *then* populates several fields: `tsc_timestamp`, `system_time`, `tsc_shift`, `tsc_to_system_mul`, and `flags`.  Given the initial zeroing and the subsequent assignments, the `copy_to_user` call here should be fine.  No uninitialized data should be leaking.

Hold on, what about the opposite direction: `KVM_SET_CLOCK_GUEST`? Here, the code *copies* from user space into `struct pvclock_vcpu_time_info user_hv_clock;`.  This is a potential attack vector, as user-provided data can be malicious.  However, the code does a check: `if (user_hv_clock.pad0 || user_hv_clock.pad[0] || user_hv_clock.pad[1])`. That's good, so the code appears to be validating the padded bytes, which is a common security best practice.

Finally, I need to investigate the `set_tsc_khz` function.  It looks like it computes a scale to convert nanoseconds to TSC cycles using `kvm_get_time_scale`. I need to ensure that `kvm_get_time_scale` initializes `tsc_shift` and `tsc_mult`. I'll have to investigate that function to ensure that no uninitialized values are read.



36/3 2026/11/11 17:22 tool grepper
0m Args:
{
  "Expression": "kvm_get_time_scale"
}

Results:
{
  "Output": "arch/x86/kvm/x86.c=898=static uint32_t div_frac(uint32_t dividend, uint32_t divisor)\n--\narch/x86/kvm/x86.c-903-\narch/x86/kvm/x86.c:904:static void kvm_get_time_scale(u64 scaled_hz, u64 base_hz,\narch/x86/kvm/x86.c-905-\t\t\t       s8 *pshift, u32 *pmultiplier)\n--\narch/x86/kvm/x86.c=1025=static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool init)\n--\narch/x86/kvm/x86.c-1042-\t/* Compute a scale to convert nanoseconds in TSC cycles */\narch/x86/kvm/x86.c:1043:\tkvm_get_time_scale(user_tsc_khz * 1000LL, NSEC_PER_SEC,\narch/x86/kvm/x86.c-1044-\t\t\t   \u0026tsc_shift, \u0026tsc_mult);\n--\narch/x86/kvm/x86.c=1730=static void pvclock_update_vm_gtod_copy(struct kvm *kvm)\n--\narch/x86/kvm/x86.c-1765-\t\tif (tsc_hz)\narch/x86/kvm/x86.c:1766:\t\t\tkvm_get_time_scale(NSEC_PER_SEC, tsc_hz,\narch/x86/kvm/x86.c-1767-\t\t\t\t\t   \u0026ka-\u003emaster_tsc_shift,\n--\narch/x86/kvm/x86.c=2026=int kvm_guest_time_update(struct kvm_vcpu *v)\n--\narch/x86/kvm/x86.c-2111-\tif (unlikely(vcpu-\u003ehw_tsc_hz != tgt_tsc_hz)) {\narch/x86/kvm/x86.c:2112:\t\tkvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_hz,\narch/x86/kvm/x86.c-2113-\t\t\t\t   \u0026vcpu-\u003epvclock_tsc_shift,\n--\ntools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c=67=static void add_cpuid_entry(struct kvm_vcpu *vcpu, u32 function,\n--\ntools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c-92-/*\ntools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c:93: * Compute pvclock mul/shift from frequency, matching kvm_get_time_scale().\ntools/testing/selftests/kvm/x86/xen_cpuid_timing_test.c-94- */\n"
}

37/3 2026/11/11 17:22 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 75634
							output: 42
							thoughts: 14
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing the `kvm_get_time_scale` Function**

Alright, let's dive into `kvm_get_time_scale`. I immediately want to understand its purpose within the KVM architecture. My initial thought is likely about what problem this function is solving. Is it related to virtual timekeeping, guest-host synchronization, or something else entirely? Given the name, I'd wager it has something to do with time scales, but the specifics are what I need to unpack. I'll need to look at the surrounding code to determine how it's used.

My immediate questions are about the source of the time scale information. Is it being pulled from the hardware directly, or calculated based on some internal KVM state? Are there any potential race conditions I need to be aware of if multiple vCPUs are calling this concurrently? Does this function use any locking mechanisms, or is the information assumed to be immutable?

Beyond the implementation details, I'm thinking about the implications for performance. How computationally expensive is this call? Is it optimized for frequent access, or is it more of a "rarely-needed" utility function? Does it affect the overall performance of the virtual machine? I'll probably also need to consider any potential interactions with time-related features like TSC (Time Stamp Counter) or other hardware counters. It would be smart to review how the function fits into the overall KVM timekeeping infrastructure, and any interactions with the guest operating system’s notion of time. I'll be looking for potential sources of drift, or avenues for manipulation by the guest, especially if it returns an unvalidated value. In short, let's dig in and see how this time scale works!



38/3 2026/11/11 17:22 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 904,
  "LineCount": 35
}

Results:
{
  "Contents": " 904:\tstatic void kvm_get_time_scale(u64 scaled_hz, u64 base_hz,\n 905:\t\t\t\t       s8 *pshift, u32 *pmultiplier)\n 906:\t{\n 907:\t\tu64 scaled_hz_u64 = scaled_hz;\n 908:\t\ts32 shift = 0;\n 909:\t\tu64 base_hz_u64;\n 910:\t\tu32 base32;\n 911:\t\n 912:\t\t/*\n 913:\t\t * This function calculates a fixed-point multiplier and shift such\n 914:\t\t * that:\n 915:\t\t *   time_ns = (tsc_cycles \u003c\u003c shift) * multiplier \u003e\u003e 32\n 916:\t\t *\n 917:\t\t * Where tsc_cycles tick at base_hz, and time_ns should count at\n 918:\t\t * scaled_hz (typically NSEC_PER_SEC for a TSC→nanoseconds conversion).\n 919:\t\t *\n 920:\t\t * The multiplier is: (scaled_hz \u003c\u003c 32) / base_hz, adjusted by shift\n 921:\t\t * to keep everything in range.\n 922:\t\t */\n 923:\t\n 924:\t\tbase_hz_u64 = base_hz;\n 925:\t\n 926:\t\t/*\n 927:\t\t * Start by shifting base_hz right until it fits in 32 bits, and\n 928:\t\t * is lower than double the target rate. This introduces a negative\n 929:\t\t * shift value which would result in pvclock_scale_delta() shifting\n 930:\t\t * the actual tick count right before performing the multiplication.\n 931:\t\t */\n 932:\t\twhile (base_hz_u64 \u003e scaled_hz_u64 * 2 || base_hz_u64 \u003e\u003e 32) {\n 933:\t\t\tbase_hz_u64 \u003e\u003e= 1;\n 934:\t\t\tshift--;\n 935:\t\t}\n 936:\t\n 937:\t\t/* Now the shifted base_hz fits in 32 bits. */\n 938:\t\tbase32 = (u32)base_hz_u64;\n"
}

39/3 2026/11/11 17:22 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 76668
							output: 42
							thoughts: 17
						

Thoughts:
Okay, here's my interpretation of that request, formatted as requested:

**Deconstructing `kvm_get_time_scale`**

Alright, so the task at hand is to understand `kvm_get_time_scale`. I need to dig into this function and understand its purpose and operation. Given my expertise, I'm already anticipating this will be related to managing or interpreting time within the Kernel Virtual Machine (KVM) environment. This could involve scaling factors, converting between guest and host time, or something along those lines. The phrase "Let's read the rest" implies there's context and code available that I need to analyze. My focus shifts to understanding the specific implementation details. The structure of the code, variables, and any conditional logic within that function will illuminate its function. I expect to be able to extract a clear understanding of its role in the overall system after I carefully read the function's code. I'm ready to move forward.



40/3 2026/11/11 17:23 tool read-file
0m Args:
{
  "File": "arch/x86/kvm/x86.c",
  "FirstLine": 939,
  "LineCount": 30
}

Results:
{
  "Contents": " 939:\t\n 940:\t\t/*\n 941:\t\t * Next, shift scaled_hz right until it fits in 32 bits, and ensure\n 942:\t\t * that the shifted base_hz is strictly larger (so that the result of the\n 943:\t\t * final division also fits in 32 bits).\n 944:\t\t */\n 945:\t\twhile (base32 \u003c= scaled_hz_u64 || scaled_hz_u64 \u003e\u003e 32) {\n 946:\t\t\tif (scaled_hz_u64 \u003e\u003e 32 || base32 \u0026 BIT(31))\n 947:\t\t\t\tscaled_hz_u64 \u003e\u003e= 1;\n 948:\t\t\telse\n 949:\t\t\t\tbase32 \u003c\u003c= 1;\n 950:\t\t\tshift++;\n 951:\t\t}\n 952:\t\n 953:\t\t*pshift = shift;\n 954:\t\t*pmultiplier = div_frac(scaled_hz_u64, base32);\n 955:\t}\n 956:\t\n 957:\t#ifdef CONFIG_X86_64\n 958:\tstatic atomic_t kvm_guest_has_master_clock = ATOMIC_INIT(0);\n 959:\t#endif\n 960:\t\n 961:\tstatic DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);\n 962:\tstatic unsigned long max_tsc_khz;\n 963:\t\n 964:\tstatic u32 adjust_tsc_khz(u32 khz, s32 ppm)\n 965:\t{\n 966:\t\tu64 v = (u64)khz * (1000000 + ppm);\n 967:\t\tdo_div(v, 1000000);\n 968:\t\treturn v;\n"
}

41/3 2026/11/11 17:23 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 77429
							output: 33
							thoughts: 1228
						

Thoughts:
**Analysis of KVM Clock and TSC Initialization**

Okay, let's break down this KVM clock and TSC initialization code. My initial observation is that `kvm_get_time_scale` is very reliable – it *always* writes to the provided pointers, `*pshift` and `*pmultiplier`. This is important because it sets the foundation for subsequent calculations.

Now, looking at `kvm_set_tsc_khz`, the code uses `kvm_get_time_scale` to compute `tsc_shift` and `tsc_mult`. These values are directly tied to the user-provided TSC frequency (`user_tsc_khz`). Critically, these variables are *fully initialized* before being assigned to the `vcpu`'s `arch` structure. This gives me confidence that we are dealing with a well-defined state at this point.

Next, I examined `kvm_vm_ioctl_set_clock`. Here, if the `KVM_CLOCK_REALTIME` flag is set, the code takes a snapshot of `CLOCK_REALTIME` and `CLOCK_MONOTONIC_RAW` using `ktime_get_snapshot_id`. The crucial point is that a `struct system_time_snapshot snap` is initialized using `{}`. Then, the real-time nanoseconds are obtained.  This approach maintains coherence between the real time clock and raw monotonic clock.

Moving on to `kvm_arch_init_vm`, I see the initialization of various `kvm->arch` fields, including flags related to TSC frequency matching. Importantly, `kvmclock_ns` and `kvmclock_host_tsc` are written in both branches of the conditional (`kvm_get_time_and_clockread` or the fallback block). The values are derived either from a potentially host-provided method or from an internal fallback if needed. `kvm->arch.cur_tsc_offset` is then derived from `kvmclock_host_tsc`, and I need to consider potential edge cases where these initial values might not be what the user expects.

Finally, `kvm_vcpu_ioctl_set_clock_guest` and specifically how it handles the input `user_hv_clock`. This copies user-provided data. The code then meticulously checks several fields for validity: the `pad` fields (ensuring they are zero), a non-zero `tsc_to_system_mul`, and a valid `tsc_shift` range.  It then calculates `user_tsc_hz`.  I can confirm that no uninitialized variable are being used in this part.

My next step is to examine how the `kvm_vcpu` or `kvm_vcpu_arch` structures are allocated to verify that they are zero-initialized or otherwise properly handled during memory allocation. I'm noting the addition of `this_tsc_freq_generation` and `user_set_tsc` to `kvm_vcpu_arch` and need to track where these fields are set and used.



42/3 2026/11/11 17:23 tool grepper
0m Args:
{
  "Expression": "vcpu.*alloc",
  "PathPrefixes": [
    "arch/x86/kvm"
  ]
}

Results:
{
  "Output": "arch/x86/kvm/hyperv.c=980=int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/hyperv.c-987-\narch/x86/kvm/hyperv.c:988:\thv_vcpu = kzalloc_obj(struct kvm_vcpu_hv, GFP_KERNEL_ACCOUNT);\narch/x86/kvm/hyperv.c-989-\tif (!hv_vcpu)\n--\narch/x86/kvm/svm/nested.c=1488=int svm_allocate_nested(struct vcpu_svm *svm)\n--\narch/x86/kvm/svm/nested.c-1500-\narch/x86/kvm/svm/nested.c:1501:\tsvm-\u003enested.msrpm = svm_vcpu_alloc_msrpm();\narch/x86/kvm/svm/nested.c-1502-\tif (!svm-\u003enested.msrpm)\n--\narch/x86/kvm/svm/svm.c=1344=static int svm_vcpu_create(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/svm/svm.c-1358-\tif (pml) {\narch/x86/kvm/svm/svm.c:1359:\t\tvcpu-\u003earch.pml_page = snp_safe_alloc_page();\narch/x86/kvm/svm/svm.c-1360-\t\tif (!vcpu-\u003earch.pml_page)\n--\narch/x86/kvm/svm/svm.c-1371-\narch/x86/kvm/svm/svm.c:1372:\tsvm-\u003emsrpm = svm_vcpu_alloc_msrpm();\narch/x86/kvm/svm/svm.c-1373-\tif (!svm-\u003emsrpm) {\n--\narch/x86/kvm/svm/svm.h=803=void *svm_alloc_permissions_map(unsigned long size, gfp_t gfp_mask);\narch/x86/kvm/svm/svm.h-804-\narch/x86/kvm/svm/svm.h:805:static inline void *svm_vcpu_alloc_msrpm(void)\narch/x86/kvm/svm/svm.h-806-{\n--\narch/x86/kvm/vmx/vmx.c=7525=int vmx_vcpu_create(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/vmx/vmx.c-7546-\tif (enable_pml) {\narch/x86/kvm/vmx/vmx.c:7547:\t\tvcpu-\u003earch.pml_page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);\narch/x86/kvm/vmx/vmx.c-7548-\t\tif (!vcpu-\u003earch.pml_page)\n--\narch/x86/kvm/x86.c=9928=int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)\n--\narch/x86/kvm/x86.c-9958-\narch/x86/kvm/x86.c:9959:\tvcpu-\u003earch.mce_banks = kcalloc(KVM_MAX_MCE_BANKS * 4, sizeof(u64),\narch/x86/kvm/x86.c-9960-\t\t\t\t       GFP_KERNEL_ACCOUNT);\narch/x86/kvm/x86.c:9961:\tvcpu-\u003earch.mci_ctl2_banks = kcalloc(KVM_MAX_MCE_BANKS, sizeof(u64),\narch/x86/kvm/x86.c-9962-\t\t\t\t\t    GFP_KERNEL_ACCOUNT);\n"
}

43/3 2026/11/11 17:23 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 80372
							output: 585
							thoughts: 2447
						

Thoughts:
**KMSAN Analysis: No Need for Dedicated Fuzzing**

Alright, let's break this down. My initial assessment is that this patch doesn't warrant a KMSAN fuzzing session. The code involves KVM's TSC synchronization, master clock management, and some new ioctls. The goal here is to carefully evaluate if the changes introduce any risks related to uninitialized memory being exposed, especially to user space.

I began by scrutinizing the allocation strategy. The `kvm` and `vcpu` structs are allocated with `kzalloc` and `kmem_cache_zalloc` respectively, guaranteeing zero-initialization of all fields. Excellent starting point.

Next, I meticulously checked each of the four criteria for KMSAN triggering. Regarding the first, "Kernel structures sent to user space," I examined `KVM_VCPU_TSC_SCALE`, `KVM_GET_CLOCK_GUEST`, and the `__get_kvmclock_master_clock` function. The `KVM_VCPU_TSC_SCALE` struct, containing `__u64` fields, has no padding and all fields are initialized before the `copy_to_user` call. `KVM_GET_CLOCK_GUEST` uses a `struct pvclock_vcpu_time_info hv_clock = {};` which is initialized to zero, and the data is then populated and *then* sent to userspace. In `__get_kvmclock_master_clock`, the relevant `data` is initialized. I found no other instances of `copy_to_user` to investigate. So, no evidence of uninitialized memory being leaked.

Moving to the second criterion, "Conditional logic depending on uninitialized variables," I traced all variables in functions like `kvm_set_tsc_khz`, `kvm_synchronize_tsc_at`, `__kvm_synchronize_tsc`, `kvm_vcpu_ioctl_get_clock_guest`, and more. Each and every variable is initialized before its use, particularly in all conditional branching.

Then, for the third criterion – "Allocation of data structures with potentially uninitialized fields" – it's clear that all structures are either zero-initialized at allocation or initialized explicitly. There are new fields, but they're within the zero-allocated `kvm_arch` and `kvm_vcpu_arch` structures.

Finally, regarding the fourth criterion – "Bounds checks/lengths leading to access of uninitialized memory" – there's nothing here that alters buffer handling or lengths in a way that would allow the code to read uninitialized memory.

The critical point is that the patch primarily concerns x86 KVM TSC synchronization, PVCLOCK guest time handling, and related ioctls. While concurrency bugs are possible, those issues are primarily detected by LOCKDEP and thread sanitizers. Memory safety bugs would be KASAN's domain.

In short, there is no chance that any uninitialized memory will be read. I've examined every path and all local and user buffers have been zero initialized.

Therefore, no, a dedicated KMSAN fuzzing session isn't necessary. The logic is sound, the data is initialized. Set `NeedsKMSAN` to `false` and move on.



44/3 2026/11/11 17:23 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch series refactors x86 KVM timestamp counter (TSC) synchronization and master clock tracking, allowing the master clock to remain active even when vCPUs have divergent TSC offsets (provided their TSC frequencies match). It also adds KVM_GET_CLOCK_GUEST and KVM_SET_CLOCK_GUEST ioctls along with the KVM_VCPU_TSC_SCALE device attribute to support precise kvmclock migration.\n\nEvaluating the memory safety aspects contrasting KMSAN and KASAN:\n1. Structures copied to userspace:\n   - KVM_GET_CLOCK_GUEST copies `struct pvclock_vcpu_time_info hv_clock = {}`, which is completely zero-initialized on the stack. Because it is declared `__attribute__((__packed__))`, there are no hidden compiler alignment holes, and all fields (including `pad0` and `pad[2]`) are explicitly zeroed before copying to userspace.\n   - KVM_VCPU_TSC_SCALE copies `struct kvm_vcpu_tsc_scale scale` consisting of two `__u64` members (16 bytes total) with no internal or trailing padding holes; both members (`tsc_ratio` and `tsc_frac_bits`) are explicitly assigned before `copy_to_user`.\n   - In `kvm_vm_ioctl_get_clock`, `struct kvm_clock_data data` was already zero-initialized with `{ 0 }`.\n2. Stack and heap initialization:\n   - New struct members in `struct kvm_arch` and `struct kvm_vcpu_arch` reside in objects allocated with zero-initialization (`kzalloc` and `kmem_cache_zalloc`).\n   - All newly introduced or modified local variables on the stack (e.g., `tsc_shift`, `tsc_mult`, `host_tsc`, `ns`, `clock`) are fully initialized by helper functions or explicitly in all control flow branches before being evaluated or passed onward.\n3. Bug profiles and sanitizer coverage:\n   - The primary risks in this patch series involve concurrency and locking protocol updates (`tsc_write_lock`, `pvclock_sc` seqcount, vCPU request propagation), as well as fixed-point arithmetic, shift bounds, and clock monotonicity logic.\n   - Concurrency bugs are covered by LOCKDEP and standard race checkers; any potential memory corruption or out-of-bounds access is covered by KASAN.\n   - There are no risks of uninitialized memory reads or kernel info-leaks.\n\nTherefore, running a dedicated KMSAN fuzzing session is not justified.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch series refactors x86 KVM timestamp counter (TSC) synchronization and master clock tracking, allowing the master clock to remain active even when vCPUs have divergent TSC offsets (provided their TSC frequencies match). It also adds KVM_GET_CLOCK_GUEST and KVM_SET_CLOCK_GUEST ioctls along with the KVM_VCPU_TSC_SCALE device attribute to support precise kvmclock migration.\n\nEvaluating the memory safety aspects contrasting KMSAN and KASAN:\n1. Structures copied to userspace:\n   - KVM_GET_CLOCK_GUEST copies `struct pvclock_vcpu_time_info hv_clock = {}`, which is completely zero-initialized on the stack. Because it is declared `__attribute__((__packed__))`, there are no hidden compiler alignment holes, and all fields (including `pad0` and `pad[2]`) are explicitly zeroed before copying to userspace.\n   - KVM_VCPU_TSC_SCALE copies `struct kvm_vcpu_tsc_scale scale` consisting of two `__u64` members (16 bytes total) with no internal or trailing padding holes; both members (`tsc_ratio` and `tsc_frac_bits`) are explicitly assigned before `copy_to_user`.\n   - In `kvm_vm_ioctl_get_clock`, `struct kvm_clock_data data` was already zero-initialized with `{ 0 }`.\n2. Stack and heap initialization:\n   - New struct members in `struct kvm_arch` and `struct kvm_vcpu_arch` reside in objects allocated with zero-initialization (`kzalloc` and `kmem_cache_zalloc`).\n   - All newly introduced or modified local variables on the stack (e.g., `tsc_shift`, `tsc_mult`, `host_tsc`, `ns`, `clock`) are fully initialized by helper functions or explicitly in all control flow branches before being evaluated or passed onward.\n3. Bug profiles and sanitizer coverage:\n   - The primary risks in this patch series involve concurrency and locking protocol updates (`tsc_write_lock`, `pvclock_sc` seqcount, vCPU request propagation), as well as fixed-point arithmetic, shift bounds, and clock monotonicity logic.\n   - Concurrency bugs are covered by LOCKDEP and standard race checkers; any potential memory corruption or out-of-bounds access is covered by KASAN.\n   - There are no risks of uninitialized memory reads or kernel info-leaks.\n\nTherefore, running a dedicated KMSAN fuzzing session is not justified.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)