Skip to contentSkip to conversation

qemu-kvm.git uq/master queue

GIT PULL In review Marcelo Tosatti 4 participants 26 messages Oct 20, 2010 – Oct 21, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Huang Ying (1):

      Add RAM -> physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

 Makefile.objs         |    1 +
 compatfd.c            |  117 ++++++++++++++++++
 compatfd.h            |   43 +++++++
 configure             |   18 +++
 cpu-common.h          |    3 +-
 cpus.c                |  156 ++++++++++++++++++++++--
 exec-all.h            |    2 +-
 exec.c                |   26 +++--
 kvm-all.c             |   18 +++
 kvm-stub.c            |    5 +
 kvm.h                 |    9 ++
 target-i386/cpu.h     |   32 +++++-
 target-i386/cpuid.c   |   79 ++++++++++---
 target-i386/helper.c  |    6 +
 target-i386/kvm.c     |  311 ++++++++++++++++++++++++++++++++++++++++++++++++-
 target-i386/kvm_x86.h |   22 ++++
 16 files changed, 801 insertions(+), 47 deletions(-)
 create mode 100644 compatfd.c
 create mode 100644 compatfd.h
 create mode 100644 target-i386/kvm_x86.h
#1 lore raw

PATCH 1/10 Set cpuid definition to 0 before initializing it

From: Joerg Roedel <[email protected]>

This patch cleans the (stack-allocated) cpuid definition to 0 before actually initializing it.

---
 target-i386/cpuid.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
target-i386/cpuid.c +2 -0
index 04ba8d5..3fcf78f 100644
@@ -788,6 +788,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
 {
     x86_def_t def1, *def = &def1;
 
+    memset(def, 0, sizeof(*def));
+
     if (cpu_x86_find_by_name(def, cpu_model) < 0)
         return -1;
     if (def->vendor1) {
Signature · 1 line
1.7.2.1
#2 lore raw

PATCH 2/10 Add svm cpuid features

In reply to Marcelo Tosatti

From: Joerg Roedel <[email protected]>

This patch adds the svm cpuid feature flags to the qemu intialization path. It also adds the svm features available on phenom to its cpu-definition and extends the host cpu type to support all svm features KVM can provide.

---
 target-i386/cpu.h   |   12 ++++++++
 target-i386/cpuid.c |   77 +++++++++++++++++++++++++++++++++++++++-----------
 target-i386/kvm.c   |    3 ++
 3 files changed, 75 insertions(+), 17 deletions(-)
target-i386/cpu.h +12 -0
index 1144d4e..77eeab1 100644
@@ -405,6 +405,17 @@
 #define CPUID_EXT3_IBS     (1 << 10)
 #define CPUID_EXT3_SKINIT  (1 << 12)
 
+#define CPUID_SVM_NPT          (1 << 0)
+#define CPUID_SVM_LBRV         (1 << 1)
+#define CPUID_SVM_SVMLOCK      (1 << 2)
+#define CPUID_SVM_NRIPSAVE     (1 << 3)
+#define CPUID_SVM_TSCSCALE     (1 << 4)
+#define CPUID_SVM_VMCBCLEAN    (1 << 5)
+#define CPUID_SVM_FLUSHASID    (1 << 6)
+#define CPUID_SVM_DECODEASSIST (1 << 7)
+#define CPUID_SVM_PAUSEFILTER  (1 << 10)
+#define CPUID_SVM_PFTHRESHOLD  (1 << 12)
+
 #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
 #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
 #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
@@ -702,6 +713,7 @@ typedef struct CPUX86State {
     uint8_t has_error_code;
     uint32_t sipi_vector;
     uint32_t cpuid_kvm_features;
+    uint32_t cpuid_svm_features;
     
     /* in order to simplify APIC support, we leave this pointer to the
        user */
target-i386/cpuid.c +60 -17

172 lines not on this page · raw message

target-i386/kvm.c +3 -0
index a33d2fa..74e7b4f 100644
@@ -192,6 +192,9 @@ int kvm_arch_init_vcpu(CPUState *env)
                                                              0, R_EDX);
     env->cpuid_ext3_features &= kvm_arch_get_supported_cpuid(env, 0x80000001,
                                                              0, R_ECX);
+    env->cpuid_svm_features  &= kvm_arch_get_supported_cpuid(env, 0x8000000A,
+                                                             0, R_EDX);
+
 
     cpuid_i = 0;
 
Signature · 1 line
1.7.2.1
#3 lore raw

PATCH 3/10 signalfd compatibility

In reply to Marcelo Tosatti

Port qemu-kvm's signalfd compat code.

commit 5a7fdd0abd7cd24dac205317a4195446ab8748b5

Author: Anthony Liguori <[email protected]>
Date:   Wed May 7 11:55:47 2008 -0500

Use signalfd() in io-thread

This patch reworks the IO thread to use signalfd() instead of sigtimedwait() This will eliminate the need to use SIGIO everywhere.

---
 Makefile.objs |    1 +
 compatfd.c    |  117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 compatfd.h    |   43 +++++++++++++++++++++
 configure     |   18 +++++++++
 4 files changed, 179 insertions(+), 0 deletions(-)
 create mode 100644 compatfd.c
 create mode 100644 compatfd.h
Makefile.objs +1 -0
index 816194a..d73002d 100644
@@ -125,6 +125,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))
 
 common-obj-y += iov.o acl.o
 common-obj-$(CONFIG_THREAD) += qemu-thread.o
+common-obj-$(CONFIG_IOTHREAD) += compatfd.o
 common-obj-y += notify.o event_notifier.o
 common-obj-y += qemu-timer.o
 
compatfd.c new file +117 -0

117 lines not on this page · raw message

compatfd.h new file +43 -0

43 lines not on this page · raw message

configure +18 -0
index a079a49..ae8188e 100755
@@ -1957,6 +1957,21 @@ if compile_prog "" "" ; then
   splice=yes
 fi
 
+##########################################
+# signalfd probe
+signalfd="no"
+cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <signal.h>
+int main(void) { return syscall(SYS_signalfd, -1, NULL, _NSIG / 8); }
+EOF
+
+if compile_prog "" "" ; then
+  signalfd=yes
+fi
+
 # check if eventfd is supported
 eventfd=no
 cat > $TMPC << EOF
@@ -2559,6 +2574,9 @@ fi
 if test "$fdt" = "yes" ; then
   echo "CONFIG_FDT=y" >> $config_host_mak
 fi
+if test "$signalfd" = "yes" ; then
+  echo "CONFIG_SIGNALFD=y" >> $config_host_mak
+fi
 if test "$need_offsetof" = "yes" ; then
   echo "CONFIG_NEED_OFFSETOF=y" >> $config_host_mak
 fi
Signature · 1 line
1.7.2.1
#4 lore raw

PATCH 4/10 iothread: use signalfd

In reply to Marcelo Tosatti

Block SIGALRM, SIGIO and consume them via signalfd.

---
 cpus.c |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 69 insertions(+), 5 deletions(-)
cpus.c +69 -5
index b09f5e3..3875657 100644
@@ -33,6 +33,7 @@
 #include "exec-all.h"
 
 #include "cpus.h"
+#include "compatfd.h"
 
 #ifdef SIGRTMIN
 #define SIG_IPI (SIGRTMIN+4)
@@ -329,14 +330,75 @@ static QemuCond qemu_work_cond;
 
 static void tcg_init_ipi(void);
 static void kvm_init_ipi(CPUState *env);
