All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huang Ying <ying.huang@intel.com>
To: Avi Kivity <avi@redhat.com>,
	Anthony Liguori <anthony@codemonkey.ws>,
	Andi Kleen <andi@firstfloor.org>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>
Subject: [PATCH -v4 2/2] QEMU-KVM: MCE: Add MCE simulation support to qemu/kvm
Date: Mon, 11 May 2009 16:48:26 +0800	[thread overview]
Message-ID: <1242031706.8213.20.camel@yhuang-dev.sh.intel.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 7813 bytes --]

KVM ioctls are used to initialize MCE simulation and inject MCE. The
real MCE simulation is implemented in Linux kernel.


ChangeLog:

v3:

- Re-based on qemu/tcg MCE support patch

v2:

- Use new kernel MCE capability exportion interface.


Signed-off-by: Huang Ying <ying.huang@intel.com>

---
 kvm/kernel/arch/x86/include/asm/kvm.h |    1 
 kvm/kernel/include/linux/kvm.h        |   21 +++++++++++++++++
 kvm/libkvm/libkvm-x86.c               |   39 +++++++++++++++++++++++++++++++++
 kvm/libkvm/libkvm.h                   |    4 +++
 qemu-kvm-x86.c                        |   23 +++++++++++++++++++
 qemu-kvm.c                            |   40 ++++++++++++++++++++++++++++++++++
 qemu-kvm.h                            |    3 ++
 target-i386/helper.c                  |    5 ++++
 target-i386/machine.c                 |    4 +--
 9 files changed, 138 insertions(+), 2 deletions(-)

--- a/kvm/libkvm/libkvm-x86.c
+++ b/kvm/libkvm/libkvm-x86.c
@@ -378,6 +378,45 @@ int kvm_set_msrs(kvm_context_t kvm, int 
     return r;
 }
 
