aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2020-03-10 11:22:48 +0100
committerGerd Hoffmann <kraxel@redhat.com>2020-03-16 14:29:41 +0100
commitb3fa857752dcffd84a770e4bfe265160f96ab08e (patch)
tree561decad188698aac9bf0f4df9451c498fd77360
parent34160e05257328a3e18200cccfe394e7aeb10be3 (diff)
downloadseabios-hppa-b3fa857752dcffd84a770e4bfe265160f96ab08e.zip
seabios-hppa-b3fa857752dcffd84a770e4bfe265160f96ab08e.tar.gz
seabios-hppa-b3fa857752dcffd84a770e4bfe265160f96ab08e.tar.bz2
kvm: add support for reading tsc frequency from kvmclock
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Message-id: 20200310102248.28412-4-kraxel@redhat.com
-rw-r--r--src/fw/paravirt.c44
-rw-r--r--src/fw/paravirt.h12
2 files changed, 56 insertions, 0 deletions
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index 1e3d601..119280c 100644
--- a/src/fw/paravirt.c
+++ b/src/fw/paravirt.c
@@ -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();
diff --git a/src/fw/paravirt.h b/src/fw/paravirt.h
index f7e1d4c..4e2e993 100644
--- a/src/fw/paravirt.h
+++ b/src/fw/paravirt.h
@@ -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)