-static void unblock_io_signals(void);
+static sigset_t block_io_signals(void);
+
+/* If we have signalfd, we mask out the signals we want to handle and then
+ * use signalfd to listen for them.  We rely on whatever the current signal
+ * handler is to dispatch the signals when we receive them.
+ */
+static void sigfd_handler(void *opaque)
+{
+    int fd = (unsigned long) opaque;
+    struct qemu_signalfd_siginfo info;
+    struct sigaction action;
+    ssize_t len;
+
+    while (1) {
+        do {
+            len = read(fd, &info, sizeof(info));
+        } while (len == -1 && errno == EINTR);
+
+        if (len == -1 && errno == EAGAIN) {
+            break;
+        }
+
+        if (len != sizeof(info)) {
+            printf("read from sigfd returned %zd: %m\n", len);
+            return;
+        }
+
+        sigaction(info.ssi_signo, NULL, &action);
+        if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
+            action.sa_sigaction(info.ssi_signo,
+                                (siginfo_t *)&info, NULL);
+        } else if (action.sa_handler) {
+            action.sa_handler(info.ssi_signo);
+        }
+    }
+}
+
+static int qemu_signalfd_init(sigset_t mask)
+{
+    int sigfd;
+
+    sigfd = qemu_signalfd(&mask);
+    if (sigfd == -1) {
+        fprintf(stderr, "failed to create signalfd\n");
+        return -errno;
+    }
+
+    fcntl_setfl(sigfd, O_NONBLOCK);
+
+    qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
+                         (void *)(unsigned long) sigfd);
+
+    return 0;
+}
 
 int qemu_init_main_loop(void)
 {
     int ret;
+    sigset_t blocked_signals;
 
     cpu_set_debug_excp_handler(cpu_debug_handler);
 
+    blocked_signals = block_io_signals();
+
+    ret = qemu_signalfd_init(blocked_signals);
+    if (ret)
+        return ret;
+
+    /* Note eventfd must be drained before signalfd handlers run */
     ret = qemu_event_init();
     if (ret)
         return ret;
@@ -347,7 +409,6 @@ int qemu_init_main_loop(void)
     qemu_mutex_init(&qemu_global_mutex);
     qemu_mutex_lock(&qemu_global_mutex);
 
-    unblock_io_signals();
     qemu_thread_self(&io_thread);
 
     return 0;
@@ -586,19 +647,22 @@ static void kvm_init_ipi(CPUState *env)
     }
 }
 
-static void unblock_io_signals(void)
+static sigset_t block_io_signals(void)
 {
     sigset_t set;
 
+    /* SIGUSR2 used by posix-aio-compat.c */
     sigemptyset(&set);
     sigaddset(&set, SIGUSR2);
-    sigaddset(&set, SIGIO);
-    sigaddset(&set, SIGALRM);
     pthread_sigmask(SIG_UNBLOCK, &set, NULL);
 
     sigemptyset(&set);
+    sigaddset(&set, SIGIO);
+    sigaddset(&set, SIGALRM);
     sigaddset(&set, SIG_IPI);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
+
+    return set;
 }
 
 void qemu_mutex_lock_iothread(void)
Signature · 1 line
1.7.2.1
#5 lore raw

PATCH 5/10 kvm: x86: add mce support

In reply to Marcelo Tosatti

Port qemu-kvm's MCE support

commit c68b2374c9048812f488e00ffb95db66c0bc07a7

Author: Huang Ying <[email protected]>
Date:   Mon Jul 20 10:00:53 2009 +0800

Add MCE simulation support to qemu/kvm

KVM ioctls are used to initialize MCE simulation and inject MCE. The real MCE simulation is implemented in Linux kernel. The Kernel part has been merged.

---
 target-i386/helper.c  |    6 +++
 target-i386/kvm.c     |   84 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/kvm_x86.h |   21 ++++++++++++
 3 files changed, 111 insertions(+), 0 deletions(-)
 create mode 100644 target-i386/kvm_x86.h
target-i386/helper.c +6 -0
index e134340..4b430dd 100644
@@ -27,6 +27,7 @@
 #include "exec-all.h"
 #include "qemu-common.h"
 #include "kvm.h"
+#include "kvm_x86.h"
 
 //#define DEBUG_MMU
 
@@ -1030,6 +1031,11 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
     if (bank >= bank_num || !(status & MCI_STATUS_VAL))
         return;
 
+    if (kvm_enabled()) {
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+        return;
+    }
+
     /*
      * if MSR_MCG_CTL is not all 1s, the uncorrected error
      * reporting is disabled
target-i386/kvm.c +84 -0

102 lines not on this page · raw message

target-i386/kvm_x86.h new file +21 -0
new file mode 100644
index 0000000..c1ebd24
@@ -0,0 +1,21 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori   <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef __KVM_X86_H__
+#define __KVM_X86_H__
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+
+#endif
Signature · 1 line
1.7.2.1
#6 lore raw

Re: [PATCH 05/10] kvm: x86: add mce support

Quoted 81 lines · Marcelo Tosatti

Port qemu-kvm's MCE support

commit c68b2374c9048812f488e00ffb95db66c0bc07a7

Author: Huang Ying<[email protected]>
Date:   Mon Jul 20 10:00:53 2009 +0800

Add MCE simulation support to qemu/kvm

KVM ioctls are used to initialize MCE simulation and inject MCE. The real MCE simulation is implemented in Linux kernel. The Kernel part has been merged.

---
  target-i386/helper.c  |    6 +++
  target-i386/kvm.c     |   84 +++++++++++++++++++++++++++++++++++++++++++++++++
  target-i386/kvm_x86.h |   21 ++++++++++++
  3 files changed, 111 insertions(+), 0 deletions(-)

create mode 100644 target-i386/kvm_x86.h

target-i386/helper.c +6 -0
index e134340..4b430dd 100644
@@ -27,6 +27,7 @@
  #include "exec-all.h"
  #include "qemu-common.h"
  #include "kvm.h"
+#include "kvm_x86.h"
 
  //#define DEBUG_MMU
 
@@ -1030,6 +1031,11 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
      if (bank>= bank_num || !(status&  MCI_STATUS_VAL))
          return;
 
+    if (kvm_enabled()) {
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+        return;
+    }
+
      /*
       * if MSR_MCG_CTL is not all 1s, the uncorrected error
       * reporting is disabled
target-i386/kvm.c +21 -0
index 74e7b4f..343fb02 100644
@@ -27,6 +27,7 @@
  #include "hw/pc.h"
  #include "hw/apic.h"
  #include "ioport.h"
+#include "kvm_x86.h"
 
  #ifdef CONFIG_KVM_PARA
  #include<linux/kvm_para.h>
@@ -167,6 +168,67 @@ static int get_para_features(CPUState *env)
  }
  #endif
 
+#ifdef KVM_CAP_MCE
+static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
+                                     int *max_banks)
+{
+    int r;
+
+    r = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+    if (r>  0) {
+        *max_banks = r;
+        return kvm_ioctl(s, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+    }
+    return -ENOSYS;
+}
+
+static int kvm_setup_mce(CPUState *env, uint64_t *mcg_cap)
+{
+    return kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, mcg_cap);
+}
+
+static int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m)

target-i386/kvm.c static int get_para_features(CPUState *env) · line 200

Quoted 10 lines
target-i386/kvm.c +9 -0
+{
+    return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
+}
+
+struct kvm_x86_mce_data
+{
+    CPUState *env;
+    struct kvm_x86_mce *mce;
+};
 

CODING_STYLE.

target-i386/kvm.c static int get_para_features(CPUState *env)

Quoted 9 lines
target-i386/kvm.c +8 -0
+static void kvm_do_inject_x86_mce(void *_data)
+{
+    struct kvm_x86_mce_data *data = _data;
+    int r;
+
+    r = kvm_set_mce(data->env, data->mce);
+    if (r<  0)
+        perror("kvm_set_mce FAILED");
 

CODING_STYLE.

Quoted 39 lines
target-i386/kvm.c +32 -0
+}
+#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,
+    };
+
+    run_on_cpu(cenv, kvm_do_inject_x86_mce,&data);
+#endif
+}
+
  int kvm_arch_init_vcpu(CPUState *env)
  {
      struct {
@@ -277,6 +339,28 @@ int kvm_arch_init_vcpu(CPUState *env)
 
      cpuid_data.cpuid.nent = cpuid_i;
 
+#ifdef KVM_CAP_MCE
+    if (((env->cpuid_version>>  8)&0xF)>= 6
+&&  (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+&&  kvm_check_extension(env->kvm_state, KVM_CAP_MCE)>  0) {
+        uint64_t mcg_cap;
+        int banks;
+
+        if (kvm_get_mce_cap_supported(env->kvm_state,&mcg_cap,&banks))
+            perror("kvm_get_mce_cap_supported FAILED");

target-i386/kvm.c int kvm_arch_init_vcpu(CPUState *env) · line 360

Quoted 10 lines
target-i386/kvm.c +9 -0
+        else {
+            if (banks>  MCE_BANKS_DEF)
+                banks = MCE_BANKS_DEF;
+            mcg_cap&= MCE_CAP_DEF;
+            mcg_cap |= banks;
+            if (kvm_setup_mce(env,&mcg_cap))
+                perror("kvm_setup_mce FAILED");
+            else
+                env->mcg_cap = mcg_cap;
 

CODING_STYLE.

Quoted 35 lines
target-i386/kvm.c +4 -0
+        }
+    }
+#endif
+
      return kvm_vcpu_ioctl(env, KVM_SET_CPUID2,&cpuid_data);
  }
target-i386/kvm_x86.h new file +21 -0
new file mode 100644
index 0000000..c1ebd24
@@ -0,0 +1,21 @@
+/*
+ * QEMU KVM support
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Anthony Liguori<[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef __KVM_X86_H__
+#define __KVM_X86_H__
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+
+#endif
#7 lore raw

PATCH 6/10 Export qemu_ram_addr_from_host

In reply to Marcelo Tosatti

To be used by next patches.

---
 cpu-common.h |    3 ++-
 exec-all.h   |    2 +-
 exec.c       |   26 +++++++++++++++++---------
 3 files changed, 20 insertions(+), 11 deletions(-)
cpu-common.h +2 -1
index 0426bc8..a543b5d 100644
@@ -47,7 +47,8 @@ void qemu_ram_free(ram_addr_t addr);
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
 /* This should not be used by devices.  */
