Pablo Greco 40546a
From 6094ea6111dd57274b6037e76f662a06b8e5c9d1 Mon Sep 17 00:00:00 2001
Pablo Greco 40546a
Message-Id: <6094ea6111dd57274b6037e76f662a06b8e5c9d1@dist-git>
Pablo Greco 40546a
From: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Date: Fri, 21 Jun 2019 09:25:43 +0200
Pablo Greco 40546a
Subject: [PATCH] vircpuhost: Add support for reading MSRs
Pablo Greco 40546a
MIME-Version: 1.0
Pablo Greco 40546a
Content-Type: text/plain; charset=UTF-8
Pablo Greco 40546a
Content-Transfer-Encoding: 8bit
Pablo Greco 40546a
Pablo Greco 40546a
The new virHostCPUGetMSR internal API will try to read the MSR from
Pablo Greco 40546a
/dev/cpu/0/msr and if it is not possible (the device does not exist or
Pablo Greco 40546a
libvirt is running unprivileged), it will fallback to asking KVM for the
Pablo Greco 40546a
MSR using KVM_GET_MSRS ioctl.
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Pablo Greco 40546a
(cherry picked from commit df4b46737f43a1a67f9b5de2840213a1bd2b3cce)
Pablo Greco 40546a
Pablo Greco 40546a
https://bugzilla.redhat.com/show_bug.cgi?id=1697627
Pablo Greco 40546a
Pablo Greco 40546a
Conflicts:
Pablo Greco 40546a
	src/util/virhostcpu.h
Pablo Greco 40546a
            - different header file guard symbol
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
Pablo Greco 40546a
Message-Id: <0d4c18704c435cccc2b18ebd55f4f914caf05d13.1561068591.git.jdenemar@redhat.com>
Pablo Greco 40546a
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Pablo Greco 40546a
---
Pablo Greco 40546a
 src/libvirt_private.syms |  1 +
Pablo Greco 40546a
 src/util/virhostcpu.c    | 80 ++++++++++++++++++++++++++++++++++++++++
Pablo Greco 40546a
 src/util/virhostcpu.h    |  3 ++
Pablo Greco 40546a
 3 files changed, 84 insertions(+)
Pablo Greco 40546a
Pablo Greco 40546a
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
Pablo Greco 40546a
index 347667b17c..9ebc5384fb 100644
Pablo Greco 40546a
--- a/src/libvirt_private.syms
Pablo Greco 40546a
+++ b/src/libvirt_private.syms
Pablo Greco 40546a
@@ -1974,6 +1974,7 @@ virHostCPUGetInfo;
Pablo Greco 40546a
 virHostCPUGetKVMMaxVCPUs;
Pablo Greco 40546a
 virHostCPUGetMap;
Pablo Greco 40546a
 virHostCPUGetMicrocodeVersion;
Pablo Greco 40546a
+virHostCPUGetMSR;
Pablo Greco 40546a
 virHostCPUGetOnline;
Pablo Greco 40546a
 virHostCPUGetOnlineBitmap;
Pablo Greco 40546a
 virHostCPUGetPresentBitmap;
Pablo Greco 40546a
diff --git a/src/util/virhostcpu.c b/src/util/virhostcpu.c
Pablo Greco 40546a
index effe04ca3a..d0c47faa18 100644
Pablo Greco 40546a
--- a/src/util/virhostcpu.c
Pablo Greco 40546a
+++ b/src/util/virhostcpu.c
Pablo Greco 40546a
@@ -64,6 +64,7 @@
Pablo Greco 40546a
 VIR_LOG_INIT("util.hostcpu");
Pablo Greco 40546a
 
Pablo Greco 40546a
 #define KVM_DEVICE "/dev/kvm"
Pablo Greco 40546a
+#define MSR_DEVICE "/dev/cpu/0/msr"
Pablo Greco 40546a
 
Pablo Greco 40546a
 
Pablo Greco 40546a
 #if defined(__FreeBSD__) || defined(__APPLE__)
