]> xenbits.xensource.com Git - seabios.git/commitdiff
kvm: add support for reading tsc frequency from kvmclock
authorGerd Hoffmann <kraxel@redhat.com>
Tue, 10 Mar 2020 10:22:48 +0000 (11:22 +0100)
committerGerd Hoffmann <kraxel@redhat.com>
Mon, 16 Mar 2020 13:29:41 +0000 (14:29 +0100)
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20200310102248.28412-4-kraxel@redhat.com

src/fw/paravirt.c
src/fw/paravirt.h

index 1e3d6012700b4b9e0326100c3ae2d395b403df87..119280c574fd75d23add98bf2ebbc4614b284b98 100644 (file)
@@ -75,6 +75,48 @@ static void kvm_detect(void)
     }
 }
 
+#define KVM_FEATURE_CLOCKSOURCE           0
+#define KVM_FEATURE_CLOCKSOURCE2          3
+
+#define MSR_KVM_SYSTEM_TIME            0x12
+#define MSR_KVM_SYSTEM_TIME_NEW  0x4b564d01
+
+#define PVCLOCK_TSC_STABLE_BIT     (1 << 0)
+
+struct pvclock_vcpu_time_info *kvmclock;
+
+static void kvmclock_init(void)
+{
+    unsigned int eax, ebx, ecx, edx, msr;
+
+    if (!runningOnKVM())
+        return;
+
+    cpuid(KVM_CPUID_SIGNATURE + 0x01, &eax, &ebx, &ecx, &edx);
+    if (eax & (1 <<  KVM_FEATURE_CLOCKSOURCE2))
+        msr = MSR_KVM_SYSTEM_TIME_NEW;
+    else if (eax & (1 <<  KVM_FEATURE_CLOCKSOURCE))
+        msr = MSR_KVM_SYSTEM_TIME;
+    else
+        return;
+
+    kvmclock = memalign_low(sizeof(*kvmclock), 32);
+    memset(kvmclock, 0, sizeof(*kvmclock));
+    u32 value = (u32)(kvmclock);
+    dprintf(1, "kvmclock: at 0x%x (msr 0x%x)\n", value, msr);
+    wrmsr(msr, value | 0x01);
+
+    if (!(kvmclock->flags & PVCLOCK_TSC_STABLE_BIT))
+        return;
+    u32 MHz = (1000 << 16) / (kvmclock->tsc_to_system_mul >> 16);
+    if (kvmclock->tsc_shift < 0)
+        MHz <<= -kvmclock->tsc_shift;
+    else
+        MHz >>= kvmclock->tsc_shift;
+    dprintf(1, "kvmclock: stable tsc, %d MHz\n", MHz);
+    tsctimer_setfreq(MHz * 1000, "kvmclock");
+}
+
 static void qemu_detect(void)
 {
     if (!CONFIG_QEMU_HARDWARE)
@@ -163,6 +205,8 @@ qemu_platform_setup(void)
         return;
     }
 
+    kvmclock_init();
+
     // Initialize pci
     pci_setup();
     smm_device_setup();
index f7e1d4c551d91426310132a02a67942c45c4e81a..4e2e993ba9d3ce6d72781a813ee2951638a05c60 100644 (file)
@@ -5,6 +5,18 @@
 #include "biosvar.h" // GET_GLOBAL
 #include "romfile.h" // struct romfile_s
 
+// kvmclock
+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 */
+
 // Types of paravirtualized platforms.
 #define PF_QEMU     (1<<0)
 #define PF_XEN      (1<<1)