-ram_addr_t qemu_ram_addr_from_host(void *ptr);
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr);
 
 int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
                            CPUWriteMemoryFunc * const *mem_write,
exec-all.h +1 -1
index 3a53fe6..c457058 100644
@@ -334,7 +334,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
     }
     p = (void *)(unsigned long)addr
         + env1->tlb_table[mmu_idx][page_index].addend;
-    return qemu_ram_addr_from_host(p);
+    return qemu_ram_addr_from_host_nofail(p);
 }
 #endif
 
exec.c +17 -9
index 1fbe91c..631d8c5 100644
@@ -2085,7 +2085,7 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
     if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
         p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
             + tlb_entry->addend);
-        ram_addr = qemu_ram_addr_from_host(p);
+        ram_addr = qemu_ram_addr_from_host_nofail(p);
         if (!cpu_physical_memory_is_dirty(ram_addr)) {
             tlb_entry->addr_write |= TLB_NOTDIRTY;
         }
@@ -2938,23 +2938,31 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
     return NULL;
 }
 
-/* Some of the softmmu routines need to translate from a host pointer
-   (typically a TLB entry) back to a ram offset.  */
-ram_addr_t qemu_ram_addr_from_host(void *ptr)
+int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
 {
     RAMBlock *block;
     uint8_t *host = ptr;
 
     QLIST_FOREACH(block, &ram_list.blocks, next) {
         if (host - block->host < block->length) {
-            return block->offset + (host - block->host);
+            *ram_addr = block->offset + (host - block->host);
+            return 0;
         }
     }
+    return -1;
+}
 
-    fprintf(stderr, "Bad ram pointer %p\n", ptr);
-    abort();
+/* Some of the softmmu routines need to translate from a host pointer
+   (typically a TLB entry) back to a ram offset.  */
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
+{
+    ram_addr_t ram_addr;
 
-    return 0;
+    if (qemu_ram_addr_from_host(ptr, &ram_addr)) {
+        fprintf(stderr, "Bad ram pointer %p\n", ptr);
+        abort();
+    }
+    return ram_addr;
 }
 
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -3703,7 +3711,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
 {
     if (buffer != bounce.buffer) {
         if (is_write) {
-            ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
+            ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
             while (access_len) {
                 unsigned l;
                 l = TARGET_PAGE_SIZE;
Signature · 1 line
1.7.2.1
#8 lore raw

PATCH 7/10 Add RAM -> physical addr mapping in MCE simulation

In reply to Marcelo Tosatti

From: Huang Ying <[email protected]>

In QEMU-KVM, physical address != RAM address. While MCE simulation needs physical address instead of RAM address. So kvm_physical_memory_addr_from_ram() is implemented to do the conversion, and it is invoked before being filled in the IA32_MCi_ADDR MSR.

---
 kvm-all.c |   18 ++++++++++++++++++
 kvm.h     |    6 ++++++
 2 files changed, 24 insertions(+), 0 deletions(-)
kvm-all.c +18 -0
index 1cc696f..37b99c7 100644
@@ -137,6 +137,24 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
     return found;
 }
 
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem = &s->slots[i];
+
+        if (ram_addr >= mem->phys_offset &&
+            ram_addr < mem->phys_offset + mem->memory_size) {
+            *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
 static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
 {
     struct kvm_userspace_memory_region mem;
kvm.h +6 -0
index 50b6c01..b2fb3af 100644
@@ -174,6 +174,12 @@ static inline void cpu_synchronize_post_init(CPUState *env)
     }
 }
 
+
+#if !defined(CONFIG_USER_ONLY)
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr);
+#endif
+
 #endif
 int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
 
Signature · 1 line
1.7.2.1
#9 lore raw

Re: [PATCH 07/10] Add RAM -> physical addr mapping in MCE simulation

Quoted 30 lines · Marcelo Tosatti

From: Huang Ying<[email protected]>

In QEMU-KVM, physical address != RAM address. While MCE simulation needs physical address instead of RAM address. So kvm_physical_memory_addr_from_ram() is implemented to do the conversion, and it is invoked before being filled in the IA32_MCi_ADDR MSR.

---
  kvm-all.c |   18 ++++++++++++++++++
  kvm.h     |    6 ++++++
  2 files changed, 24 insertions(+), 0 deletions(-)
kvm-all.c +5 -0
index 1cc696f..37b99c7 100644
@@ -137,6 +137,24 @@ static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
      return found;
  }
 
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr)
+{
+    int i;
+

kvm-all.c static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s, · line 154

Quoted 10 lines
kvm-all.c +9 -0
+    for (i = 0; i<  ARRAY_SIZE(s->slots); i++) {
+        KVMSlot *mem =&s->slots[i];
+
+        if (ram_addr>= mem->phys_offset&&
+            ram_addr<  mem->phys_offset + mem->memory_size) {
+            *phys_addr = mem->start_addr + (ram_addr - mem->phys_offset);
+            return 1;
+        }
+    }
 

This is bogus.

There isn't one mapping from ram_addr_t to target_phys_addr_t. There may be many because or RAM aliasing.

Using KVMSlot is also wrong. This is a function that belongs in exec.c.

Regards,

Anthony Liguori

Quoted 24 lines
kvm-all.c +3 -0
+    return 0;
+}
+
  static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
  {
      struct kvm_userspace_memory_region mem;
kvm.h +6 -0
index 50b6c01..b2fb3af 100644
@@ -174,6 +174,12 @@ static inline void cpu_synchronize_post_init(CPUState *env)
      }
  }
 
+
+#if !defined(CONFIG_USER_ONLY)
+int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
+                                      target_phys_addr_t *phys_addr);
+#endif
+
  #endif
  int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
 
#10 lore raw

PATCH 8/10 MCE: Relay UCR MCE to guest

In reply to Marcelo Tosatti

Port qemu-kvm's

commit 4b62fff1101a7ad77553147717a8bd3bf79df7ef

Author: Huang Ying <[email protected]>
Date:   Mon Sep 21 10:43:25 2009 +0800

MCE: Relay UCR MCE to guest

UCR (uncorrected recovery) MCE is supported in recent Intel CPUs, where some hardware error such as some memory error can be reported without PCC (processor context corrupted). To recover from such MCE, the corresponding memory will be unmapped, and all processes accessing the memory will be killed via SIGBUS.

For KVM, if QEMU/KVM is killed, all guest processes will be killed too. So we relay SIGBUS from host OS to guest system via a UCR MCE injection. Then guest OS can isolate corresponding memory and kill necessary guest processes only. SIGBUS sent to main thread (not VCPU threads) will be broadcast to all VCPU threads as UCR MCE.

---
 cpus.c                |   82 ++++++++++++++++++++--
 kvm-stub.c            |    5 ++
 kvm.h                 |    3 +
 target-i386/cpu.h     |   20 +++++-
 target-i386/helper.c  |    2 +-
 target-i386/kvm.c     |  178 ++++++++++++++++++++++++++++++++++++++++++++++++-
 target-i386/kvm_x86.h |    3 +-
 7 files changed, 279 insertions(+), 14 deletions(-)
cpus.c +74 -8
index 3875657..ad58c55 100644
@@ -34,6 +34,10 @@
 
 #include "cpus.h"
 #include "compatfd.h"
+#ifdef CONFIG_LINUX
+#include <sys/prctl.h>
+#include <sys/signalfd.h>
+#endif
 
 #ifdef SIGRTMIN
 #define SIG_IPI (SIGRTMIN+4)
@@ -41,6 +45,10 @@
 #define SIG_IPI SIGUSR1
 #endif
 
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
+#endif
+
 static CPUState *next_cpu;
 
 /***********************************************************/