+int kvm_get_mce_cap_supported(kvm_context_t kvm, uint64_t *mce_cap,
+                              int *max_banks)
+{
+#ifdef KVM_CAP_MCE
+    int r;
+
+    r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r > 0) {
+        *max_banks = r;
+        return ioctl(kvm->fd, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+    }
+#endif
+    return -ENOSYS;
+}
+
+int kvm_setup_mce(kvm_context_t kvm, int vcpu, uint64_t *mcg_cap)
+{
+#ifdef KVM_CAP_MCE
+    int r;
+
+    r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r > 0)
+        return ioctl(kvm->vcpu_fd[vcpu], KVM_X86_SETUP_MCE, mcg_cap);
+#endif
+    return -ENOSYS;
+}
+
+int kvm_set_mce(kvm_context_t kvm, int vcpu, struct kvm_x86_mce *m)
+{
+#ifdef KVM_CAP_MCE
+    int r;
+
+    r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r > 0)
+        return ioctl(kvm->vcpu_fd[vcpu], KVM_X86_SET_MCE, m);
+#endif
+    return -ENOSYS;
+}
+
 static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
 {
     	fprintf(stderr,
--- a/kvm/libkvm/libkvm.h
+++ b/kvm/libkvm/libkvm.h
@@ -27,6 +27,10 @@ typedef struct kvm_context *kvm_context_
 struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
 int kvm_get_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
 int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
+int kvm_get_mce_cap_supported(kvm_context_t, uint64_t *mce_cap, int *max_banks);
+int kvm_setup_mce(kvm_context_t, int vcpu, uint64_t *mcg_cap);
+struct kvm_x86_mce;
+int kvm_set_mce(kvm_context_t, int vcpu, struct kvm_x86_mce *mce);
 #endif
 
 /*!
--- a/qemu-kvm-x86.c
+++ b/qemu-kvm-x86.c
@@ -566,6 +566,29 @@ int kvm_arch_qemu_init_env(CPUState *cen
 	do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, &copy);
 
     kvm_setup_cpuid2(kvm_context, cenv->cpu_index, cpuid_nent, cpuid_ent);
+
+#ifdef KVM_CAP_MCE
+    if (((cenv->cpuid_version >> 8)&0xF) >= 6
+        && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+        && kvm_check_extension(kvm_context, KVM_CAP_MCE) > 0) {
+        uint64_t mcg_cap;
+        int banks;
+
+        if (kvm_get_mce_cap_supported(kvm_context, &mcg_cap, &banks))
+            perror("kvm_get_mce_cap_supported FAILED");
+        else {
+            if (banks > MCE_BANKS_DEF)
+                banks = MCE_BANKS_DEF;
+            mcg_cap &= MCE_CAP_DEF;
+            mcg_cap |= banks;
+            if (kvm_setup_mce(kvm_context, cenv->cpu_index, &mcg_cap))
+                perror("kvm_setup_mce FAILED");
+            else
+                cenv->mcg_cap = mcg_cap;
+        }
+    }
+#endif
+
     return 0;
 }
 
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -236,4 +236,7 @@ uint32_t kvm_arch_get_supported_cpuid(CP
                                       int reg);
 
 
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+
 #endif
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1460,6 +1460,11 @@ void cpu_inject_x86_mce(CPUState *cenv, 
     unsigned bank_num = mcg_cap & 0xff;
     uint64_t *banks = cenv->mce_banks;
 
+    if (kvm_enabled()) {
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+        return;
+    }
+
     if (bank >= bank_num || !(status & MCI_STATUS_VAL))
         return;
 
--- a/kvm/kernel/include/linux/kvm.h
+++ b/kvm/kernel/include/linux/kvm.h
@@ -455,6 +455,9 @@ struct kvm_trace_rec {
 #define KVM_CAP_ASSIGN_DEV_IRQ 29
 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -494,6 +497,20 @@ struct kvm_irq_routing {
 
 #endif
 
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+	__u64 status;
+	__u64 addr;
+	__u64 misc;
+	__u64 mcg_status;
+	__u8 bank;
+	__u8 pad1;
+	__u16 pad2;
+	__u32 pad3;
+};
+#endif
+
 /*
  * ioctls for VM fds
  */
@@ -581,6 +598,10 @@ struct kvm_irq_routing {
 #define KVM_NMI                   _IO(KVMIO,  0x9a)
 /* Available with KVM_CAP_SET_GUEST_DEBUG */
 #define KVM_SET_GUEST_DEBUG       _IOW(KVMIO,  0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE         _IOW(KVMIO,  0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO,  0x9d, __u64)
+#define KVM_X86_SET_MCE           _IOW(KVMIO,  0x9e, struct kvm_x86_mce)
 
 /*
  * Deprecated interfaces
--- a/kvm/kernel/arch/x86/include/asm/kvm.h
+++ b/kvm/kernel/arch/x86/include/asm/kvm.h
@@ -57,6 +57,7 @@
 #define __KVM_HAVE_USER_NMI
 #define __KVM_HAVE_GUEST_DEBUG
 #define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1431,3 +1431,43 @@ uint32_t kvm_arch_get_supported_cpuid(CP
 {
     return kvm_get_supported_cpuid(kvm_context, function, reg);
 }
+
+#ifdef TARGET_I386
+#ifdef KVM_CAP_MCE
+struct kvm_x86_mce_data
+{
+    CPUState *env;
+    struct kvm_x86_mce *mce;
+};
+
+static void kvm_do_inject_x86_mce(void *_data)
+{
+    struct kvm_x86_mce_data *data = _data;
+    int r;
+
+    r = kvm_set_mce(kvm_context, data->env->cpu_index, data->mce);
+    if (r < 0)
+        perror("kvm_set_mce FAILED");
+}
+#endif
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc)
+{
+#ifdef KVM_CAP_MCE
+    struct kvm_x86_mce mce = {
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+    };
+    struct kvm_x86_mce_data data = {
+            .env = cenv,
+            .mce = &mce,
+    };
+
+    on_vcpu(cenv, kvm_do_inject_x86_mce, &data);
+#endif
+}
+#endif
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -162,7 +162,7 @@ void cpu_save(QEMUFile *f, void *opaque)
 
     /* MCE */
     qemu_put_be64s(f, &env->mcg_cap);
-    if (env->mcg_cap) {
+    if (env->mcg_cap && !kvm_enabled()) {
         qemu_put_be64s(f, &env->mcg_status);
         qemu_put_be64s(f, &env->mcg_ctl);
         for (i = 0; i < env->mcg_cap & 0xff; i++) {
@@ -378,7 +378,7 @@ int cpu_load(QEMUFile *f, void *opaque, 
 
     if (version_id >= 10) {
         qemu_get_be64s(f, &env->mcg_cap);
-        if (env->mcg_cap) {
+        if (env->mcg_cap && !kvm_enabled()) {
             qemu_get_be64s(f, &env->mcg_status);
             qemu_get_be64s(f, &env->mcg_ctl);
             for (i = 0; i < env->mcg_cap & 0xff; i++) {


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

                 reply	other threads:[~2009-05-11  8:49 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1242031706.8213.20.camel@yhuang-dev.sh.intel.com \
    --to=ying.huang@intel.com \
    --cc=andi@firstfloor.org \
    --cc=anthony@codemonkey.ws \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.