From df4b46737f43a1a67f9b5de2840213a1bd2b3cce Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Fri, 22 Mar 2019 16:44:02 +0100 Subject: [PATCH] vircpuhost: Add support for reading MSRs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new virHostCPUGetMSR internal API will try to read the MSR from /dev/cpu/0/msr and if it is not possible (the device does not exist or libvirt is running unprivileged), it will fallback to asking KVM for the MSR using KVM_GET_MSRS ioctl. Signed-off-by: Jiri Denemark Reviewed-by: Ján Tomko --- src/libvirt_private.syms | 1 + src/util/virhostcpu.c | 80 ++++++++++++++++++++++++++++++++++++++++ src/util/virhostcpu.h | 3 ++ 3 files changed, 84 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 5d66623350..94c823d39d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2027,6 +2027,7 @@ virHostCPUGetInfo; virHostCPUGetKVMMaxVCPUs; virHostCPUGetMap; virHostCPUGetMicrocodeVersion; +virHostCPUGetMSR; virHostCPUGetOnline; virHostCPUGetOnlineBitmap; virHostCPUGetPresentBitmap; diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c index 6514c3d765..10bf3a93d5 100644 --- a/src/util/virhostcpu.c +++ b/src/util/virhostcpu.c @@ -58,6 +58,7 @@ VIR_LOG_INIT("util.hostcpu"); #define KVM_DEVICE "/dev/kvm" +#define MSR_DEVICE "/dev/cpu/0/msr" #if defined(__FreeBSD__) || defined(__APPLE__) @@ -1254,3 +1255,82 @@ virHostCPUGetMicrocodeVersion(void) } #endif /* __linux__ */ + + +#if HAVE_LINUX_KVM_H && defined(KVM_GET_MSRS) +static int +virHostCPUGetMSRFromKVM(unsigned long index, + uint64_t *result) +{ + VIR_AUTOCLOSE fd = -1; + struct { + struct kvm_msrs header; + struct kvm_msr_entry entry; + } msr = { + .header = { .nmsrs = 1 }, + .entry = { .index = index }, + }; + + if ((fd = open(KVM_DEVICE, O_RDONLY)) < 0) { + virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE); + return -1; + } + + if (ioctl(fd, KVM_GET_MSRS, &msr) < 0) { + VIR_DEBUG("Cannot get MSR 0x%lx from KVM", index); + return 1; + } + + *result = msr.entry.data; + return 0; +} + +#else + +static int +virHostCPUGetMSRFromKVM(unsigned long index ATTRIBUTE_UNUSED, + uint64_t *result ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Reading MSRs via KVM is not supported on this platform")); + return -1; +} +#endif /* HAVE_LINUX_KVM_H && defined(KVM_GET_MSRS) */ + + +/* + * Returns 0 on success, + * 1 when the MSR is not supported by the host CPU, +* -1 on error. + */ +int +virHostCPUGetMSR(unsigned long index, + uint64_t *msr) +{ + VIR_AUTOCLOSE fd = -1; + char ebuf[1024]; + + *msr = 0; + + if ((fd = open(MSR_DEVICE, O_RDONLY)) < 0) { + VIR_DEBUG("Unable to open %s: %s", + MSR_DEVICE, virStrerror(errno, ebuf, sizeof(ebuf))); + } else { + int rc = pread(fd, msr, sizeof(*msr), index); + + if (rc == sizeof(*msr)) + return 0; + + if (rc < 0 && errno == EIO) { + VIR_DEBUG("CPU does not support MSR 0x%lx", index); + return 1; + } + + VIR_DEBUG("Cannot read MSR 0x%lx from %s: %s", + index, MSR_DEVICE, virStrerror(errno, ebuf, sizeof(ebuf))); + } + + VIR_DEBUG("Falling back to KVM ioctl"); + + return virHostCPUGetMSRFromKVM(index, msr); +} diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h index df6a7e789d..0d20dbef61 100644 --- a/src/util/virhostcpu.h +++ b/src/util/virhostcpu.h @@ -66,4 +66,7 @@ int virHostCPUGetOnline(unsigned int cpu, bool *online); unsigned int virHostCPUGetMicrocodeVersion(void); +int virHostCPUGetMSR(unsigned long index, + uint64_t *msr); + #endif /* LIBVIRT_VIRHOSTCPU_H */