@@ -498,28 +506,77 @@ static void qemu_tcg_wait_io_event(void)
     }
 }
 
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS, &action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();
+}
+
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
+{
+#if defined(TARGET_I386)
+    if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))
+#endif
+        sigbus_reraise();
+}
+
 static void qemu_kvm_eat_signal(CPUState *env, int timeout)
 {
     struct timespec ts;
     int r, e;
     siginfo_t siginfo;
     sigset_t waitset;
+    sigset_t chkset;
 
     ts.tv_sec = timeout / 1000;
     ts.tv_nsec = (timeout % 1000) * 1000000;
 
     sigemptyset(&waitset);
     sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    qemu_mutex_unlock(&qemu_global_mutex);
-    r = sigtimedwait(&waitset, &siginfo, &ts);
-    e = errno;
-    qemu_mutex_lock(&qemu_global_mutex);
+    do {
+        qemu_mutex_unlock(&qemu_global_mutex);
 
-    if (r == -1 && !(e == EAGAIN || e == EINTR)) {
-        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-        exit(1);
-    }
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1 && !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
+#endif
+                sigbus_reraise();
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
 }
 
 static void qemu_kvm_wait_io_event(CPUState *env)
@@ -640,6 +697,7 @@ static void kvm_init_ipi(CPUState *env)
 
     pthread_sigmask(SIG_BLOCK, NULL, &set);
     sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
     r = kvm_set_signal_mask(env, &set);
     if (r) {
         fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
@@ -650,6 +708,7 @@ static void kvm_init_ipi(CPUState *env)
 static sigset_t block_io_signals(void)
 {
     sigset_t set;
+    struct sigaction action;
 
     /* SIGUSR2 used by posix-aio-compat.c */
     sigemptyset(&set);
@@ -660,8 +719,15 @@ static sigset_t block_io_signals(void)
     sigaddset(&set, SIGIO);
     sigaddset(&set, SIGALRM);
     sigaddset(&set, SIG_IPI);
+    sigaddset(&set, SIGBUS);
     pthread_sigmask(SIG_BLOCK, &set, NULL);
 
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS, &action, NULL);
+    prctl(PR_MCE_KILL, 1, 1, 0, 0);
+
     return set;
 }
 
kvm-stub.c +5 -0
index d45f9fa..5384a4b 100644
@@ -141,3 +141,8 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
 {
     return -ENOSYS;
 }
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
kvm.h +3 -0
index b2fb3af..60a9b42 100644
@@ -110,6 +110,9 @@ int kvm_arch_init_vcpu(CPUState *env);
 
 void kvm_arch_reset_vcpu(CPUState *env);
 
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_on_sigbus(int code, void *addr);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
target-i386/cpu.h +18 -2
index 77eeab1..85ed30f 100644
@@ -250,16 +250,32 @@
 #define PG_ERROR_RSVD_MASK 0x08
 #define PG_ERROR_I_D_MASK  0x10
 
-#define MCG_CTL_P	(1UL<<8)   /* MCG_CAP register available */
+#define MCG_CTL_P	(1ULL<<8)   /* MCG_CAP register available */
+#define MCG_SER_P	(1ULL<<24) /* MCA recovery/new status bits */
 
-#define MCE_CAP_DEF	MCG_CTL_P
+#define MCE_CAP_DEF	(MCG_CTL_P|MCG_SER_P)
 #define MCE_BANKS_DEF	10
 
+#define MCG_STATUS_RIPV	(1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV	(1ULL<<1)   /* ip points to correct instruction */
 #define MCG_STATUS_MCIP	(1ULL<<2)   /* machine check in progress */
 
 #define MCI_STATUS_VAL	(1ULL<<63)  /* valid error */
 #define MCI_STATUS_OVER	(1ULL<<62)  /* previous errors lost */
 #define MCI_STATUS_UC	(1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN	(1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC	(1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S	(1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR	(1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF	0	/* segment offset */
+#define MCM_ADDR_LINEAR	1	/* linear address */
+#define MCM_ADDR_PHYS	2	/* physical address */
+#define MCM_ADDR_MEM	3	/* memory address */
+#define MCM_ADDR_GENERIC 7	/* generic */
 
 #define MSR_IA32_TSC                    0x10
 #define MSR_IA32_APICBASE               0x1b
target-i386/helper.c +1 -1
index 4b430dd..4fff4a8 100644
@@ -1032,7 +1032,7 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
         return;
 
     if (kvm_enabled()) {
-        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
         return;
     }
 
target-i386/kvm.c +176 -2

216 lines not on this page · raw message

target-i386/kvm_x86.h +2 -1
index c1ebd24..04932cf 100644
@@ -16,6 +16,7 @@
 #define __KVM_X86_H__
 
 void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error);
 
 #endif
Signature · 1 line
1.7.2.1
#11 lore raw

Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

Quoted 37 lines · Marcelo Tosatti

Port qemu-kvm's

commit 4b62fff1101a7ad77553147717a8bd3bf79df7ef

Author: Huang Ying<[email protected]>
Date:   Mon Sep 21 10:43:25 2009 +0800

MCE: Relay UCR MCE to guest

UCR (uncorrected recovery) MCE is supported in recent Intel CPUs, where some hardware error such as some memory error can be reported without PCC (processor context corrupted). To recover from such MCE, the corresponding memory will be unmapped, and all processes accessing the memory will be killed via SIGBUS.

For KVM, if QEMU/KVM is killed, all guest processes will be killed too. So we relay SIGBUS from host OS to guest system via a UCR MCE injection. Then guest OS can isolate corresponding memory and kill necessary guest processes only. SIGBUS sent to main thread (not VCPU threads) will be broadcast to all VCPU threads as UCR MCE.

---
  cpus.c                |   82 ++++++++++++++++++++--
  kvm-stub.c            |    5 ++
  kvm.h                 |    3 +
  target-i386/cpu.h     |   20 +++++-
  target-i386/helper.c  |    2 +-
  target-i386/kvm.c     |  178 ++++++++++++++++++++++++++++++++++++++++++++++++-
  target-i386/kvm_x86.h |    3 +-
  7 files changed, 279 insertions(+), 14 deletions(-)
cpus.c +0 -0
index 3875657..ad58c55 100644

cpus.c line 41

Quoted 8 lines
cpus.c +4 -0
@@ -34,6 +34,10 @@
 
  #include "cpus.h"
  #include "compatfd.h"
+#ifdef CONFIG_LINUX
+#include<sys/prctl.h>
+#include<sys/signalfd.h>
+#endif
 

signalfd() was introduced in 2.6.22 but this is unconditionally included. This is going to break the build on any old Linux systems.

Quoted 32 lines
cpus.c +19 -0
  #ifdef SIGRTMIN
  #define SIG_IPI (SIGRTMIN+4)
@@ -41,6 +45,10 @@
  #define SIG_IPI SIGUSR1
  #endif
 
+#ifndef PR_MCE_KILL
+#define PR_MCE_KILL 33
+#endif
+
  static CPUState *next_cpu;
 
  /***********************************************************/
@@ -498,28 +506,77 @@ static void qemu_tcg_wait_io_event(void)
      }
  }
 
+static void sigbus_reraise(void)
+{
+    sigset_t set;
+    struct sigaction action;
+
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = SIG_DFL;
+    if (!sigaction(SIGBUS,&action, NULL)) {
+        raise(SIGBUS);
+        sigemptyset(&set);
+        sigaddset(&set, SIGBUS);
+        sigprocmask(SIG_UNBLOCK,&set, NULL);
+    }
+    perror("Failed to re-raise SIGBUS!\n");
+    abort();

cpus.c static void qemu_tcg_wait_io_event(void) · line 533

Quoted 10 lines
cpus.c +9 -0
+}
+
+static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo,
+                           void *ctx)
+{
+#if defined(TARGET_I386)
+    if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr))
+#endif
+        sigbus_reraise();
 

This violates CODING style. Why not just get rid of the sigbus handler when not on TARGET_I386?

Quoted 47 lines
cpus.c +25 -8
+}
+
  static void qemu_kvm_eat_signal(CPUState *env, int timeout)
  {
      struct timespec ts;
      int r, e;
      siginfo_t siginfo;
      sigset_t waitset;
+    sigset_t chkset;
 
      ts.tv_sec = timeout / 1000;
      ts.tv_nsec = (timeout % 1000) * 1000000;
 
      sigemptyset(&waitset);
      sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    qemu_mutex_unlock(&qemu_global_mutex);
-    r = sigtimedwait(&waitset,&siginfo,&ts);
-    e = errno;
-    qemu_mutex_lock(&qemu_global_mutex);
+    do {
+        qemu_mutex_unlock(&qemu_global_mutex);
 
-    if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
-        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-        exit(1);
-    }
+        r = sigtimedwait(&waitset,&siginfo,&ts);
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
+#endif
+                sigbus_reraise();
+            break;
+        default:
+            break;

cpus.c static void qemu_tcg_wait_io_event(void) · line 581

Quoted 10 lines
cpus.c +8 -0
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
  }
 

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Shouldn't we be looping on just sigismember(SIGBUS)?

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