Pablo Greco 40546a
@@ -1266,3 +1267,82 @@ virHostCPUGetMicrocodeVersion(void)
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
 #endif /* __linux__ */
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
+#if HAVE_LINUX_KVM_H && defined(KVM_GET_MSRS)
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+virHostCPUGetMSRFromKVM(unsigned long index,
Pablo Greco 40546a
+                        uint64_t *result)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_AUTOCLOSE fd = -1;
Pablo Greco 40546a
+    struct {
Pablo Greco 40546a
+        struct kvm_msrs header;
Pablo Greco 40546a
+        struct kvm_msr_entry entry;
Pablo Greco 40546a
+    } msr = {
Pablo Greco 40546a
+        .header = { .nmsrs = 1 },
Pablo Greco 40546a
+        .entry = { .index = index },
Pablo Greco 40546a
+    };
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if ((fd = open(KVM_DEVICE, O_RDONLY)) < 0) {
Pablo Greco 40546a
+        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
Pablo Greco 40546a
+        return -1;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if (ioctl(fd, KVM_GET_MSRS, &msr) < 0) {
Pablo Greco 40546a
+        VIR_DEBUG("Cannot get MSR 0x%lx from KVM", index);
Pablo Greco 40546a
+        return 1;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    *result = msr.entry.data;
Pablo Greco 40546a
+    return 0;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+
Pablo Greco 40546a
+#else
Pablo Greco 40546a
+
Pablo Greco 40546a
+static int
Pablo Greco 40546a
+virHostCPUGetMSRFromKVM(unsigned long index ATTRIBUTE_UNUSED,
Pablo Greco 40546a
+                        uint64_t *result ATTRIBUTE_UNUSED)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    virReportSystemError(ENOSYS, "%s",
Pablo Greco 40546a
+                         _("Reading MSRs via KVM is not supported on this platform"));
Pablo Greco 40546a
+    return -1;
Pablo Greco 40546a
+}
Pablo Greco 40546a
+#endif /* HAVE_LINUX_KVM_H && defined(KVM_GET_MSRS) */
Pablo Greco 40546a
+
Pablo Greco 40546a
+
Pablo Greco 40546a
+/*
Pablo Greco 40546a
+ * Returns 0 on success,
Pablo Greco 40546a
+ *         1 when the MSR is not supported by the host CPU,
Pablo Greco 40546a
+*         -1 on error.
Pablo Greco 40546a
+ */
Pablo Greco 40546a
+int
Pablo Greco 40546a
+virHostCPUGetMSR(unsigned long index,
Pablo Greco 40546a
+                 uint64_t *msr)
Pablo Greco 40546a
+{
Pablo Greco 40546a
+    VIR_AUTOCLOSE fd = -1;
Pablo Greco 40546a
+    char ebuf[1024];
Pablo Greco 40546a
+
Pablo Greco 40546a
+    *msr = 0;
Pablo Greco 40546a
+
Pablo Greco 40546a
+    if ((fd = open(MSR_DEVICE, O_RDONLY)) < 0) {
Pablo Greco 40546a
+        VIR_DEBUG("Unable to open %s: %s",
Pablo Greco 40546a
+                  MSR_DEVICE, virStrerror(errno, ebuf, sizeof(ebuf)));
Pablo Greco 40546a
+    } else {
Pablo Greco 40546a
+        int rc = pread(fd, msr, sizeof(*msr), index);
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (rc == sizeof(*msr))
Pablo Greco 40546a
+            return 0;
Pablo Greco 40546a
+
Pablo Greco 40546a
+        if (rc < 0 && errno == EIO) {
Pablo Greco 40546a
+            VIR_DEBUG("CPU does not support MSR 0x%lx", index);
Pablo Greco 40546a
+            return 1;
Pablo Greco 40546a
+        }
Pablo Greco 40546a
+
Pablo Greco 40546a
+        VIR_DEBUG("Cannot read MSR 0x%lx from %s: %s",
Pablo Greco 40546a
+                  index, MSR_DEVICE, virStrerror(errno, ebuf, sizeof(ebuf)));
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
+    VIR_DEBUG("Falling back to KVM ioctl");
Pablo Greco 40546a
+
Pablo Greco 40546a
+    return virHostCPUGetMSRFromKVM(index, msr);
Pablo Greco 40546a
+}
Pablo Greco 40546a
diff --git a/src/util/virhostcpu.h b/src/util/virhostcpu.h
Pablo Greco 40546a
index f9f3359288..e705623d4f 100644
Pablo Greco 40546a
--- a/src/util/virhostcpu.h
Pablo Greco 40546a
+++ b/src/util/virhostcpu.h
Pablo Greco 40546a
@@ -68,4 +68,7 @@ int virHostCPUGetOnline(unsigned int cpu, bool *online);
Pablo Greco 40546a
 
Pablo Greco 40546a
 unsigned int virHostCPUGetMicrocodeVersion(void);
Pablo Greco 40546a
 
Pablo Greco 40546a
+int virHostCPUGetMSR(unsigned long index,
Pablo Greco 40546a
+                     uint64_t *msr);
Pablo Greco 40546a
+
Pablo Greco 40546a
 #endif /* __VIR_HOSTCPU_H__*/
Pablo Greco 40546a
-- 
Pablo Greco 40546a
2.22.0
Pablo Greco 40546a