Quoted 20 lines

static void qemu_kvm_wait_io_event(CPUState *env)

cpus.c +2 -0
@@ -640,6 +697,7 @@ static void kvm_init_ipi(CPUState *env)
 
      pthread_sigmask(SIG_BLOCK, NULL,&set);
      sigdelset(&set, SIG_IPI);
+    sigdelset(&set, SIGBUS);
      r = kvm_set_signal_mask(env,&set);
      if (r) {
          fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
@@ -650,6 +708,7 @@ static void kvm_init_ipi(CPUState *env)
  static sigset_t block_io_signals(void)
  {
      sigset_t set;
+    struct sigaction action;
 
      /* SIGUSR2 used by posix-aio-compat.c */
      sigemptyset(&set);
@@ -660,8 +719,15 @@ static sigset_t block_io_signals(void)
      sigaddset(&set, SIGIO);
      sigaddset(&set, SIGALRM);

cpus.c static sigset_t block_io_signals(void) · line 730

Quoted 10 lines
cpus.c +6 -0
      sigaddset(&set, SIG_IPI);
+    sigaddset(&set, SIGBUS);
      pthread_sigmask(SIG_BLOCK,&set, NULL);
 
+    memset(&action, 0, sizeof(action));
+    action.sa_flags = SA_SIGINFO;
+    action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler;
+    sigaction(SIGBUS,&action, NULL);
+    prctl(PR_MCE_KILL, 1, 1, 0, 0);
 

We don't seem to do any checking of the return value here. EINVAL seems like an expected error to me.

Quoted 101 lines
cpus.c +0 -0
      return set;
  }
kvm-stub.c +5 -0
index d45f9fa..5384a4b 100644
@@ -141,3 +141,8 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
  {
      return -ENOSYS;
  }
+
+int kvm_on_sigbus(int code, void *addr)
+{
+    return 1;
+}
kvm.h +3 -0
index b2fb3af..60a9b42 100644
@@ -110,6 +110,9 @@ int kvm_arch_init_vcpu(CPUState *env);
 
  void kvm_arch_reset_vcpu(CPUState *env);
 
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
+int kvm_on_sigbus(int code, void *addr);
+
  struct kvm_guest_debug;
  struct kvm_debug_exit_arch;
 
target-i386/cpu.h +18 -2
index 77eeab1..85ed30f 100644
@@ -250,16 +250,32 @@
  #define PG_ERROR_RSVD_MASK 0x08
  #define PG_ERROR_I_D_MASK  0x10
 
-#define MCG_CTL_P	(1UL<<8)   /* MCG_CAP register available */
+#define MCG_CTL_P	(1ULL<<8)   /* MCG_CAP register available */
+#define MCG_SER_P	(1ULL<<24) /* MCA recovery/new status bits */
 
-#define MCE_CAP_DEF	MCG_CTL_P
+#define MCE_CAP_DEF	(MCG_CTL_P|MCG_SER_P)
  #define MCE_BANKS_DEF	10
 
+#define MCG_STATUS_RIPV	(1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV	(1ULL<<1)   /* ip points to correct instruction */
  #define MCG_STATUS_MCIP	(1ULL<<2)   /* machine check in progress */
 
  #define MCI_STATUS_VAL	(1ULL<<63)  /* valid error */
  #define MCI_STATUS_OVER	(1ULL<<62)  /* previous errors lost */
  #define MCI_STATUS_UC	(1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN	(1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC	(1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S	(1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR	(1ULL<<55)  /* Action required */
+
+/* MISC register defines */
+#define MCM_ADDR_SEGOFF	0	/* segment offset */
+#define MCM_ADDR_LINEAR	1	/* linear address */
+#define MCM_ADDR_PHYS	2	/* physical address */
+#define MCM_ADDR_MEM	3	/* memory address */
+#define MCM_ADDR_GENERIC 7	/* generic */
 
  #define MSR_IA32_TSC                    0x10
  #define MSR_IA32_APICBASE               0x1b
target-i386/helper.c +1 -1
index 4b430dd..4fff4a8 100644
@@ -1032,7 +1032,7 @@ void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
          return;
 
      if (kvm_enabled()) {
-        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
          return;
      }
 
target-i386/kvm.c +7 -0
index 343fb02..8e26bc4 100644
@@ -46,6 +46,13 @@
  #define MSR_KVM_WALL_CLOCK  0x11
  #define MSR_KVM_SYSTEM_TIME 0x12
 
+#ifndef BUS_MCEERR_AR
+#define BUS_MCEERR_AR 4
+#endif
+#ifndef BUS_MCEERR_AO
+#define BUS_MCEERR_AO 5
+#endif
+
  #ifdef KVM_CAP_EXT_CPUID
 
  static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)

target-i386/kvm.c static int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m) · line 205

Quoted 7 lines
target-i386/kvm.c +3 -0
@@ -192,10 +199,39 @@ static int kvm_set_mce(CPUState *env, struct kvm_x86_mce *m)
      return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, m);
  }
 
+static int kvm_get_msr(CPUState *env, struct kvm_msr_entry *msrs, int n)
+{
+    struct kvm_msrs *kmsrs = qemu_malloc(sizeof *kmsrs + n * sizeof *msrs);
 

sizeof should take ()s.

Quoted 35 lines
target-i386/kvm.c +26 -0
+    int r;
+
+    kmsrs->nmsrs = n;
+    memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
+    r = kvm_vcpu_ioctl(env, KVM_GET_MSRS, kmsrs);
+    memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
+    free(kmsrs);
+    return r;
+}
+
+/* FIXME: kill this and kvm_get_msr, use env->mcg_status instead */
+static int kvm_mce_in_exception(CPUState *env)
+{
+    struct kvm_msr_entry msr_mcg_status = {
+        .index = MSR_MCG_STATUS,
+    };
+    int r;
+
+    r = kvm_get_msr(env,&msr_mcg_status, 1);
+    if (r == -1 || r == 0) {
+        return -1;
+    }
+    return !!(msr_mcg_status.data&  MCG_STATUS_MCIP);
+}
+
  struct kvm_x86_mce_data
  {
      CPUState *env;
      struct kvm_x86_mce *mce;
+    int abort_on_error;
  };
 

static void kvm_do_inject_x86_mce(void *_data)

target-i386/kvm.c +0 -0
@@ -203,14 +239,26 @@ static void kvm_do_inject_x86_mce(void *_data)
      struct kvm_x86_mce_data *data = _data;

target-i386/kvm.c static void kvm_do_inject_x86_mce(void *_data) · line 249

Quoted 10 lines
target-i386/kvm.c +7 -0
      int r;
 
+    /* If there is an MCE excpetion being processed, ignore this SRAO MCE */
+    r = kvm_mce_in_exception(data->env);
+    if (r == -1)
+        fprintf(stderr, "Failed to get MCE status\n");
+    else if (r&&  !(data->mce->status&  MCI_STATUS_AR))
+        return;
+
 

CODING_STYLE.

Quoted 19 lines
target-i386/kvm.c +7 -2
      r = kvm_set_mce(data->env, data->mce);
-    if (r<  0)
+    if (r<  0) {
          perror("kvm_set_mce FAILED");
+        if (data->abort_on_error) {
+            abort();
+        }
+    }
  }
  #endif
 
  void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc)
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error)
  {
  #ifdef KVM_CAP_MCE
      struct kvm_x86_mce mce = {

target-i386/kvm.c void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, · line 279

Quoted 7 lines
target-i386/kvm.c +3 -0
@@ -225,7 +273,15 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
              .mce =&mce,
      };
 
+    if (!cenv->mcg_cap) {
+        fprintf(stderr, "MCE support is not enabled!\n");
+        return;
 

But we unconditionally enable this functionality so that means we're going to get spammed on stderr whenever an MCE occurs.

We really should not register a sigbus handler unless KVM supports injection and let the process get killed.

target-i386/kvm.c void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, · line 287

Quoted 7 lines
target-i386/kvm.c +5 -0
+    }
+
      run_on_cpu(cenv, kvm_do_inject_x86_mce,&data);
+#else
+    if (abort_on_error)
+        abort();
 

CODING_STYLE

target-i386/kvm.c bool kvm_arch_stop_on_emulation_error(CPUState *env) · line 1591

Quoted 13 lines
target-i386/kvm.c +0 -0
  #endif
  }
target-i386/kvm.c +5 -0
@@ -1528,3 +1584,121 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
                ((env->segs[R_CS].selector&  3) != 3);
  }
 
+static void hardware_memory_error(void)
+{
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
+}

This shouldn't be here.

Quoted 35 lines
target-i386/kvm.c +34 -0
+int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+#if defined(KVM_CAP_MCE)
+    struct kvm_x86_mce mce = {
+            .bank = 9,
+    };
+    void *vaddr;
+    ram_addr_t ram_addr;
+    target_phys_addr_t paddr;
+    int r;
+
+    if ((env->mcg_cap&  MCG_SER_P)&&  addr
+&&  (code == BUS_MCEERR_AR
+            || code == BUS_MCEERR_AO)) {
+        if (code == BUS_MCEERR_AR) {
+            /* Fake an Intel architectural Data Load SRAR UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | MCI_STATUS_AR | 0x134;
+            mce.misc = (MCM_ADDR_PHYS<<  6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
+        } else {
+            /*
+             * If there is an MCE excpetion being processed, ignore
+             * this SRAO MCE
+             */
+            r = kvm_mce_in_exception(env);
+            if (r == -1) {
+                fprintf(stderr, "Failed to get MCE status\n");
+            } else if (r) {
+                return 0;
+            }
+            /* Fake an Intel architectural Memory scrubbing UCR */
+            mce.status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN

target-i386/kvm.c bool kvm_arch_stop_on_emulation_error(CPUState *env) · line 1636

Quoted 10 lines
target-i386/kvm.c +10 -0
+                | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                | 0xc0;
+            mce.misc = (MCM_ADDR_PHYS<<  6) | 0xc;
+            mce.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        }
+        vaddr = (void *)addr;
+        if (qemu_ram_addr_from_host(vaddr,&ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr,&paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!\n");

This is not a very useful way to handle this condition. why not at least reraise a SIGBUS so that we have a proper core?

target-i386/kvm.c bool kvm_arch_stop_on_emulation_error(CPUState *env) · line 1648

Quoted 13 lines
target-i386/kvm.c +12 -0
+            /* Hope we are lucky for AO MCE */
+            if (code == BUS_MCEERR_AO) {
+                return 0;
+            } else {
+                hardware_memory_error();
+            }
+        }
+        mce.addr = paddr;
+        r = kvm_set_mce(env,&mce);
+        if (r<  0) {
+            fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
+            abort();

There are calls to hardware_memory_error() and fprintf() in the same function. It all should be error_report().

Quoted 14 lines
target-i386/kvm.c +13 -0
+        }
+    } else
+#endif
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;

target-i386/kvm.c bool kvm_arch_stop_on_emulation_error(CPUState *env) · line 1671

Quoted 10 lines
target-i386/kvm.c +10 -0
+}
+
+int kvm_on_sigbus(int code, void *addr)
+{
+#if defined(KVM_CAP_MCE)
+    if ((first_cpu->mcg_cap&  MCG_SER_P)&&  addr&&  code == BUS_MCEERR_AO) {
+        uint64_t status;
+        void *vaddr;
+        target_phys_addr_t ram_addr;
+        unsigned long paddr;

ram_addr should be ram_addr_t and paddr should be target_phys_addr_t.

target-i386/kvm.c bool kvm_arch_stop_on_emulation_error(CPUState *env) · line 1679

Quoted 9 lines
target-i386/kvm.c +8 -0
+        CPUState *cenv;
+
+        /* Hope we are lucky for AO MCE */
+        vaddr = addr;
+        if (qemu_ram_addr_from_host(vaddr,&ram_addr) ||
+            !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr,&paddr)) {
+            fprintf(stderr, "Hardware memory error for memory used by "
+                    "QEMU itself instead of guest system!: %p\n", addr);

Again, this is not a useful way to handle this.

Quoted 31 lines
target-i386/kvm.c +25 -0
+            return 0;
+        }
+        status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+            | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+            | 0xc0;
+        kvm_inject_x86_mce(first_cpu, 9, status,
+                           MCG_STATUS_MCIP | MCG_STATUS_RIPV, paddr,
+                           (MCM_ADDR_PHYS<<  6) | 0xc, 1);
+        for (cenv = first_cpu->next_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+            kvm_inject_x86_mce(cenv, 1, MCI_STATUS_VAL | MCI_STATUS_UC,
+                               MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, 1);
+        }
+    } else
+#endif
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
target-i386/kvm_x86.h +0 -0
index c1ebd24..04932cf 100644

target-i386/kvm_x86.h line 22

Quoted 8 lines
target-i386/kvm_x86.h +2 -1
@@ -16,6 +16,7 @@
  #define __KVM_X86_H__
 
  void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc);
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int abort_on_error);
 
  #endif

Regards,

Anthony Liguori

#12 lore raw

Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

Quoted 62 lines · Anthony Liguori
Quoted 57 lines
cpus.c +20 -8
+}
+
  static void qemu_kvm_eat_signal(CPUState *env, int timeout)
  {
      struct timespec ts;
      int r, e;
      siginfo_t siginfo;
      sigset_t waitset;
+    sigset_t chkset;
 
      ts.tv_sec = timeout / 1000;
      ts.tv_nsec = (timeout % 1000) * 1000000;
 
      sigemptyset(&waitset);
      sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    qemu_mutex_unlock(&qemu_global_mutex);
-    r = sigtimedwait(&waitset,&siginfo,&ts);
-    e = errno;
-    qemu_mutex_lock(&qemu_global_mutex);
+    do {
+        qemu_mutex_unlock(&qemu_global_mutex);
 
-    if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
-        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-        exit(1);
-    }
+        r = sigtimedwait(&waitset,&siginfo,&ts);
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, 

siginfo.si_addr))

cpus.c +13 -0
+#endif
+                sigbus_reraise();
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, 
Quoted 2 lines

SIGBUS));
}

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Quoted 3 lines

Shouldn't we be looping on just sigismember(SIGBUS)?

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

I think this is important too. The last time I went through the code and played around here, it wasn't possible to set timeout to a very, very large value because there are still things that we poll for (like whether shutdown has occurred). If we loop indefinitely without reducing ts, we can potentially recreate an infinite timeout which means we won't catch any of the events we poll for. This would be a very, very subtle bug to track down.

Regards,

Anthony Liguori

#13 lore raw

Re: [Qemu-devel] Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

Quoted 71 lines · Anthony Liguori
Quoted 65 lines · Anthony Liguori
Quoted 57 lines
cpus.c +20 -8
+}
+
 static void qemu_kvm_eat_signal(CPUState *env, int timeout)
 {
     struct timespec ts;
     int r, e;
     siginfo_t siginfo;
     sigset_t waitset;
+    sigset_t chkset;
 
     ts.tv_sec = timeout / 1000;
     ts.tv_nsec = (timeout % 1000) * 1000000;
 
     sigemptyset(&waitset);
     sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
 
-    qemu_mutex_unlock(&qemu_global_mutex);
-    r = sigtimedwait(&waitset,&siginfo,&ts);
-    e = errno;
-    qemu_mutex_lock(&qemu_global_mutex);
+    do {
+        qemu_mutex_unlock(&qemu_global_mutex);
 
-    if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
-        fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
-        exit(1);
-    }
+        r = sigtimedwait(&waitset,&siginfo,&ts);
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code,

siginfo.si_addr))

cpus.c +13 -0
+#endif
+                sigbus_reraise();
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) ||
Quoted 2 lines

sigismember(&chkset, SIGBUS));
}

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Quoted 4 lines

Shouldn't we be looping on just sigismember(SIGBUS)?

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

Quoted 7 lines

I think this is important too. The last time I went through the code and played around here, it wasn't possible to set timeout to a very, very large value because there are still things that we poll
for (like whether shutdown has occurred). If we loop indefinitely
without reducing ts, we can potentially recreate an infinite timeout which means we won't catch any of the events we poll for. This would be a very, very subtle bug to track down.

We should just kill timeout parameter, i don't see any use for it.

#14 lore raw

Re: [Qemu-devel] Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

In reply to Anthony Liguori
Quoted 33 lines · Anthony Liguori
Quoted 17 lines
cpus.c +17 -0
+        e = errno;
+
+        qemu_mutex_lock(&qemu_global_mutex);
+
+        if (r == -1&&  !(e == EAGAIN || e == EINTR)) {
+            fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+#ifdef TARGET_I386
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr))
+#endif
+                sigbus_reraise();
+            break;
+        default:

cpus.c static void qemu_tcg_wait_io_event(void) · line 580

Quoted 10 lines
cpus.c +9 -0
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            fprintf(stderr, "sigpending: %s\n", strerror(e));
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
 }

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Quoted 1 line

Shouldn't we be looping on just sigismember(SIGBUS)?

Think of SIG_IPI and SIGBUS pending. SIGBUS must be processed immediately.

Yes, sigismember(SIGBUS) would be fine. But the current code too.

Quoted 2 lines

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

Right, timeout not used at the moment.

maintainer
#15 lore raw

Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

In reply to Anthony Liguori
Quoted 5 lines · Anthony Liguori

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Shouldn't we be looping on just sigismember(SIGBUS)?

You mean because SIG_IPI is a real-time signal and standard signals are delivered first? OTOH, real-time signals can be queued multiple times so it makes sense to loop on SIG_IPI as well.

Quoted 2 lines

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

The timeout of qemu_kvm_eat_signal is always zero.

Paolo

#16 lore raw

Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

Quoted 5 lines · Paolo Bonzini
Quoted 4 lines · Anthony Liguori

I don't understand why this loop is needed but we specifically wait for a signal to get delivered that's either SIG_IPI or SIGBUS. We then check whether a SIG_IPI or SIGBUS is pending and loop waiting for signals again.

Quoted 8 lines
Quoted 1 line

Shouldn't we be looping on just sigismember(SIGBUS)?

You mean because SIG_IPI is a real-time signal and standard signals are delivered first? OTOH, real-time signals can be queued multiple times so it makes sense to loop on SIG_IPI as well.

Quoted 2 lines

BTW, we're no longer respecting timeout because we're not adjusting ts after each iteration.

The timeout of qemu_kvm_eat_signal is always zero.

So then qemu_kvm_eat_signal purely polls and it will happily keep polling as long as there is a signal pending.

So what's the point of doing a sigtimedwait() and dropping qemu_mutex? Why not just check sigpending in a loop?

Regards,

Anthony Liguori

Quoted 1 line

Paolo

maintainer
#17 lore raw

Re: [PATCH 08/10] MCE: Relay UCR MCE to guest

Quoted 7 lines · Anthony Liguori
Quoted 2 lines

The timeout of qemu_kvm_eat_signal is always zero.

So then qemu_kvm_eat_signal purely polls and it will happily keep polling as long as there is a signal pending.

So what's the point of doing a sigtimedwait() and dropping qemu_mutex?

I agree that keeping the qemu_mutex makes sense if you remove the timeout argument (which I even have a patch for, as part of my Win32 iothread series). Until there is the theoretical possibility of suspending the process, qemu_kvm_eat_signal should drop the mutex.

Quoted 1 line

Why not just check sigpending in a loop?

Because sigtimedwait eats the signal, unlike sigpending (and sigsuspend).

#18 lore raw

PATCH 9/10 Add savevm/loadvm support for MCE

In reply to Marcelo Tosatti

Port qemu-kvm's

commit 1bab5d11545d8de5facf46c28630085a2f9651ae

Author: Huang Ying <[email protected]>
Date:   Wed Mar 3 16:52:46 2010 +0800

Add savevm/loadvm support for MCE

MCE registers are saved/load into/from CPUState in kvm_arch_save/load_regs. To simulate the MCG_STATUS clearing upon reset, MSR_MCG_STATUS is set to 0 for KVM_PUT_RESET_STATE.

---
 target-i386/kvm.c |   39 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 38 insertions(+), 1 deletions(-)
target-i386/kvm.c +38 -1
index 8e26bc4..1701cb9 100644
@@ -777,7 +777,7 @@ static int kvm_put_msrs(CPUState *env, int level)
         struct kvm_msr_entry entries[100];
     } msr_data;
     struct kvm_msr_entry *msrs = msr_data.entries;
-    int n = 0;
+    int i, n = 0;
 
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
@@ -797,6 +797,18 @@ static int kvm_put_msrs(CPUState *env, int level)
                           env->system_time_msr);
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
     }
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        if (level == KVM_PUT_RESET_STATE)
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+        else if (level == KVM_PUT_FULL_STATE) {
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
+            for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++)
+                kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
+        }
+    }
+#endif
 
     msr_data.info.nmsrs = n;
 
@@ -1004,6 +1016,15 @@ static int kvm_get_msrs(CPUState *env)
     msrs[n++].index = MSR_KVM_SYSTEM_TIME;
     msrs[n++].index = MSR_KVM_WALL_CLOCK;
 
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        msrs[n++].index = MSR_MCG_STATUS;
+        msrs[n++].index = MSR_MCG_CTL;
+        for (i = 0; i < (env->mcg_cap & 0xff) * 4; i++)
+            msrs[n++].index = MSR_MC0_CTL + i;
+    }
+#endif
+
     msr_data.info.nmsrs = n;
     ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS, &msr_data);
     if (ret < 0)
@@ -1046,6 +1067,22 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_KVM_WALL_CLOCK:
             env->wall_clock_msr = msrs[i].data;
             break;
+#ifdef KVM_CAP_MCE
+        case MSR_MCG_STATUS:
+            env->mcg_status = msrs[i].data;
+            break;
+        case MSR_MCG_CTL:
+            env->mcg_ctl = msrs[i].data;
+            break;
+#endif
+        default:
+#ifdef KVM_CAP_MCE
+            if (msrs[i].index >= MSR_MC0_CTL &&
+                msrs[i].index < MSR_MC0_CTL + (env->mcg_cap & 0xff) * 4) {
+                env->mce_banks[msrs[i].index - MSR_MC0_CTL] = msrs[i].data;
+                break;
+            }
+#endif
         }
     }
 
Signature · 1 line
1.7.2.1
#19 lore raw

Re: [PATCH 09/10] Add savevm/loadvm support for MCE

Quoted 38 lines · Marcelo Tosatti

Port qemu-kvm's

commit 1bab5d11545d8de5facf46c28630085a2f9651ae

Author: Huang Ying<[email protected]>
Date:   Wed Mar 3 16:52:46 2010 +0800

Add savevm/loadvm support for MCE

MCE registers are saved/load into/from CPUState in kvm_arch_save/load_regs. To simulate the MCG_STATUS clearing upon reset, MSR_MCG_STATUS is set to 0 for KVM_PUT_RESET_STATE.

---
  target-i386/kvm.c |   39 ++++++++++++++++++++++++++++++++++++++-
  1 files changed, 38 insertions(+), 1 deletions(-)
target-i386/kvm.c +4 -1
index 8e26bc4..1701cb9 100644
@@ -777,7 +777,7 @@ static int kvm_put_msrs(CPUState *env, int level)
          struct kvm_msr_entry entries[100];
      } msr_data;
      struct kvm_msr_entry *msrs = msr_data.entries;
-    int n = 0;
+    int i, n = 0;
 
      kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
      kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
@@ -797,6 +797,18 @@ static int kvm_put_msrs(CPUState *env, int level)
                            env->system_time_msr);
          kvm_msr_entry_set(&msrs[n++], MSR_KVM_WALL_CLOCK, env->wall_clock_msr);
      }
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        if (level == KVM_PUT_RESET_STATE)

target-i386/kvm.c static int kvm_put_msrs(CPUState *env, int level) · line 812

Quoted 10 lines
target-i386/kvm.c +9 -0
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+        else if (level == KVM_PUT_FULL_STATE) {
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_STATUS, env->mcg_status);
+            kvm_msr_entry_set(&msrs[n++], MSR_MCG_CTL, env->mcg_ctl);
+            for (i = 0; i<  (env->mcg_cap&  0xff) * 4; i++)
+                kvm_msr_entry_set(&msrs[n++], MSR_MC0_CTL + i, env->mce_banks[i]);
+        }
+    }
+#endif
 

What happens if we live migration from a kernel with KVM_CAP_MCE to a kernel without KVM_CAP_MCE. Don't we need to bump a version somewhere?

Quoted 6 lines
target-i386/kvm.c +0 -0
      msr_data.info.nmsrs = n;
 
@@ -1004,6 +1016,15 @@ static int kvm_get_msrs(CPUState *env)
      msrs[n++].index = MSR_KVM_SYSTEM_TIME;
      msrs[n++].index = MSR_KVM_WALL_CLOCK;
 

target-i386/kvm.c static int kvm_get_msrs(CPUState *env) · line 1028

Quoted 10 lines
target-i386/kvm.c +9 -0
+#ifdef KVM_CAP_MCE
+    if (env->mcg_cap) {
+        msrs[n++].index = MSR_MCG_STATUS;
+        msrs[n++].index = MSR_MCG_CTL;
+        for (i = 0; i<  (env->mcg_cap&  0xff) * 4; i++)
+            msrs[n++].index = MSR_MC0_CTL + i;
+    }
+#endif
+
 

This patch does not respect CODING_STYLE with respect to single line ifs at all.

Regards,

Anthony Liguori

Quoted 27 lines
target-i386/kvm.c +0 -0
      msr_data.info.nmsrs = n;
      ret = kvm_vcpu_ioctl(env, KVM_GET_MSRS,&msr_data);
      if (ret<  0)
target-i386/kvm.c +16 -0
@@ -1046,6 +1067,22 @@ static int kvm_get_msrs(CPUState *env)
          case MSR_KVM_WALL_CLOCK:
              env->wall_clock_msr = msrs[i].data;
              break;
+#ifdef KVM_CAP_MCE
+        case MSR_MCG_STATUS:
+            env->mcg_status = msrs[i].data;
+            break;
+        case MSR_MCG_CTL:
+            env->mcg_ctl = msrs[i].data;
+            break;
+#endif
+        default:
+#ifdef KVM_CAP_MCE
+            if (msrs[i].index>= MSR_MC0_CTL&&
+                msrs[i].index<  MSR_MC0_CTL + (env->mcg_cap&  0xff) * 4) {
+                env->mce_banks[msrs[i].index - MSR_MC0_CTL] = msrs[i].data;
+                break;
+            }
+#endif
          }
      }
 
#20 lore raw

PATCH 10/10 Fix memory leak in register save load due to xsave support

In reply to Marcelo Tosatti

From: Avi Kivity <[email protected]>

---
 target-i386/kvm.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)
target-i386/kvm.c +8 -3
index 1701cb9..2449c2f 100644
@@ -660,7 +660,7 @@ static int kvm_put_fpu(CPUState *env)
 static int kvm_put_xsave(CPUState *env)
 {
 #ifdef KVM_CAP_XSAVE
-    int i;
+    int i, r;
     struct kvm_xsave* xsave;
     uint16_t cwd, swd, twd, fop;
 
@@ -685,7 +685,9 @@ static int kvm_put_xsave(CPUState *env)
     *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV] = env->xstate_bv;
     memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs,
             sizeof env->ymmh_regs);
-    return kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
+    r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave);
+    qemu_free(xsave);
+    return r;
 #else
     return kvm_put_fpu(env);
 #endif
@@ -850,8 +852,10 @@ static int kvm_get_xsave(CPUState *env)
 
     xsave = qemu_memalign(4096, sizeof(struct kvm_xsave));
     ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave);
-    if (ret < 0)
+    if (ret < 0) {
+        qemu_free(xsave);
         return ret;
+    }
 
     cwd = (uint16_t)xsave->region[0];
     swd = (uint16_t)(xsave->region[0] >> 16);
@@ -870,6 +874,7 @@ static int kvm_get_xsave(CPUState *env)
     env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV];
     memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE],
             sizeof env->ymmh_regs);
+    qemu_free(xsave);
     return 0;
 #else
     return kvm_get_fpu(env);
Signature · 1 line
1.7.2.1
#21 lore raw
In reply to Marcelo Tosatti
Quoted 14 lines · Marcelo Tosatti

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

   issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Huang Ying (1):

       Add RAM ->  physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Quoted 9 lines

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

Does this fix the second build issue too is this is just with v2 of hte Relay UCR MCE to guest?

Regards,

ANthony Liguori

Quoted 25 lines
  Makefile.objs         |    1 +
  compatfd.c            |  117 ++++++++++++++++++
  compatfd.h            |   43 +++++++
  configure             |   18 +++
  cpu-common.h          |    3 +-
  cpus.c                |  156 ++++++++++++++++++++++--
  exec-all.h            |    2 +-
  exec.c                |   26 +++--
  kvm-all.c             |   18 +++
  kvm-stub.c            |    5 +
  kvm.h                 |    9 ++
  target-i386/cpu.h     |   32 +++++-
  target-i386/cpuid.c   |   79 ++++++++++---
  target-i386/helper.c  |    6 +
  target-i386/kvm.c     |  311 ++++++++++++++++++++++++++++++++++++++++++++++++-
  target-i386/kvm_x86.h |   22 ++++
  16 files changed, 801 insertions(+), 47 deletions(-)

create mode 100644 compatfd.c
create mode 100644 compatfd.h
create mode 100644 target-i386/kvm_x86.h
--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#22 lore raw
Quoted 24 lines · Anthony Liguori
Quoted 14 lines · Marcelo Tosatti

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Huang Ying (1):

      Add RAM ->  physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Quoted 8 lines

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

Quoted 2 lines

Does this fix the second build issue too is this is just with v2 of hte Relay UCR MCE to guest?

Yes, second and third...

#23 lore raw
Quoted 27 lines · Marcelo Tosatti
Quoted 25 lines · Anthony Liguori
Quoted 23 lines · Marcelo Tosatti

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

   issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Huang Ying (1):

       Add RAM ->   physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

Quoted 5 lines
Quoted 3 lines

Does this fix the second build issue too is this is just with v2 of hte Relay UCR MCE to guest?

Yes, second and third...

That wasn't enough either. The types used in this code aren't correct.

I've fixed up the build and pushed http://repo.or.cz/w/qemu/aliguori.git qemu-kvm-20101020

Let me test a little bit and look a bit more closely at the code and then I'll push to the main tree.

Regards,

Anthony Liguori

#24 lore raw
In reply to Marcelo Tosatti
Quoted 14 lines · Marcelo Tosatti

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

   issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Huang Ying (1):

       Add RAM ->  physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Quoted 9 lines

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

The MCE doesn't look to be ready for prime time yet.

Regards,

Anthony Liguori

Quoted 21 lines
  Makefile.objs         |    1 +
  compatfd.c            |  117 ++++++++++++++++++
  compatfd.h            |   43 +++++++
  configure             |   18 +++
  cpu-common.h          |    3 +-
  cpus.c                |  156 ++++++++++++++++++++++--
  exec-all.h            |    2 +-
  exec.c                |   26 +++--
  kvm-all.c             |   18 +++
  kvm-stub.c            |    5 +
  kvm.h                 |    9 ++
  target-i386/cpu.h     |   32 +++++-
  target-i386/cpuid.c   |   79 ++++++++++---
  target-i386/helper.c  |    6 +
  target-i386/kvm.c     |  311 ++++++++++++++++++++++++++++++++++++++++++++++++-
  target-i386/kvm_x86.h |   22 ++++
  16 files changed, 801 insertions(+), 47 deletions(-)

create mode 100644 compatfd.c
create mode 100644 compatfd.h
create mode 100644 target-i386/kvm_x86.h

#25 lore raw
In reply to Marcelo Tosatti
Quoted 7 lines · Marcelo Tosatti

The following changes since commit 38cc9b607f85017b095793cab6c129bc9844f441:

   issue snd_pcm_start() when capturing audio (2010-10-18 00:39:06 +0400)

are available in the git repository at:
git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git uq/master

Pulled (with additional build fixes).

Regards,

Anthony Liguori

Quoted 37 lines

Huang Ying (1):

       Add RAM ->  physical addr mapping in MCE simulation

Joerg Roedel (2):
Set cpuid definition to 0 before initializing it Add svm cpuid features

Marcelo Tosatti (7):
signalfd compatibility
iothread: use signalfd
kvm: x86: add mce support
Export qemu_ram_addr_from_host
MCE: Relay UCR MCE to guest
Add savevm/loadvm support for MCE
Fix memory leak in register save load due to xsave support

  Makefile.objs         |    1 +
  compatfd.c            |  117 ++++++++++++++++++
  compatfd.h            |   43 +++++++
  configure             |   18 +++
  cpu-common.h          |    3 +-
  cpus.c                |  156 ++++++++++++++++++++++--
  exec-all.h            |    2 +-
  exec.c                |   26 +++--
  kvm-all.c             |   18 +++
  kvm-stub.c            |    5 +
  kvm.h                 |    9 ++
  target-i386/cpu.h     |   32 +++++-
  target-i386/cpuid.c   |   79 ++++++++++---
  target-i386/helper.c  |    6 +
  target-i386/kvm.c     |  311 ++++++++++++++++++++++++++++++++++++++++++++++++-
  target-i386/kvm_x86.h |   22 ++++
  16 files changed, 801 insertions(+), 47 deletions(-)

create mode 100644 compatfd.c
create mode 100644 compatfd.h
create mode 100644 target-i386/kvm_x86.h