Skip to contentSkip to conversation

qemu-kvm.git uq/master queue

GIT PULL In review Marcelo Tosatti 2 participants 38 messages Mar 15, 2011 – Mar 16, 2011 KVM

lore
Share & tools
lore
#0 lore raw

The following changes since commit cc015e9a5dde2f03f123357fa060acbdfcd570a4:

add Win32 IPI service (2011-03-13 14:44:22 +0000)

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

Huang Ying (2):
Add qemu_ram_remap
KVM, MCE, unpoison memory address across reboot

Jan Kiszka (33):
kvm: ppc: Fix breakage of kvm_arch_pre_run/process_irqchip_events
kvm: Fix build warning when KVM_CAP_SET_GUEST_DEBUG is lacking
x86: Account for MCE in cpu_has_work
x86: Perform implicit mcg_status reset
x86: Small cleanups of MCE helpers
x86: Refine error reporting of MCE injection services
x86: Optionally avoid injecting AO MCEs while others are pending Synchronize VCPU states before reset
kvm: x86: Move MCE functions together
kvm: Rename kvm_arch_process_irqchip_events to async_events
kvm: x86: Inject pending MCE events on state writeback
x86: Run qemu_inject_x86_mce on target VCPU
kvm: x86: Consolidate TCG and KVM MCE injection code
kvm: x86: Clean up kvm_setup_mce
kvm: x86: Fail kvm_arch_init_vcpu if MCE initialization fails Implement qemu_kvm_eat_signals only for CONFIG_LINUX
x86: Unbreak TCG support for hardware breakpoints
s390: Detect invalid invocations of qemu_ram_free/remap Break up user and system cpu_interrupt implementations
kvm: Add in-kernel irqchip awareness to cpu_thread_is_idle
kvm: x86: Do not leave halt if interrupts are disabled
kvm: Mark VCPU state dirty on creation
x86: Properly reset PAT MSR
x86: Save/restore PAT MSR
kvm: x86: Synchronize PAT MSR with the kernel
kvm: Consider EXIT_DEBUG unknown without CAP_SET_GUEST_DEBUG
kvm: Keep KVM_RUN return value in separate variable
kvm: Reorder error handling of KVM_RUN
kvm: Rework inner loop of kvm_cpu_exec
kvm: Align kvm_arch_handle_exit to kvm_cpu_exec changes
kvm: x86: Reorder functions in kvm.c
kvm: x86: Push kvm_arch_debug to kvm_arch_handle_exit Expose thread_id in info cpus

 cpu-all.h             |    8 +-
 cpu-common.h          |    1 +
 cpu-defs.h            |    1 +
 cpu-exec.c            |   27 +++
 cpus.c                |  126 +++++------
 exec.c                |   84 +++++++-
 kvm-all.c             |   46 ++---
 kvm.h                 |    4 +-
 monitor.c             |   15 +-
 os-posix.c            |   10 +
 os-win32.c            |    5 +
 osdep.h               |    1 +
 qemu-common.h         |    6 +-
 qmp-commands.hx       |    3 +
 target-i386/cpu.h     |   13 +-
 target-i386/cpuid.c   |    1 -
 target-i386/exec.h    |   15 +-
 target-i386/helper.c  |  190 ++++++++++------
 target-i386/kvm.c     |  593 +++++++++++++++++++++----------------------------
 target-i386/kvm_x86.h |   25 --
 target-i386/machine.c |    2 +
 target-ppc/kvm.c      |   14 +-
 target-s390x/kvm.c    |    7 +-
 vl.c                  |    1 +
 24 files changed, 628 insertions(+), 570 deletions(-)
 delete mode 100644 target-i386/kvm_x86.h
#1 lore raw

PATCH 1/35 kvm: ppc: Fix breakage of kvm_arch_pre_run/process_irqchip_events

From: Jan Kiszka <[email protected]>

Commit 7a39fe5882 failed to convert the right arch function.

---
 target-ppc/kvm.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
target-ppc/kvm.c +3 -3
index bd4012a..3924f4b 100644
@@ -222,7 +222,7 @@ int kvmppc_set_interrupt(CPUState *env, int irq, int level)
 #define PPC_INPUT_INT PPC6xx_INPUT_INT
 #endif
 
-int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
+void kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
 {
     int r;
     unsigned irq;
@@ -253,15 +253,15 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run)
     /* We don't know if there are more interrupts pending after this. However,
      * the guest will return to userspace in the course of handling this one
      * anyways, so we will get a chance to deliver the rest. */
-    return 0;
 }
 
 void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
 }
 
-void kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_irqchip_events(CPUState *env)
 {
+    return 0;
 }
 
 static int kvmppc_handle_halt(CPUState *env)
Signature · 1 line
1.7.4
#2 lore raw

PATCH 2/35 kvm: Fix build warning when KVM_CAP_SET_GUEST_DEBUG is lacking

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Original fix by David Gibson.

---
 kvm-all.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
kvm-all.c +2 -0
index e6a7de4..7753c8a 100644
@@ -998,7 +998,9 @@ int kvm_cpu_exec(CPUState *env)
     }
     ret = EXCP_INTERRUPT;
 
+#ifdef KVM_CAP_SET_GUEST_DEBUG
 out:
+#endif
     env->exit_request = 0;
     cpu_single_env = NULL;
     return ret;
Signature · 1 line
1.7.4
#3 lore raw

PATCH 3/35 x86: Account for MCE in cpu_has_work

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

MCEs can be injected asynchronously, so they can also terminate the halt state.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/exec.h |   15 ++++++---------
 1 files changed, 6 insertions(+), 9 deletions(-)
target-i386/exec.h +6 -9
index 3e7386e..6f9f709 100644
@@ -293,15 +293,12 @@ static inline void load_eflags(int eflags, int update_mask)
 
 static inline int cpu_has_work(CPUState *env)
 {
-    int work;
-
-    work = (env->interrupt_request & CPU_INTERRUPT_HARD) &&
-           (env->eflags & IF_MASK);
-    work |= env->interrupt_request & CPU_INTERRUPT_NMI;
-    work |= env->interrupt_request & CPU_INTERRUPT_INIT;
-    work |= env->interrupt_request & CPU_INTERRUPT_SIPI;
-
-    return work;
+    return ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env->eflags & IF_MASK)) ||
+           (env->interrupt_request & (CPU_INTERRUPT_NMI |
+                                      CPU_INTERRUPT_INIT |
+                                      CPU_INTERRUPT_SIPI |
+                                      CPU_INTERRUPT_MCE));
 }
 
 /* load efer and update the corresponding hflags. XXX: do consistency
Signature · 1 line
1.7.4
#4 lore raw

PATCH 4/35 x86: Perform implicit mcg_status reset

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Reorder mcg_status in CPUState to achieve automatic clearing on reset.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/cpu.h    |    3 ++-
 target-i386/helper.c |    2 --
 2 files changed, 2 insertions(+), 3 deletions(-)
target-i386/cpu.h +2 -1
index 5f1df8b..75156e7 100644
@@ -687,6 +687,8 @@ typedef struct CPUX86State {
 
     uint64_t pat;
 
+    uint64_t mcg_status;
+
     /* exception/interrupt handling */
     int error_code;
     int exception_is_int;
@@ -741,7 +743,6 @@ typedef struct CPUX86State {
     struct DeviceState *apic_state;
 
     uint64_t mcg_cap;
-    uint64_t mcg_status;
     uint64_t mcg_ctl;
     uint64_t mce_banks[MCE_BANKS_DEF*4];
 
target-i386/helper.c +0 -2
index f0c546d..f41416f 100644
@@ -101,8 +101,6 @@ void cpu_reset(CPUX86State *env)
     env->dr[7] = DR7_FIXED_1;
     cpu_breakpoint_remove_all(env, BP_CPU);
     cpu_watchpoint_remove_all(env, BP_CPU);
-
-    env->mcg_status = 0;
 }
 
 void cpu_x86_close(CPUX86State *env)
Signature · 1 line
1.7.4
#5 lore raw

PATCH 5/35 x86: Small cleanups of MCE helpers

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Fix some code style issues, use proper headers, and align to cpu_x86 naming scheme. No functional changes.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 cpu-all.h            |    4 ----
 monitor.c            |    2 +-
 target-i386/cpu.h    |    5 +++++
 target-i386/helper.c |   41 ++++++++++++++++++++++++-----------------
 4 files changed, 30 insertions(+), 22 deletions(-)
cpu-all.h +0 -4
index 87b0f86..caf5e6c 100644
@@ -971,8 +971,4 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf);
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
-void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int broadcast);
-
 #endif /* CPU_ALL_H */
monitor.c +1 -1
index 22ae3bb..45b0cc2 100644
@@ -2713,7 +2713,7 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
 
     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
         if (cenv->cpu_index == cpu_index && cenv->mcg_cap) {
-            cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc,
+            cpu_x86_inject_mce(cenv, bank, status, mcg_status, addr, misc,
                                broadcast);
             break;
         }
target-i386/cpu.h +5 -0
index 75156e7..52bb48e 100644
@@ -986,4 +986,9 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 
 void do_cpu_init(CPUState *env);
 void do_cpu_sipi(CPUState *env);
+
+void cpu_x86_inject_mce(CPUState *cenv, int bank, uint64_t status,
+                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
+                        int broadcast);
+
 #endif /* CPU_I386_H */
target-i386/helper.c +24 -17

95 lines not on this page · raw message

Signature · 1 line
1.7.4
#6 lore raw

PATCH 6/35 x86: Refine error reporting of MCE injection services

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

As this service is used by the human monitor, make sure that errors get reported to the right channel, and also raise the verbosity.

This requires to move Monitor typedef in qemu-common.h to resolve the include dependency.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 monitor.c            |    4 +-
 qemu-common.h        |    6 ++--
 target-i386/cpu.h    |    6 ++--
 target-i386/helper.c |   79 +++++++++++++++++++++++++++++---------------------
 4 files changed, 54 insertions(+), 41 deletions(-)
monitor.c +2 -2
index 45b0cc2..662df7c 100644
@@ -2712,8 +2712,8 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
     int broadcast = qdict_get_try_bool(qdict, "broadcast", 0);
 
     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
-        if (cenv->cpu_index == cpu_index && cenv->mcg_cap) {
-            cpu_x86_inject_mce(cenv, bank, status, mcg_status, addr, misc,
+        if (cenv->cpu_index == cpu_index) {
+            cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
                                broadcast);
             break;
         }
qemu-common.h +3 -3
index 3fe1719..7a96dd1 100644
@@ -18,6 +18,9 @@ typedef struct QEMUFile QEMUFile;
 typedef struct QEMUBH QEMUBH;
 typedef struct DeviceState DeviceState;
 
+struct Monitor;
+typedef struct Monitor Monitor;
+
 /* we put basic includes here to avoid repeating them in device drivers */
 #include <stdlib.h>
 #include <stdio.h>
@@ -327,9 +330,6 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
 void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
                             size_t skip);
 
-struct Monitor;
-typedef struct Monitor Monitor;
-
 /* Convert a byte between binary and BCD.  */
 static inline uint8_t to_bcd(uint8_t val)
 {
target-i386/cpu.h +3 -3
index 52bb48e..486af1d 100644
@@ -987,8 +987,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 void do_cpu_init(CPUState *env);
 void do_cpu_sipi(CPUState *env);
 
-void cpu_x86_inject_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int broadcast);
+void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
+                        uint64_t status, uint64_t mcg_status, uint64_t addr,
+                        uint64_t misc, int broadcast);
 
 #endif /* CPU_I386_H */
target-i386/helper.c +46 -33

121 lines not on this page · raw message

Signature · 1 line
1.7.4
#7 lore raw

PATCH 7/35 x86: Optionally avoid injecting AO MCEs while others are pending

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Allow to tell cpu_x86_inject_mce that it should ignore Action Optional MCE events when the target VCPU is still processing another one. This will be used by KVM soon.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 monitor.c            |    7 +++++--
 target-i386/cpu.h    |    5 ++++-
 target-i386/helper.c |   26 +++++++++++++++++++-------
 3 files changed, 28 insertions(+), 10 deletions(-)
monitor.c +5 -2
index 662df7c..ae20927 100644
@@ -2709,12 +2709,15 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
     uint64_t mcg_status = qdict_get_int(qdict, "mcg_status");
     uint64_t addr = qdict_get_int(qdict, "addr");
     uint64_t misc = qdict_get_int(qdict, "misc");
-    int broadcast = qdict_get_try_bool(qdict, "broadcast", 0);
+    int flags = MCE_INJECT_UNCOND_AO;
 
+    if (qdict_get_try_bool(qdict, "broadcast", 0)) {
+        flags |= MCE_INJECT_BROADCAST;
+    }
     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
         if (cenv->cpu_index == cpu_index) {
             cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
-                               broadcast);
+                               flags);
             break;
         }
     }
target-i386/cpu.h +4 -1
index 486af1d..d0eae75 100644
@@ -987,8 +987,11 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
 void do_cpu_init(CPUState *env);
 void do_cpu_sipi(CPUState *env);
 
+#define MCE_INJECT_BROADCAST    1
+#define MCE_INJECT_UNCOND_AO    2
+
 void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
                         uint64_t status, uint64_t mcg_status, uint64_t addr,
-                        uint64_t misc, int broadcast);
+                        uint64_t misc, int flags);
 
 #endif /* CPU_I386_H */
target-i386/helper.c +19 -7
index 462d332..e3ef40c 100644
@@ -1069,11 +1069,20 @@ static void breakpoint_handler(CPUState *env)
 
 static void
 qemu_inject_x86_mce(Monitor *mon, 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 flags)
 {
     uint64_t mcg_cap = cenv->mcg_cap;
     uint64_t *banks = cenv->mce_banks + 4 * bank;
 
+    /*
+     * If there is an MCE exception being processed, ignore this SRAO MCE
+     * unless unconditional injection was requested.
+     */
+    if (!(flags & MCE_INJECT_UNCOND_AO) && !(status & MCI_STATUS_AR)
+        && (cenv->mcg_status & MCG_STATUS_MCIP)) {
+        return;
+    }
     if (status & MCI_STATUS_UC) {
         /*
          * if MSR_MCG_CTL is not all 1s, the uncorrected error
@@ -1127,7 +1136,7 @@ qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,
 
 void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
                         uint64_t status, uint64_t mcg_status, uint64_t addr,
-                        uint64_t misc, int broadcast)
+                        uint64_t misc, int flags)
 {
     unsigned bank_num = cenv->mcg_cap & 0xff;
     CPUState *env;
@@ -1145,27 +1154,30 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
         monitor_printf(mon, "Invalid MCE status code\n");
         return;
     }
-    if (broadcast && !cpu_x86_support_mca_broadcast(cenv)) {
+    if ((flags & MCE_INJECT_BROADCAST)
+        && !cpu_x86_support_mca_broadcast(cenv)) {
         monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
         return;
     }
 
     if (kvm_enabled()) {
-        if (broadcast) {
+        if (flags & MCE_INJECT_BROADCAST) {
             flag |= MCE_BROADCAST;
         }
 
         kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
     } else {
-        qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc);
-        if (broadcast) {
+        qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc,
+                            flags);
+        if (flags & MCE_INJECT_BROADCAST) {
             for (env = first_cpu; env != NULL; env = env->next_cpu) {
                 if (cenv == env) {
                     continue;
                 }
                 qemu_inject_x86_mce(mon, env, 1,
                                     MCI_STATUS_VAL | MCI_STATUS_UC,
-                                    MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0);
+                                    MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0,
+                                    flags);
             }
         }
     }
Signature · 1 line
1.7.4
#8 lore raw

PATCH 8/35 Synchronize VCPU states before reset

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

This is required to support keeping VCPU states across a system reset. If we do not read the current state before the reset, cpu_synchronize_all_post_reset may write back incorrect state information.

The first user of this will be MCE MSR synchronization which currently works around the missing cpu_synchronize_all_states.

---
 vl.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
vl.c +1 -0
index 5e007a7..f4c24d3 100644
@@ -1450,6 +1450,7 @@ static void main_loop(void)
         }
         if (qemu_reset_requested()) {
             pause_all_vcpus();
+            cpu_synchronize_all_states();
             qemu_system_reset();
             resume_all_vcpus();
         }
Signature · 1 line
1.7.4
#9 lore raw

PATCH 9/35 kvm: x86: Move MCE functions together

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Pure function suffling to avoid multiple #ifdef KVM_CAP_MCE sections, no functional changes. While at it, annotate some #ifdef sections.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/kvm.c |  346 ++++++++++++++++++++++++++---------------------------
 1 files changed, 171 insertions(+), 175 deletions(-)
target-i386/kvm.c +171 -175
index 1f12cbf..aba2cc9 100644
@@ -172,7 +172,7 @@ static int get_para_features(CPUState *env)
 #endif
     return features;
 }
-#endif
+#endif /* CONFIG_KVM_PARA */
 
 #ifdef KVM_CAP_MCE
 static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
@@ -273,8 +273,174 @@ static void kvm_inject_x86_mce_on(CPUState *env, struct kvm_x86_mce *mce,
     run_on_cpu(env, kvm_do_inject_x86_mce, &data);
 }
 
-static void kvm_mce_broadcast_rest(CPUState *env);
-#endif
+static void kvm_mce_broadcast_rest(CPUState *env)
+{
+    struct kvm_x86_mce mce = {
+        .bank = 1,
+        .status = MCI_STATUS_VAL | MCI_STATUS_UC,
+        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
+        .addr = 0,
+        .misc = 0,
+    };
+    CPUState *cenv;
+
+    /* Broadcast MCA signal for processor version 06H_EH and above */
+    if (cpu_x86_support_mca_broadcast(env)) {
+        for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+            if (cenv == env) {
+                continue;
+            }
+            kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR);
+        }
+    }
+}
+
+static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr)
+{
+    struct kvm_x86_mce mce = {
+        .bank = 9,
+        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                  | MCI_STATUS_AR | 0x134,
+        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV,
+        .addr = paddr,
+        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
+    };
+    int r;
+
+    r = kvm_set_mce(env, &mce);
+    if (r < 0) {
+        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
+        abort();
+    }
+    kvm_mce_broadcast_rest(env);
+}
+
+static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr)
+{
+    struct kvm_x86_mce mce = {
+        .bank = 9,
+        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                  | 0xc0,
+        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
+        .addr = paddr,
+        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
+    };
+    int r;
+
+    r = kvm_set_mce(env, &mce);
+    if (r < 0) {
+        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
+        abort();
+    }
+    kvm_mce_broadcast_rest(env);
+}
+
+static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr)
+{
+    struct kvm_x86_mce mce = {
+        .bank = 9,
+        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
+                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
+                  | 0xc0,
+        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
+        .addr = paddr,
+        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
+    };
+
+    kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR);
+    kvm_mce_broadcast_rest(env);
+}
+#endif /* KVM_CAP_MCE */
+
+static void hardware_memory_error(void)
+{
+    fprintf(stderr, "Hardware memory error!\n");
+    exit(1);
+}
+
+int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
+{
+#ifdef KVM_CAP_MCE
+    void *vaddr;
+    ram_addr_t ram_addr;
+    target_phys_addr_t paddr;
+
+    if ((env->mcg_cap & MCG_SER_P) && addr
+        && (code == BUS_MCEERR_AR
+            || code == BUS_MCEERR_AO)) {
+        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");
+            /* Hope we are lucky for AO MCE */
+            if (code == BUS_MCEERR_AO) {
+                return 0;
+            } else {
+                hardware_memory_error();
+            }
+        }
+
+        if (code == BUS_MCEERR_AR) {
+            /* Fake an Intel architectural Data Load SRAR UCR */
+            kvm_mce_inj_srar_dataload(env, paddr);
+        } else {
+            /*
+             * If there is an MCE excpetion being processed, ignore
+             * this SRAO MCE
+             */
+            if (!kvm_mce_in_progress(env)) {
+                /* Fake an Intel architectural Memory scrubbing UCR */
+                kvm_mce_inj_srao_memscrub(env, paddr);
+            }
+        }
+    } else
+#endif /* KVM_CAP_MCE */
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+int kvm_arch_on_sigbus(int code, void *addr)
+{
+#ifdef KVM_CAP_MCE
+    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
+        void *vaddr;
+        ram_addr_t ram_addr;
+        target_phys_addr_t paddr;
+
+        /* 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);
+            return 0;
+        }
+        kvm_mce_inj_srao_memscrub2(first_cpu, paddr);
+    } else
+#endif /* KVM_CAP_MCE */
+    {
+        if (code == BUS_MCEERR_AO) {
+            return 0;
+        } else if (code == BUS_MCEERR_AR) {
+            hardware_memory_error();
+        } else {
+            return 1;
+        }
+    }
+    return 0;
+}
 
 void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
                         uint64_t mcg_status, uint64_t addr, uint64_t misc,
@@ -294,11 +460,11 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
     }
 
     kvm_inject_x86_mce_on(cenv, &mce, flag);
-#else
+#else /* !KVM_CAP_MCE*/
     if (flag & ABORT_ON_ERROR) {
         abort();
     }
-#endif
+#endif /* !KVM_CAP_MCE*/
 }
 
 static void cpu_update_state(void *opaque, int running, int reason)
@@ -1783,173 +1949,3 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
     return !(env->cr[0] & CR0_PE_MASK) ||
            ((env->segs[R_CS].selector  & 3) != 3);
 }
-
-static void hardware_memory_error(void)
-{
-    fprintf(stderr, "Hardware memory error!\n");
-    exit(1);
-}
-
-#ifdef KVM_CAP_MCE
-static void kvm_mce_broadcast_rest(CPUState *env)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 1,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = 0,
-        .misc = 0,
-    };
-    CPUState *cenv;
-
-    /* Broadcast MCA signal for processor version 06H_EH and above */
-    if (cpu_x86_support_mca_broadcast(env)) {
-        for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
-            if (cenv == env) {
-                continue;
-            }
-            kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR);
-        }
-    }
-}
-
-static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | MCI_STATUS_AR | 0x134,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
-    int r;
-
-    r = kvm_set_mce(env, &mce);
-    if (r < 0) {
-        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
-        abort();
-    }
-    kvm_mce_broadcast_rest(env);
-}
-
-static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | 0xc0,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
-    int r;
-
-    r = kvm_set_mce(env, &mce);
-    if (r < 0) {
-        fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno));
-        abort();
-    }
-    kvm_mce_broadcast_rest(env);
-}
-
-static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr)
-{
-    struct kvm_x86_mce mce = {
-        .bank = 9,
-        .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN
-                  | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S
-                  | 0xc0,
-        .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV,
-        .addr = paddr,
-        .misc = (MCM_ADDR_PHYS << 6) | 0xc,
-    };
-
-    kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR);
-    kvm_mce_broadcast_rest(env);
-}
-
-#endif
-
-int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
-{
-#if defined(KVM_CAP_MCE)
-    void *vaddr;
-    ram_addr_t ram_addr;
-    target_phys_addr_t paddr;
-
-    if ((env->mcg_cap & MCG_SER_P) && addr
-        && (code == BUS_MCEERR_AR
-            || code == BUS_MCEERR_AO)) {
-        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");
-            /* Hope we are lucky for AO MCE */
-            if (code == BUS_MCEERR_AO) {
-                return 0;
-            } else {
-                hardware_memory_error();
-            }
-        }
-
-        if (code == BUS_MCEERR_AR) {
-            /* Fake an Intel architectural Data Load SRAR UCR */
-            kvm_mce_inj_srar_dataload(env, paddr);
-        } else {
-            /*
-             * If there is an MCE excpetion being processed, ignore
-             * this SRAO MCE
-             */
-            if (!kvm_mce_in_progress(env)) {
-                /* Fake an Intel architectural Memory scrubbing UCR */
-                kvm_mce_inj_srao_memscrub(env, paddr);
-            }
-        }
-    } else
-#endif
-    {
-        if (code == BUS_MCEERR_AO) {
-            return 0;
-        } else if (code == BUS_MCEERR_AR) {
-            hardware_memory_error();
-        } else {
-            return 1;
-        }
-    }
-    return 0;
-}
-
-int kvm_arch_on_sigbus(int code, void *addr)
-{
-#if defined(KVM_CAP_MCE)
-    if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) {
-        void *vaddr;
-        ram_addr_t ram_addr;
-        target_phys_addr_t paddr;
-
-        /* 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);
-            return 0;
-        }
-        kvm_mce_inj_srao_memscrub2(first_cpu, paddr);
-    } else
-#endif
-    {
-        if (code == BUS_MCEERR_AO) {
-            return 0;
-        } else if (code == BUS_MCEERR_AR) {
-            hardware_memory_error();
-        } else {
-            return 1;
-        }
-    }
-    return 0;
-}
Signature · 1 line
1.7.4
#10 lore raw

PATCH 10/35 kvm: Rename kvm_arch_process_irqchip_events to async_events

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

We will broaden the scope of this function on x86 beyond irqchip events.

---
 kvm-all.c          |    2 +-
 kvm.h              |    2 +-
 target-i386/kvm.c  |    2 +-
 target-ppc/kvm.c   |    2 +-
 target-s390x/kvm.c |    2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)
kvm-all.c +1 -1
index 7753c8a..226843c 100644
@@ -893,7 +893,7 @@ int kvm_cpu_exec(CPUState *env)
 
     DPRINTF("kvm_cpu_exec()\n");
 
-    if (kvm_arch_process_irqchip_events(env)) {
+    if (kvm_arch_process_async_events(env)) {
         env->exit_request = 0;
         return EXCP_HLT;
     }
kvm.h +1 -1
index 59b2c29..7bc04e0 100644
@@ -102,7 +102,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run);
 
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
 
-int kvm_arch_process_irqchip_events(CPUState *env);
+int kvm_arch_process_async_events(CPUState *env);
 
 int kvm_arch_get_registers(CPUState *env);
 
target-i386/kvm.c +1 -1
index aba2cc9..0aef810 100644
@@ -1675,7 +1675,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
     cpu_set_apic_base(env->apic_state, run->apic_base);
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
     if (kvm_irqchip_in_kernel()) {
         return 0;
target-ppc/kvm.c +1 -1
index 3924f4b..6c99a16 100644
@@ -259,7 +259,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
     return 0;
 }
target-s390x/kvm.c +1 -1
index 6e94274..a85ae0f 100644
@@ -177,7 +177,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 {
 }
 
-int kvm_arch_process_irqchip_events(CPUState *env)
+int kvm_arch_process_async_events(CPUState *env)
 {
     return 0;
 }
Signature · 1 line
1.7.4
#11 lore raw

PATCH 11/35 kvm: x86: Inject pending MCE events on state writeback

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

The current way of injecting MCE events without updating of and synchronizing with the CPUState is broken and causes spurious corruptions of the MCE-related parts of the CPUState.

As a first step towards a fix, enhance the state writeback code with support for injecting events that are pending in the CPUState. A pending exception will then be signaled via cpu_interrupt(CPU_INTERRUPT_MCE). And, just like for TCG, we need to leave the halt state when CPU_INTERRUPT_MCE is pending (left broken for the to-be-removed old KVM code).

This will also allow to unify TCG and KVM injection code.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/kvm.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 60 insertions(+), 0 deletions(-)
target-i386/kvm.c +60 -0
index 0aef810..d9a6fc5 100644
@@ -467,6 +467,38 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
 #endif /* !KVM_CAP_MCE*/
 }
 
+static int kvm_inject_mce_oldstyle(CPUState *env)
+{
+#ifdef KVM_CAP_MCE
+    if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) {
+        unsigned int bank, bank_num = env->mcg_cap & 0xff;
+        struct kvm_x86_mce mce;
+
+        env->exception_injected = -1;
+
+        /*
+         * There must be at least one bank in use if an MCE is pending.
+         * Find it and use its values for the event injection.
+         */
+        for (bank = 0; bank < bank_num; bank++) {
+            if (env->mce_banks[bank * 4 + 1] & MCI_STATUS_VAL) {
+                break;
+            }
+        }
+        assert(bank < bank_num);
+
+        mce.bank = bank;
+        mce.status = env->mce_banks[bank * 4 + 1];
+        mce.mcg_status = env->mcg_status;
+        mce.addr = env->mce_banks[bank * 4 + 2];
+        mce.misc = env->mce_banks[bank * 4 + 3];
+
+        return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce);
+    }
+#endif /* KVM_CAP_MCE */
+    return 0;
+}
+
 static void cpu_update_state(void *opaque, int running, int reason)
 {
     CPUState *env = opaque;
@@ -1539,6 +1571,11 @@ int kvm_arch_put_registers(CPUState *env, int level)
     if (ret < 0) {
         return ret;
     }
+    /* must be before kvm_put_msrs */
+    ret = kvm_inject_mce_oldstyle(env);
+    if (ret < 0) {
+        return ret;
+    }
     ret = kvm_put_msrs(env, level);
     if (ret < 0) {
         return ret;
@@ -1677,6 +1714,29 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
 
 int kvm_arch_process_async_events(CPUState *env)
 {
+    if (env->interrupt_request & CPU_INTERRUPT_MCE) {
+        /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */
+        assert(env->mcg_cap);
+
+        env->interrupt_request &= ~CPU_INTERRUPT_MCE;
+
+        kvm_cpu_synchronize_state(env);
+
+        if (env->exception_injected == EXCP08_DBLE) {
+            /* this means triple fault */
+            qemu_system_reset_request();
+            env->exit_request = 1;
+            return 0;
+        }
+        env->exception_injected = EXCP12_MCHK;
+        env->has_error_code = 0;
+
+        env->halted = 0;
+        if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) {
+            env->mp_state = KVM_MP_STATE_RUNNABLE;
+        }
+    }
+
     if (kvm_irqchip_in_kernel()) {
         return 0;
     }
Signature · 1 line
1.7.4
#12 lore raw

PATCH 12/35 x86: Run qemu_inject_x86_mce on target VCPU

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

We will use the current TCG-only MCE injection path for KVM as well, and then this read-modify-write of the target VCPU state has to be performed synchronously in the corresponding thread.

---
 target-i386/helper.c |   87 +++++++++++++++++++++++++++++++++----------------
 1 files changed, 58 insertions(+), 29 deletions(-)
target-i386/helper.c +58 -29
index e3ef40c..a32960c 100644
@@ -1067,29 +1067,42 @@ static void breakpoint_handler(CPUState *env)
         prev_debug_excp_handler(env);
 }
 
-static void
-qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,
-                    uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                    int flags)
+typedef struct MCEInjectionParams {
+    Monitor *mon;
+    CPUState *env;
+    int bank;
+    uint64_t status;
+    uint64_t mcg_status;
+    uint64_t addr;
+    uint64_t misc;
+    int flags;
+} MCEInjectionParams;
+
+static void do_inject_x86_mce(void *data)
 {
-    uint64_t mcg_cap = cenv->mcg_cap;
-    uint64_t *banks = cenv->mce_banks + 4 * bank;
+    MCEInjectionParams *params = data;
+    CPUState *cenv = params->env;
+    uint64_t *banks = cenv->mce_banks + 4 * params->bank;
+
+    cpu_synchronize_state(cenv);
 
     /*
      * If there is an MCE exception being processed, ignore this SRAO MCE
      * unless unconditional injection was requested.
      */
-    if (!(flags & MCE_INJECT_UNCOND_AO) && !(status & MCI_STATUS_AR)
+    if (!(params->flags & MCE_INJECT_UNCOND_AO)
+        && !(params->status & MCI_STATUS_AR)
         && (cenv->mcg_status & MCG_STATUS_MCIP)) {
         return;
     }
-    if (status & MCI_STATUS_UC) {
+
+    if (params->status & MCI_STATUS_UC) {
         /*
          * if MSR_MCG_CTL is not all 1s, the uncorrected error
          * reporting is disabled
          */
-        if ((mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
-            monitor_printf(mon,
+        if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
+            monitor_printf(params->mon,
                            "CPU %d: Uncorrected error reporting disabled\n",
                            cenv->cpu_index);
             return;
@@ -1100,35 +1113,39 @@ qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,
          * reporting is disabled for the bank
          */
         if (banks[0] != ~(uint64_t)0) {
-            monitor_printf(mon, "CPU %d: Uncorrected error reporting disabled "
-                           "for bank %d\n", cenv->cpu_index, bank);
+            monitor_printf(params->mon,
+                           "CPU %d: Uncorrected error reporting disabled for"
+                           " bank %d\n",
+                           cenv->cpu_index, params->bank);
             return;
         }
 
         if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
             !(cenv->cr[4] & CR4_MCE_MASK)) {
-            monitor_printf(mon, "CPU %d: Previous MCE still in progress, "
-                                "raising triple fault\n", cenv->cpu_index);
+            monitor_printf(params->mon,
+                           "CPU %d: Previous MCE still in progress, raising"
+                           " triple fault\n",
+                           cenv->cpu_index);
             qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
             qemu_system_reset_request();
             return;
         }
         if (banks[1] & MCI_STATUS_VAL) {
-            status |= MCI_STATUS_OVER;
+            params->status |= MCI_STATUS_OVER;
         }
-        banks[2] = addr;
-        banks[3] = misc;
-        cenv->mcg_status = mcg_status;
-        banks[1] = status;
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        cenv->mcg_status = params->mcg_status;
+        banks[1] = params->status;
         cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
     } else if (!(banks[1] & MCI_STATUS_VAL)
                || !(banks[1] & MCI_STATUS_UC)) {
         if (banks[1] & MCI_STATUS_VAL) {
-            status |= MCI_STATUS_OVER;
+            params->status |= MCI_STATUS_OVER;
         }
-        banks[2] = addr;
-        banks[3] = misc;
-        banks[1] = status;
+        banks[2] = params->addr;
+        banks[3] = params->misc;
+        banks[1] = params->status;
     } else {
         banks[1] |= MCI_STATUS_OVER;
     }
@@ -1138,6 +1155,16 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
                         uint64_t status, uint64_t mcg_status, uint64_t addr,
                         uint64_t misc, int flags)
 {
+    MCEInjectionParams params = {
+        .mon = mon,
+        .env = cenv,
+        .bank = bank,
+        .status = status,
+        .mcg_status = mcg_status,
+        .addr = addr,
+        .misc = misc,
+        .flags = flags,
+    };
     unsigned bank_num = cenv->mcg_cap & 0xff;
     CPUState *env;
     int flag = 0;
@@ -1167,17 +1194,19 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
 
         kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
     } else {
-        qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc,
-                            flags);
+        run_on_cpu(cenv, do_inject_x86_mce, &params);
         if (flags & MCE_INJECT_BROADCAST) {
+            params.bank = 1;
+            params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
+            params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+            params.addr = 0;
+            params.misc = 0;
             for (env = first_cpu; env != NULL; env = env->next_cpu) {
                 if (cenv == env) {
                     continue;
                 }
-                qemu_inject_x86_mce(mon, env, 1,
-                                    MCI_STATUS_VAL | MCI_STATUS_UC,
-                                    MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0,
-                                    flags);
+                params.env = env;
+                run_on_cpu(cenv, do_inject_x86_mce, &params);
             }
         }
     }
Signature · 1 line
1.7.4
#13 lore raw

PATCH 13/35 kvm: x86: Consolidate TCG and KVM MCE injection code

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

This switches KVM's MCE injection path to cpu_x86_inject_mce, both for SIGBUS and monitor initiated events. This means we prepare the MCA MSRs in the VCPUState also for KVM.

We have to drop the MSRs writeback restrictions for this purpose which is now safe as every uncoordinated MSR injection is removed with this patch.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/helper.c  |   34 +++-----
 target-i386/kvm.c     |  238 +++++-------------------------------------------
 target-i386/kvm_x86.h |   25 -----
 3 files changed, 37 insertions(+), 260 deletions(-)
 delete mode 100644 target-i386/kvm_x86.h
target-i386/helper.c +12 -22
index a32960c..a08309f 100644
@@ -27,7 +27,6 @@
 #include "exec-all.h"
 #include "qemu-common.h"
 #include "kvm.h"
-#include "kvm_x86.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu.h"
 #include "monitor.h"
@@ -1167,7 +1166,6 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
     };
     unsigned bank_num = cenv->mcg_cap & 0xff;
     CPUState *env;
-    int flag = 0;
 
     if (!cenv->mcg_cap) {
         monitor_printf(mon, "MCE injection not supported\n");
@@ -1187,27 +1185,19 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
         return;
     }
 
-    if (kvm_enabled()) {
-        if (flags & MCE_INJECT_BROADCAST) {
-            flag |= MCE_BROADCAST;
-        }
-
-        kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
-    } else {
-        run_on_cpu(cenv, do_inject_x86_mce, &params);
-        if (flags & MCE_INJECT_BROADCAST) {
-            params.bank = 1;
-            params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
-            params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
-            params.addr = 0;
-            params.misc = 0;
-            for (env = first_cpu; env != NULL; env = env->next_cpu) {
-                if (cenv == env) {
-                    continue;
-                }
-                params.env = env;
-                run_on_cpu(cenv, do_inject_x86_mce, &params);
+    run_on_cpu(cenv, do_inject_x86_mce, &params);
+    if (flags & MCE_INJECT_BROADCAST) {
+        params.bank = 1;
+        params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
+        params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+        params.addr = 0;
+        params.misc = 0;
+        for (env = first_cpu; env != NULL; env = env->next_cpu) {
+            if (cenv == env) {
+                continue;
             }
+            params.env = env;
+            run_on_cpu(cenv, do_inject_x86_mce, &params);
         }
     }
 }
target-i386/kvm.c +25 -213

297 lines not on this page · raw message

target-i386/kvm_x86.h deleted +0 -25
deleted file mode 100644
index 9d7b584..0000000
@@ -1,25 +0,0 @@
-/*
- * 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__
-
-#define ABORT_ON_ERROR  0x01
-#define MCE_BROADCAST   0x02
-
-void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
-                        uint64_t mcg_status, uint64_t addr, uint64_t misc,
-                        int flag);
-
-#endif
Signature · 1 line
1.7.4
#14 lore raw

PATCH 14/35 kvm: x86: Clean up kvm_setup_mce

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

There is nothing to abstract here. Fold kvm_setup_mce into its caller and fix up the error reporting (return code of kvm_vcpu_ioctl holds the error value).

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/kvm.c |   11 ++++-------
 1 files changed, 4 insertions(+), 7 deletions(-)
target-i386/kvm.c +4 -7
index 4974fa4..9d71b20 100644
@@ -187,11 +187,6 @@ static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *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 void kvm_mce_inject(CPUState *env, target_phys_addr_t paddr, int code)
 {
     uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
@@ -440,6 +435,7 @@ int kvm_arch_init_vcpu(CPUState *env)
         && kvm_check_extension(env->kvm_state, KVM_CAP_MCE) > 0) {
         uint64_t mcg_cap;
         int banks;
+        int ret;
 
         if (kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks)) {
             perror("kvm_get_mce_cap_supported FAILED");
@@ -448,8 +444,9 @@ int kvm_arch_init_vcpu(CPUState *env)
                 banks = MCE_BANKS_DEF;
             mcg_cap &= MCE_CAP_DEF;
             mcg_cap |= banks;
-            if (kvm_setup_mce(env, &mcg_cap)) {
-                perror("kvm_setup_mce FAILED");
+            ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap);
+            if (ret < 0) {
+                fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
             } else {
                 env->mcg_cap = mcg_cap;
             }
Signature · 1 line
1.7.4
#15 lore raw

PATCH 15/35 kvm: x86: Fail kvm_arch_init_vcpu if MCE initialization fails

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

There is no reason to continue if the kernel claims to support MCE but then fails to process our request.

CC Huang Ying <[email protected]>
CC Hidetoshi Seto <[email protected]>
CC Jin Dongming <[email protected]>
---
 target-i386/kvm.c |   30 +++++++++++++++++-------------
 1 files changed, 17 insertions(+), 13 deletions(-)
target-i386/kvm.c +17 -13
index 9d71b20..1574186 100644
@@ -437,20 +437,24 @@ int kvm_arch_init_vcpu(CPUState *env)
         int banks;
         int ret;
 
-        if (kvm_get_mce_cap_supported(env->kvm_state, &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;
-            ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap);
-            if (ret < 0) {
-                fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
-            } else {
-                env->mcg_cap = mcg_cap;
-            }
+        ret = kvm_get_mce_cap_supported(env->kvm_state, &mcg_cap, &banks);
+        if (ret < 0) {
+            fprintf(stderr, "kvm_get_mce_cap_supported: %s", strerror(-ret));
+            return ret;
         }
+
+        if (banks > MCE_BANKS_DEF) {
+            banks = MCE_BANKS_DEF;
+        }
+        mcg_cap &= MCE_CAP_DEF;
+        mcg_cap |= banks;
+        ret = kvm_vcpu_ioctl(env, KVM_X86_SETUP_MCE, &mcg_cap);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
+            return ret;
+        }
+
+        env->mcg_cap = mcg_cap;
     }
 #endif
 
Signature · 1 line
1.7.4
#16 lore raw

PATCH 16/35 Add qemu_ram_remap

In reply to Marcelo Tosatti

From: Huang Ying <[email protected]>

qemu_ram_remap() unmaps the specified RAM pages, then re-maps these pages again. This is used by KVM HWPoison support to clear HWPoisoned page tables across guest rebooting, so that a new page may be allocated later to recover the memory error.

[ Jan: style fixlets, WIN32 fix ]

---
 cpu-all.h    |    4 +++
 cpu-common.h |    1 +
 exec.c       |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 67 insertions(+), 1 deletions(-)
cpu-all.h +4 -0
index caf5e6c..4f4631d 100644
@@ -863,10 +863,14 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
 extern int phys_ram_fd;
 extern ram_addr_t ram_size;
 
+/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */
+#define RAM_PREALLOC_MASK   (1 << 0)
+
 typedef struct RAMBlock {
     uint8_t *host;
     ram_addr_t offset;
     ram_addr_t length;
+    uint32_t flags;
     char idstr[256];
     QLIST_ENTRY(RAMBlock) next;
 #if defined(__linux__) && !defined(TARGET_S390X)
cpu-common.h +1 -0
index 54d21d4..ef4e8da 100644
@@ -50,6 +50,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
                         ram_addr_t size, void *host);
 ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
 void qemu_ram_free(ram_addr_t addr);
+void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
 /* This should only be used for ram local to a device.  */
 void *qemu_get_ram_ptr(ram_addr_t addr);
 /* Same but slower, to use for migration, where the order of
exec.c +62 -1

81 lines not on this page · raw message

Signature · 1 line
1.7.4
#17 lore raw

PATCH 17/35 KVM, MCE, unpoison memory address across reboot

In reply to Marcelo Tosatti

From: Huang Ying <[email protected]>

In Linux kernel HWPoison processing implementation, the virtual address in processes mapping the error physical memory page is marked as HWPoison. So that, the further accessing to the virtual address will kill corresponding processes with SIGBUS.

If the error physical memory page is used by a KVM guest, the SIGBUS will be sent to QEMU, and QEMU will simulate a MCE to report that memory error to the guest OS. If the guest OS can not recover from the error (for example, the page is accessed by kernel code), guest OS will reboot the system. But because the underlying host virtual address backing the guest physical memory is still poisoned, if the guest system accesses the corresponding guest physical memory even after rebooting, the SIGBUS will still be sent to QEMU and MCE will be simulated. That is, guest system can not recover via rebooting.

In fact, across rebooting, the contents of guest physical memory page need not to be kept. We can allocate a new host physical page to back the corresponding guest physical address.

This patch fixes this issue in QEMU-KVM via calling qemu_ram_remap() to clear the corresponding page table entry, so that make it possible to allocate a new page to recover the issue.

[ Jan: rebasing and tiny cleanups]

---
 target-i386/kvm.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)
target-i386/kvm.c +36 -0
index 1574186..f7995bd 100644
@@ -173,7 +173,40 @@ static int get_para_features(CPUState *env)
 }
 #endif /* CONFIG_KVM_PARA */
 
+typedef struct HWPoisonPage {
+    ram_addr_t ram_addr;
+    QLIST_ENTRY(HWPoisonPage) list;
+} HWPoisonPage;
+
+static QLIST_HEAD(, HWPoisonPage) hwpoison_page_list =
+    QLIST_HEAD_INITIALIZER(hwpoison_page_list);
+
+static void kvm_unpoison_all(void *param)
+{
+    HWPoisonPage *page, *next_page;
+
+    QLIST_FOREACH_SAFE(page, &hwpoison_page_list, list, next_page) {
+        QLIST_REMOVE(page, list);
+        qemu_ram_remap(page->ram_addr, TARGET_PAGE_SIZE);
+        qemu_free(page);
+    }
+}
+
 #ifdef KVM_CAP_MCE
+static void kvm_hwpoison_page_add(ram_addr_t ram_addr)
+{
+    HWPoisonPage *page;
+
+    QLIST_FOREACH(page, &hwpoison_page_list, list) {
+        if (page->ram_addr == ram_addr) {
+            return;
+        }
+    }
+    page = qemu_malloc(sizeof(HWPoisonPage));
+    page->ram_addr = ram_addr;
+    QLIST_INSERT_HEAD(&hwpoison_page_list, page, list);
+}
+
 static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
                                      int *max_banks)
 {
@@ -233,6 +266,7 @@ int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr)
                 hardware_memory_error();
             }
         }
+        kvm_hwpoison_page_add(ram_addr);
         kvm_mce_inject(env, paddr, code);
     } else
 #endif /* KVM_CAP_MCE */
@@ -263,6 +297,7 @@ int kvm_arch_on_sigbus(int code, void *addr)
                     "QEMU itself instead of guest system!: %p\n", addr);
             return 0;
         }
+        kvm_hwpoison_page_add(ram_addr);
         kvm_mce_inject(first_cpu, paddr, code);
     } else
 #endif /* KVM_CAP_MCE */
@@ -571,6 +606,7 @@ int kvm_arch_init(KVMState *s)
         fprintf(stderr, "e820_add_entry() table is full\n");
         return ret;
     }
+    qemu_register_reset(kvm_unpoison_all, NULL);
 
     return 0;
 }
Signature · 1 line
1.7.4
#18 lore raw

PATCH 18/35 Implement qemu_kvm_eat_signals only for CONFIG_LINUX

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

qemu_kvm_eat_signals requires POSIX support with realtime extensions for sigtimedwait. Not all our target platforms provide this. Moreover, undefined sigbus_reraise was referenced on non-Linux as well.

---
 cpus.c |   94 ++++++++++++++++++++++++++++++++--------------------------------
 1 files changed, 47 insertions(+), 47 deletions(-)
cpus.c +47 -47
index 077729c..26e5bba 100644
@@ -245,11 +245,58 @@ static void qemu_init_sigbus(void)
     prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
 }
 
+static void qemu_kvm_eat_signals(CPUState *env)
+{
+    struct timespec ts = { 0, 0 };
+    siginfo_t siginfo;
+    sigset_t waitset;
+    sigset_t chkset;
+    int r;
+
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+    sigaddset(&waitset, SIGBUS);
+
+    do {
+        r = sigtimedwait(&waitset, &siginfo, &ts);
+        if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
+            perror("sigtimedwait");
+            exit(1);
+        }
+
+        switch (r) {
+        case SIGBUS:
+            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
+                sigbus_reraise();
+            }
+            break;
+        default:
+            break;
+        }
+
+        r = sigpending(&chkset);
+        if (r == -1) {
+            perror("sigpending");
+            exit(1);
+        }
+    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
+
+#ifndef CONFIG_IOTHREAD
+    if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) {
+        qemu_notify_event();
+    }
+#endif
+}
+
 #else /* !CONFIG_LINUX */
 
 static void qemu_init_sigbus(void)
 {
 }
+
+static void qemu_kvm_eat_signals(CPUState *env)
+{
+}
 #endif /* !CONFIG_LINUX */
 
 #ifndef _WIN32
@@ -455,49 +502,6 @@ static void qemu_tcg_init_cpu_signals(void)
 #endif
 }
 
-static void qemu_kvm_eat_signals(CPUState *env)
-{
-    struct timespec ts = { 0, 0 };
-    siginfo_t siginfo;
-    sigset_t waitset;
-    sigset_t chkset;
-    int r;
-
-    sigemptyset(&waitset);
-    sigaddset(&waitset, SIG_IPI);
-    sigaddset(&waitset, SIGBUS);
-
-    do {
-        r = sigtimedwait(&waitset, &siginfo, &ts);
-        if (r == -1 && !(errno == EAGAIN || errno == EINTR)) {
-            perror("sigtimedwait");
-            exit(1);
-        }
-
-        switch (r) {
-        case SIGBUS:
-            if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
-                sigbus_reraise();
-            }
-            break;
-        default:
-            break;
-        }
-
-        r = sigpending(&chkset);
-        if (r == -1) {
-            perror("sigpending");
-            exit(1);
-        }
-    } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS));
-
-#ifndef CONFIG_IOTHREAD
-    if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) {
-        qemu_notify_event();
-    }
-#endif
-}
-
 #else /* _WIN32 */
 
 HANDLE qemu_event_handle;
@@ -526,10 +530,6 @@ static void qemu_event_increment(void)
     }
 }
 
-static void qemu_kvm_eat_signals(CPUState *env)
-{
-}
-
 static int qemu_signal_init(void)
 {
     return 0;
Signature · 1 line
1.7.4
#19 lore raw

PATCH 19/35 x86: Unbreak TCG support for hardware breakpoints

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Commit 83f338f73e broke x86 hardware breakpoint emulation by moving the debug exception handling out of cpu_exec. Fix this by moving all TCG related bits back, only leaving the generic guest debugging parts in cpus.c.

---
 cpu-exec.c |   27 +++++++++++++++++++++++++++
 cpus.c     |   27 +++------------------------
 2 files changed, 30 insertions(+), 24 deletions(-)
cpu-exec.c +27 -0
index 34eaedc..5cc9379 100644
@@ -196,6 +196,30 @@ static inline TranslationBlock *tb_find_fast(void)
     return tb;
 }
 
+static CPUDebugExcpHandler *debug_excp_handler;
+
+CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
+{
+    CPUDebugExcpHandler *old_handler = debug_excp_handler;
+
+    debug_excp_handler = handler;
+    return old_handler;
+}
+
+static void cpu_handle_debug_exception(CPUState *env)
+{
+    CPUWatchpoint *wp;
+
+    if (!env->watchpoint_hit) {
+        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+            wp->flags &= ~BP_WATCHPOINT_HIT;
+        }
+    }
+    if (debug_excp_handler) {
+        debug_excp_handler(env);
+    }
+}
+
 /* main execution loop */
 
 volatile sig_atomic_t exit_request;
@@ -269,6 +293,9 @@ int cpu_exec(CPUState *env1)
                 if (env->exception_index >= EXCP_INTERRUPT) {
                     /* exit request from the cpu execution loop */
                     ret = env->exception_index;
+                    if (ret == EXCP_DEBUG) {
+                        cpu_handle_debug_exception(env);
+                    }
                     break;
                 } else {
 #if defined(CONFIG_USER_ONLY)
cpus.c +3 -24
index 26e5bba..975a6ce 100644
@@ -166,29 +166,8 @@ static bool all_cpu_threads_idle(void)
     return true;
 }
 
-static CPUDebugExcpHandler *debug_excp_handler;
-
-CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
-{
-    CPUDebugExcpHandler *old_handler = debug_excp_handler;
-
-    debug_excp_handler = handler;
-    return old_handler;
-}
-
-static void cpu_handle_debug_exception(CPUState *env)
+static void cpu_handle_guest_debug(CPUState *env)
 {
-    CPUWatchpoint *wp;
-
-    if (!env->watchpoint_hit) {
-        QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
-            wp->flags &= ~BP_WATCHPOINT_HIT;
-        }
-    }
-    if (debug_excp_handler) {
-        debug_excp_handler(env);
-    }
-
     gdb_set_stop_cpu(env);
     qemu_system_debug_request();
 #ifdef CONFIG_IOTHREAD
@@ -818,7 +797,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
         if (cpu_can_run(env)) {
             r = kvm_cpu_exec(env);
             if (r == EXCP_DEBUG) {
-                cpu_handle_debug_exception(env);
+                cpu_handle_guest_debug(env);
             }
         }
         qemu_kvm_wait_io_event(env);
@@ -1110,7 +1089,7 @@ bool cpu_exec_all(void)
                 r = tcg_cpu_exec(env);
             }
             if (r == EXCP_DEBUG) {
-                cpu_handle_debug_exception(env);
+                cpu_handle_guest_debug(env);
                 break;
             }
         } else if (env->stop || env->stopped) {
Signature · 1 line
1.7.4
#20 lore raw

PATCH 20/35 s390: Detect invalid invocations of qemu_ram_free/remap

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

This both detects invalid invocations of qemu_ram_free and qemu_ram_remap when mem_path is non-NULL and fixes a build error on s390 ("'area' may be used uninitialized in this function").

---
 exec.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)
exec.c +4 -0
index 723ace4..c5358c3 100644
@@ -2931,6 +2931,8 @@ void qemu_ram_free(ram_addr_t addr)
                 } else {
                     qemu_vfree(block->host);
                 }
+#else
+                abort();
 #endif
             } else {
 #if defined(TARGET_S390X) && defined(CONFIG_KVM)
@@ -2979,6 +2981,8 @@ void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
                         area = mmap(vaddr, length, PROT_READ | PROT_WRITE,
                                     flags, -1, 0);
                     }
+#else
+                    abort();
 #endif
                 } else {
 #if defined(TARGET_S390X) && defined(CONFIG_KVM)
Signature · 1 line
1.7.4
#21 lore raw

PATCH 21/35 Break up user and system cpu_interrupt implementations

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.

---
 exec.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)
exec.c +10 -4
index c5358c3..12ea582 100644
@@ -1627,6 +1627,7 @@ static void cpu_unlink_tb(CPUState *env)
     spin_unlock(&interrupt_lock);
 }
 
+#ifndef CONFIG_USER_ONLY
 /* mask must never be zero, except for A20 change call */
 void cpu_interrupt(CPUState *env, int mask)
 {
@@ -1635,7 +1636,6 @@ void cpu_interrupt(CPUState *env, int mask)
     old_mask = env->interrupt_request;
     env->interrupt_request |= mask;
 
-#ifndef CONFIG_USER_ONLY
     /*
      * If called from iothread context, wake the target cpu in
      * case its halted.
@@ -1644,21 +1644,27 @@ void cpu_interrupt(CPUState *env, int mask)
         qemu_cpu_kick(env);
         return;
     }
-#endif
 
     if (use_icount) {
         env->icount_decr.u16.high = 0xffff;
-#ifndef CONFIG_USER_ONLY
         if (!can_do_io(env)
             && (mask & ~old_mask) != 0) {
             cpu_abort(env, "Raised interrupt while not in I/O function");
         }
-#endif
     } else {
         cpu_unlink_tb(env);
     }
 }
 
+#else /* CONFIG_USER_ONLY */
+
+void cpu_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request |= mask;
+    cpu_unlink_tb(env);
+}
+#endif /* CONFIG_USER_ONLY */
+
 void cpu_reset_interrupt(CPUState *env, int mask)
 {
     env->interrupt_request &= ~mask;
Signature · 1 line
1.7.4
#22 lore raw

Re: [PATCH 21/35] Break up user and system cpu_interrupt implementations

Quoted 6 lines · Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.

From KVM POV, the value of this patch is not that high as long as we do

not push the callback patches as well.

Jan

Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
#23 lore raw

Re: [PATCH 21/35] Break up user and system cpu_interrupt implementations

Quoted 8 lines · Jan Kiszka
Quoted 6 lines · Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Both have only two lines in common, and we will convert the system service into a callback which is of no use for user mode operation.

From KVM POV, the value of this patch is not that high as long as we do

not push the callback patches as well.

Agreed, patch removed from queue.

#24 lore raw

PATCH 22/35 kvm: Add in-kernel irqchip awareness to cpu_thread_is_idle

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

With in-kernel irqchip support enabled, the vcpu threads sleep in kernel space while halted. Account for this difference in cpu_thread_is_idle.

---
 cpus.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
cpus.c +2 -1
index 975a6ce..d310b7e 100644
@@ -148,7 +148,8 @@ static bool cpu_thread_is_idle(CPUState *env)
     if (env->stopped || !vm_running) {
         return true;
     }
-    if (!env->halted || qemu_cpu_has_work(env)) {
+    if (!env->halted || qemu_cpu_has_work(env) ||
+        (kvm_enabled() && kvm_irqchip_in_kernel())) {
         return false;
     }
     return true;
Signature · 1 line
1.7.4
#25 lore raw

PATCH 23/35 kvm: x86: Do not leave halt if interrupts are disabled

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

When an external interrupt is pending but IF is cleared, we must not leave the halt state prematurely.

---
 target-i386/kvm.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
target-i386/kvm.c +3 -1
index f7995bd..3a07fce 100644
@@ -1590,7 +1590,9 @@ int kvm_arch_process_async_events(CPUState *env)
         return 0;
     }
 
-    if (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)) {
+    if (((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+         (env->eflags & IF_MASK)) ||
+        (env->interrupt_request & CPU_INTERRUPT_NMI)) {
         env->halted = 0;
     }
     if (env->interrupt_request & CPU_INTERRUPT_INIT) {
Signature · 1 line
1.7.4
#26 lore raw

PATCH 24/35 kvm: Mark VCPU state dirty on creation

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

This avoids that early cpu_synchronize_state calls try to retrieve an uninitialized state from the kernel. That even causes a deadlock if io-thread is enabled.

---
 kvm-all.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
kvm-all.c +1 -0
index 226843c..62b0984 100644
@@ -211,6 +211,7 @@ int kvm_init_vcpu(CPUState *env)
 
     env->kvm_fd = ret;
     env->kvm_state = s;
+    env->kvm_vcpu_dirty = 1;
 
     mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
     if (mmap_size < 0) {
Signature · 1 line
1.7.4
#27 lore raw

PATCH 25/35 x86: Properly reset PAT MSR

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Conforming to the Intel spec, set the power-on value of PAT also on reset, but save it across INIT.

---
 target-i386/cpu.h    |    4 ++--
 target-i386/cpuid.c  |    1 -
 target-i386/helper.c |    5 +++++
 3 files changed, 7 insertions(+), 3 deletions(-)
target-i386/cpu.h +2 -2
index d0eae75..c7047d5 100644
@@ -685,8 +685,6 @@ typedef struct CPUX86State {
 
     uint64_t tsc;
 
-    uint64_t pat;
-
     uint64_t mcg_status;
 
     /* exception/interrupt handling */
@@ -707,6 +705,8 @@ typedef struct CPUX86State {
 
     CPU_COMMON
 
+    uint64_t pat;
+
     /* processor features (e.g. for CPUID insn) */
     uint32_t cpuid_level;
     uint32_t cpuid_vendor1;
target-i386/cpuid.c +0 -1
index 5382a28..814d13e 100644
@@ -847,7 +847,6 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
     env->cpuid_version |= ((def->model & 0xf) << 4) | ((def->model >> 4) << 16);
     env->cpuid_version |= def->stepping;
     env->cpuid_features = def->features;
-    env->pat = 0x0007040600070406ULL;
     env->cpuid_ext_features = def->ext_features;
     env->cpuid_ext2_features = def->ext2_features;
     env->cpuid_ext3_features = def->ext3_features;
target-i386/helper.c +5 -0
index a08309f..d15fca5 100644
@@ -99,6 +99,8 @@ void cpu_reset(CPUX86State *env)
 
     env->mxcsr = 0x1f80;
 
+    env->pat = 0x0007040600070406ULL;
+
     memset(env->dr, 0, sizeof(env->dr));
     env->dr[6] = DR6_FIXED_1;
     env->dr[7] = DR7_FIXED_1;
@@ -1280,8 +1282,11 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
 void do_cpu_init(CPUState *env)
 {
     int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
+    uint64_t pat = env->pat;
+
     cpu_reset(env);
     env->interrupt_request = sipi;
+    env->pat = pat;
     apic_init_reset(env->apic_state);
     env->halted = !cpu_is_bsp(env);
 }
Signature · 1 line
1.7.4
#28 lore raw

PATCH 26/35 x86: Save/restore PAT MSR

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

---
 target-i386/machine.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
target-i386/machine.c +2 -0
index d78eceb..6384f54 100644
@@ -491,6 +491,8 @@ static const VMStateDescription vmstate_cpu = {
         VMSTATE_UINT64_V(xcr0, CPUState, 12),
         VMSTATE_UINT64_V(xstate_bv, CPUState, 12),
         VMSTATE_YMMH_REGS_VARS(ymmh_regs, CPUState, CPU_NB_REGS, 12),
+
+        VMSTATE_UINT64_V(pat, CPUState, 13),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     },
Signature · 1 line
1.7.4
#29 lore raw

PATCH 27/35 kvm: x86: Synchronize PAT MSR with the kernel

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

---
 target-i386/kvm.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
target-i386/kvm.c +5 -0
index 3a07fce..032bc3e 100644
@@ -861,6 +861,7 @@ static int kvm_put_msrs(CPUState *env, int level)
     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);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
+    kvm_msr_entry_set(&msrs[n++], MSR_PAT, env->pat);
     if (has_msr_star) {
         kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
     }
@@ -1113,6 +1114,7 @@ static int kvm_get_msrs(CPUState *env)
     msrs[n++].index = MSR_IA32_SYSENTER_CS;
     msrs[n++].index = MSR_IA32_SYSENTER_ESP;
     msrs[n++].index = MSR_IA32_SYSENTER_EIP;
+    msrs[n++].index = MSR_PAT;
     if (has_msr_star) {
         msrs[n++].index = MSR_STAR;
     }
@@ -1168,6 +1170,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_SYSENTER_EIP:
             env->sysenter_eip = msrs[i].data;
             break;
+        case MSR_PAT:
+            env->pat = msrs[i].data;
+            break;
         case MSR_STAR:
             env->star = msrs[i].data;
             break;
Signature · 1 line
1.7.4
#30 lore raw

PATCH 28/35 kvm: Consider EXIT_DEBUG unknown without CAP_SET_GUEST_DEBUG

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Without KVM_CAP_SET_GUEST_DEBUG, we neither motivate the kernel to report KVM_EXIT_DEBUG nor do we expect such exits. So fall through to the arch code which will simply report an unknown exit reason.

---
 kvm-all.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
kvm-all.c +2 -2
index 62b0984..906521e 100644
@@ -975,17 +975,17 @@ int kvm_cpu_exec(CPUState *env)
             ret = kvm_handle_internal_error(env, run);
             break;
 #endif
+#ifdef KVM_CAP_SET_GUEST_DEBUG
         case KVM_EXIT_DEBUG:
             DPRINTF("kvm_exit_debug\n");
-#ifdef KVM_CAP_SET_GUEST_DEBUG
             if (kvm_arch_debug(&run->debug.arch)) {
                 ret = EXCP_DEBUG;
                 goto out;
             }
             /* re-enter, this exception was guest-internal */
             ret = 1;
-#endif /* KVM_CAP_SET_GUEST_DEBUG */
             break;
+#endif /* KVM_CAP_SET_GUEST_DEBUG */
         default:
             DPRINTF("kvm_arch_handle_exit\n");
             ret = kvm_arch_handle_exit(env, run);
Signature · 1 line
1.7.4
#31 lore raw

PATCH 29/35 kvm: Keep KVM_RUN return value in separate variable

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Avoid using 'ret' both for the return value of KVM_RUN as well as the code kvm_cpu_exec is supposed to return. Both have no direct relation.

---
 kvm-all.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
kvm-all.c +5 -5
index 906521e..be235ec 100644
@@ -890,7 +890,7 @@ void kvm_cpu_synchronize_post_init(CPUState *env)
 int kvm_cpu_exec(CPUState *env)
 {
     struct kvm_run *run = env->kvm_run;
-    int ret;
+    int ret, run_ret;
 
     DPRINTF("kvm_cpu_exec()\n");
 
@@ -920,7 +920,7 @@ int kvm_cpu_exec(CPUState *env)
         cpu_single_env = NULL;
         qemu_mutex_unlock_iothread();
 
-        ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
+        run_ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
 
         qemu_mutex_lock_iothread();
         cpu_single_env = env;
@@ -928,14 +928,14 @@ int kvm_cpu_exec(CPUState *env)
 
         kvm_flush_coalesced_mmio_buffer();
 
-        if (ret == -EINTR || ret == -EAGAIN) {
+        if (run_ret == -EINTR || run_ret == -EAGAIN) {
             DPRINTF("io window exit\n");
             ret = 0;
             break;
         }
 
-        if (ret < 0) {
-            DPRINTF("kvm run failed %s\n", strerror(-ret));
+        if (run_ret < 0) {
+            DPRINTF("kvm run failed %s\n", strerror(-run_ret));
             abort();
         }
 
Signature · 1 line
1.7.4
#32 lore raw

PATCH 30/35 kvm: Reorder error handling of KVM_RUN

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Test for general errors first as this is the slower path.

---
 kvm-all.c |   11 +++++------
 1 files changed, 5 insertions(+), 6 deletions(-)
kvm-all.c +5 -6
index be235ec..8531555 100644
@@ -928,13 +928,12 @@ int kvm_cpu_exec(CPUState *env)
 
         kvm_flush_coalesced_mmio_buffer();
 
-        if (run_ret == -EINTR || run_ret == -EAGAIN) {
-            DPRINTF("io window exit\n");
-            ret = 0;
-            break;
-        }
-
         if (run_ret < 0) {
+            if (run_ret == -EINTR || run_ret == -EAGAIN) {
+                DPRINTF("io window exit\n");
+                ret = 0;
+                break;
+            }
             DPRINTF("kvm run failed %s\n", strerror(-run_ret));
             abort();
         }
Signature · 1 line
1.7.4
#33 lore raw

PATCH 31/35 kvm: Rework inner loop of kvm_cpu_exec

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Let kvm_cpu_exec return EXCP_* values consistently and generate those codes already inside its inner loop. This means we will now re-enter the kernel while ret == 0.

Update kvm_handle_internal_error accordingly, but keep kvm_arch_handle_exit untouched, it will be converted in a separate step.

---
 kvm-all.c |   26 ++++++++++++++------------
 1 files changed, 14 insertions(+), 12 deletions(-)
kvm-all.c +14 -12
index 8531555..271e361 100644
@@ -831,7 +831,7 @@ static int kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
         fprintf(stderr, "emulation failure\n");
         if (!kvm_arch_stop_on_emulation_error(env)) {
             cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
-            return 0;
+            return EXCP_INTERRUPT;
         }
     }
     /* FIXME: Should trigger a qmp message to let management know
@@ -931,14 +931,13 @@ int kvm_cpu_exec(CPUState *env)
         if (run_ret < 0) {
             if (run_ret == -EINTR || run_ret == -EAGAIN) {
                 DPRINTF("io window exit\n");
-                ret = 0;
+                ret = EXCP_INTERRUPT;
                 break;
             }
             DPRINTF("kvm run failed %s\n", strerror(-run_ret));
             abort();
         }
 
-        ret = 0; /* exit loop */
         switch (run->exit_reason) {
         case KVM_EXIT_IO:
             DPRINTF("handle_io\n");
@@ -947,7 +946,7 @@ int kvm_cpu_exec(CPUState *env)
                           run->io.direction,
                           run->io.size,
                           run->io.count);
-            ret = 1;
+            ret = 0;
             break;
         case KVM_EXIT_MMIO:
             DPRINTF("handle_mmio\n");
@@ -955,14 +954,16 @@ int kvm_cpu_exec(CPUState *env)
                                    run->mmio.data,
                                    run->mmio.len,
                                    run->mmio.is_write);
-            ret = 1;
+            ret = 0;
             break;
         case KVM_EXIT_IRQ_WINDOW_OPEN:
             DPRINTF("irq_window_open\n");
+            ret = EXCP_INTERRUPT;
             break;
         case KVM_EXIT_SHUTDOWN:
             DPRINTF("shutdown\n");
             qemu_system_reset_request();
+            ret = EXCP_INTERRUPT;
             break;
         case KVM_EXIT_UNKNOWN:
             fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n",
@@ -979,28 +980,29 @@ int kvm_cpu_exec(CPUState *env)
             DPRINTF("kvm_exit_debug\n");
             if (kvm_arch_debug(&run->debug.arch)) {
                 ret = EXCP_DEBUG;
-                goto out;
+                break;
             }
             /* re-enter, this exception was guest-internal */
-            ret = 1;
+            ret = 0;
             break;
 #endif /* KVM_CAP_SET_GUEST_DEBUG */
         default:
             DPRINTF("kvm_arch_handle_exit\n");
             ret = kvm_arch_handle_exit(env, run);
+            if (ret == 0) {
+                ret = EXCP_INTERRUPT;
+            } else if (ret > 0) {
+                ret = 0;
+            }
             break;
         }
-    } while (ret > 0);
+    } while (ret == 0);
 
     if (ret < 0) {
         cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
         vm_stop(VMSTOP_PANIC);
     }
-    ret = EXCP_INTERRUPT;
 
-#ifdef KVM_CAP_SET_GUEST_DEBUG
-out:
-#endif
     env->exit_request = 0;
     cpu_single_env = NULL;
     return ret;
Signature · 1 line
1.7.4
#34 lore raw

PATCH 32/35 kvm: Align kvm_arch_handle_exit to kvm_cpu_exec changes

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Make the return code of kvm_arch_handle_exit directly usable for kvm_cpu_exec. This is straightforward for x86 and ppc, just s390 would require more work. Avoid this for now by pushing the return code translation logic into s390's kvm_arch_handle_exit.

---
 kvm-all.c          |    5 -----
 target-i386/kvm.c  |    8 ++++----
 target-ppc/kvm.c   |    8 ++++----
 target-s390x/kvm.c |    5 +++++
 4 files changed, 13 insertions(+), 13 deletions(-)
kvm-all.c +0 -5
index 271e361..f34cb69 100644
@@ -989,11 +989,6 @@ int kvm_cpu_exec(CPUState *env)
         default:
             DPRINTF("kvm_arch_handle_exit\n");
             ret = kvm_arch_handle_exit(env, run);
-            if (ret == 0) {
-                ret = EXCP_INTERRUPT;
-            } else if (ret > 0) {
-                ret = 0;
-            }
             break;
         }
     } while (ret == 0);
target-i386/kvm.c +4 -4
index 032bc3e..6f84610 100644
@@ -1618,10 +1618,10 @@ static int kvm_handle_halt(CPUState *env)
           (env->eflags & IF_MASK)) &&
         !(env->interrupt_request & CPU_INTERRUPT_NMI)) {
         env->halted = 1;
-        return 0;
+        return EXCP_HLT;
     }
 
-    return 1;
+    return 0;
 }
 
 static bool host_supports_vmx(void)
@@ -1637,7 +1637,7 @@ static bool host_supports_vmx(void)
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
 {
     uint64_t code;
-    int ret = 0;
+    int ret;
 
     switch (run->exit_reason) {
     case KVM_EXIT_HLT:
@@ -1645,7 +1645,7 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
         ret = kvm_handle_halt(env);
         break;
     case KVM_EXIT_SET_TPR:
-        ret = 1;
+        ret = 0;
         break;
     case KVM_EXIT_FAIL_ENTRY:
         code = run->fail_entry.hardware_entry_failure_reason;
target-ppc/kvm.c +4 -4
index 6c99a16..593eb98 100644
@@ -271,7 +271,7 @@ static int kvmppc_handle_halt(CPUState *env)
         env->exception_index = EXCP_HLT;
     }
 
-    return 1;
+    return 0;
 }
 
 /* map dcr access to existing qemu dcr emulation */
@@ -280,7 +280,7 @@ static int kvmppc_handle_dcr_read(CPUState *env, uint32_t dcrn, uint32_t *data)
     if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0)
         fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
 
-    return 1;
+    return 0;
 }
 
 static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
@@ -288,12 +288,12 @@ static int kvmppc_handle_dcr_write(CPUState *env, uint32_t dcrn, uint32_t data)
     if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0)
         fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
 
-    return 1;
+    return 0;
 }
 
 int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
 {
-    int ret = 0;
+    int ret;
 
     switch (run->exit_reason) {
     case KVM_EXIT_DCR:
target-s390x/kvm.c +5 -0
index a85ae0f..9123203 100644
@@ -497,6 +497,11 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
             break;
     }
 
+    if (ret == 0) {
+        ret = EXCP_INTERRUPT;
+    } else if (ret > 0) {
+        ret = 0;
+    }
     return ret;
 }
 
Signature · 1 line
1.7.4
#35 lore raw

PATCH 33/35 kvm: x86: Reorder functions in kvm.c

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Required for next patch which will access guest debug services from kvm_arch_handle_exit. No functional changes.

---
 target-i386/kvm.c |  108 ++++++++++++++++++++++++++--------------------------
 1 files changed, 54 insertions(+), 54 deletions(-)
target-i386/kvm.c +54 -54
index 6f84610..3920444 100644
@@ -1624,60 +1624,6 @@ static int kvm_handle_halt(CPUState *env)
     return 0;
 }
 
-static bool host_supports_vmx(void)
-{
-    uint32_t ecx, unused;
-
-    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
-    return ecx & CPUID_EXT_VMX;
-}
-
-#define VMX_INVALID_GUEST_STATE 0x80000021
-
-int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
-{
-    uint64_t code;
-    int ret;
-
-    switch (run->exit_reason) {
-    case KVM_EXIT_HLT:
-        DPRINTF("handle_hlt\n");
-        ret = kvm_handle_halt(env);
-        break;
-    case KVM_EXIT_SET_TPR:
-        ret = 0;
-        break;
-    case KVM_EXIT_FAIL_ENTRY:
-        code = run->fail_entry.hardware_entry_failure_reason;
-        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
-                code);
-        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
-            fprintf(stderr,
-                    "\nIf you're runnning a guest on an Intel machine without "
-                        "unrestricted mode\n"
-                    "support, the failure can be most likely due to the guest "
-                        "entering an invalid\n"
-                    "state for Intel VT. For example, the guest maybe running "
-                        "in big real mode\n"
-                    "which is not supported on less recent Intel processors."
-                        "\n\n");
-        }
-        ret = -1;
-        break;
-    case KVM_EXIT_EXCEPTION:
-        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
-                run->ex.exception, run->ex.error_code);
-        ret = -1;
-        break;
-    default:
-        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
-        ret = -1;
-        break;
-    }
-
-    return ret;
-}
-
 #ifdef KVM_CAP_SET_GUEST_DEBUG
 int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
 {
@@ -1860,6 +1806,60 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
 }
 #endif /* KVM_CAP_SET_GUEST_DEBUG */
 
+static bool host_supports_vmx(void)
+{
+    uint32_t ecx, unused;
+
+    host_cpuid(1, 0, &unused, &unused, &ecx, &unused);
+    return ecx & CPUID_EXT_VMX;
+}
+
+#define VMX_INVALID_GUEST_STATE 0x80000021
+
+int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
+{
+    uint64_t code;
+    int ret;
+
+    switch (run->exit_reason) {
+    case KVM_EXIT_HLT:
+        DPRINTF("handle_hlt\n");
+        ret = kvm_handle_halt(env);
+        break;
+    case KVM_EXIT_SET_TPR:
+        ret = 0;
+        break;
+    case KVM_EXIT_FAIL_ENTRY:
+        code = run->fail_entry.hardware_entry_failure_reason;
+        fprintf(stderr, "KVM: entry failed, hardware error 0x%" PRIx64 "\n",
+                code);
+        if (host_supports_vmx() && code == VMX_INVALID_GUEST_STATE) {
+            fprintf(stderr,
+                    "\nIf you're runnning a guest on an Intel machine without "
+                        "unrestricted mode\n"
+                    "support, the failure can be most likely due to the guest "
+                        "entering an invalid\n"
+                    "state for Intel VT. For example, the guest maybe running "
+                        "in big real mode\n"
+                    "which is not supported on less recent Intel processors."
+                        "\n\n");
+        }
+        ret = -1;
+        break;
+    case KVM_EXIT_EXCEPTION:
+        fprintf(stderr, "KVM: exception %d exit (error code 0x%x)\n",
+                run->ex.exception, run->ex.error_code);
+        ret = -1;
+        break;
+    default:
+        fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
 bool kvm_arch_stop_on_emulation_error(CPUState *env)
 {
     return !(env->cr[0] & CR0_PE_MASK) ||
Signature · 1 line
1.7.4
#36 lore raw

PATCH 34/35 kvm: x86: Push kvm_arch_debug to kvm_arch_handle_exit

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

There are no generic bits remaining in the handling of KVM_EXIT_DEBUG. So push its logic completely into arch hands, i.e. only x86 so far.

---
 kvm-all.c         |   11 -----------
 kvm.h             |    2 --
 target-i386/kvm.c |   25 ++++++++++++++++---------
 3 files changed, 16 insertions(+), 22 deletions(-)
kvm-all.c +0 -11
index f34cb69..1d7e8ea 100644
@@ -975,17 +975,6 @@ int kvm_cpu_exec(CPUState *env)
             ret = kvm_handle_internal_error(env, run);
             break;
 #endif
-#ifdef KVM_CAP_SET_GUEST_DEBUG
-        case KVM_EXIT_DEBUG:
-            DPRINTF("kvm_exit_debug\n");
-            if (kvm_arch_debug(&run->debug.arch)) {
-                ret = EXCP_DEBUG;
-                break;
-            }
-            /* re-enter, this exception was guest-internal */
-            ret = 0;
-            break;
-#endif /* KVM_CAP_SET_GUEST_DEBUG */
         default:
             DPRINTF("kvm_arch_handle_exit\n");
             ret = kvm_arch_handle_exit(env, run);
kvm.h +0 -2
index 7bc04e0..d565dba 100644
@@ -136,8 +136,6 @@ struct kvm_sw_breakpoint {
 
 QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
 
-int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info);
-
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env,
                                                  target_ulong pc);
 
target-i386/kvm.c +16 -9
index 3920444..a13599d 100644
@@ -1731,31 +1731,31 @@ void kvm_arch_remove_all_hw_breakpoints(void)
 
 static CPUWatchpoint hw_watchpoint;
 
-int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
+static int kvm_handle_debug(struct kvm_debug_exit_arch *arch_info)
 {
-    int handle = 0;
+    int ret = 0;
     int n;
 
     if (arch_info->exception == 1) {
         if (arch_info->dr6 & (1 << 14)) {
             if (cpu_single_env->singlestep_enabled) {
-                handle = 1;
+                ret = EXCP_DEBUG;
             }
         } else {
             for (n = 0; n < 4; n++) {
                 if (arch_info->dr6 & (1 << n)) {
                     switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) {
                     case 0x0:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         break;
                     case 0x1:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         cpu_single_env->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_WRITE;
                         break;
                     case 0x3:
-                        handle = 1;
+                        ret = EXCP_DEBUG;
                         cpu_single_env->watchpoint_hit = &hw_watchpoint;
                         hw_watchpoint.vaddr = hw_breakpoint[n].addr;
                         hw_watchpoint.flags = BP_MEM_ACCESS;
@@ -1765,17 +1765,18 @@ int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info)
             }
         }
     } else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) {
-        handle = 1;
+        ret = EXCP_DEBUG;
     }
-    if (!handle) {
+    if (ret == 0) {
         cpu_synchronize_state(cpu_single_env);
         assert(cpu_single_env->exception_injected == -1);
 
+        /* pass to guest */
         cpu_single_env->exception_injected = arch_info->exception;
         cpu_single_env->has_error_code = 0;
     }
 
-    return handle;
+    return ret;
 }
 
 void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
@@ -1851,6 +1852,12 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
                 run->ex.exception, run->ex.error_code);
         ret = -1;
         break;
+#ifdef KVM_CAP_SET_GUEST_DEBUG
+    case KVM_EXIT_DEBUG:
+        DPRINTF("kvm_exit_debug\n");
+        ret = kvm_handle_debug(&run->debug.arch);
+        break;
+#endif /* KVM_CAP_SET_GUEST_DEBUG */
     default:
         fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
         ret = -1;
Signature · 1 line
1.7.4
#37 lore raw

PATCH 35/35 Expose thread_id in info cpus

In reply to Marcelo Tosatti

From: Jan Kiszka <[email protected]>

Based on patch by Glauber Costa:

To allow management applications like libvirt to apply CPU affinities to the VCPU threads, expose their ID via info cpus. This patch provides the pre-existing and used interface from qemu-kvm.

---
 cpu-defs.h      |    1 +
 cpus.c          |    2 ++
 exec.c          |    3 +++
 monitor.c       |    4 ++++
 os-posix.c      |   10 ++++++++++
 os-win32.c      |    5 +++++
 osdep.h         |    1 +
 qmp-commands.hx |    3 +++
 8 files changed, 29 insertions(+), 0 deletions(-)
cpu-defs.h +1 -0
index 2b59fa6..db48a7a 100644
@@ -203,6 +203,7 @@ typedef struct CPUWatchpoint {
     int nr_cores;  /* number of cores within this CPU package */        \
     int nr_threads;/* number of threads within this CPU */              \
     int running; /* Nonzero if cpu is currently running(usermode).  */  \
+    int thread_id;                                                      \
     /* user data */                                                     \
     void *opaque;                                                       \
                                                                         \
cpus.c +2 -0
index d310b7e..28c2da2 100644
@@ -776,6 +776,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
 
     qemu_mutex_lock(&qemu_global_mutex);
     qemu_thread_get_self(env->thread);
+    env->thread_id = qemu_get_thread_id();
 
     r = kvm_init_vcpu(env);
     if (r < 0) {
@@ -817,6 +818,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
     /* signal CPU creation */
     qemu_mutex_lock(&qemu_global_mutex);
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
+        env->thread_id = qemu_get_thread_id();
         env->created = 1;
     }
     qemu_cond_signal(&qemu_cpu_cond);
exec.c +3 -0
index 12ea582..4721f04 100644
@@ -638,6 +638,9 @@ void cpu_exec_init(CPUState *env)
     env->numa_node = 0;
     QTAILQ_INIT(&env->breakpoints);
     QTAILQ_INIT(&env->watchpoints);
+#ifndef CONFIG_USER_ONLY
+    env->thread_id = qemu_get_thread_id();
+#endif
     *penv = env;
 #if defined(CONFIG_USER_ONLY)
     cpu_list_unlock();
monitor.c +4 -0
index ae20927..481572d 100644
@@ -897,6 +897,9 @@ static void print_cpu_iter(QObject *obj, void *opaque)
         monitor_printf(mon, " (halted)");
     }
 
+    monitor_printf(mon, " thread_id=%" PRId64 " ",
+                   qdict_get_int(cpu, "thread_id"));
+
     monitor_printf(mon, "\n");
 }
 
@@ -941,6 +944,7 @@ static void do_info_cpus(Monitor *mon, QObject **ret_data)
 #elif defined(TARGET_MIPS)
         qdict_put(cpu, "PC", qint_from_int(env->active_tc.PC));
 #endif
+        qdict_put(cpu, "thread_id", qint_from_int(env->thread_id));
 
         qlist_append(cpu_list, cpu);
     }
os-posix.c +10 -0
index 38c29d1..7971f86 100644
@@ -41,6 +41,7 @@
 
 #ifdef CONFIG_LINUX
 #include <sys/prctl.h>
+#include <sys/syscall.h>
 #endif
 
 #ifdef CONFIG_EVENTFD
@@ -382,3 +383,12 @@ int qemu_create_pidfile(const char *filename)
 
     return 0;
 }
+
+int qemu_get_thread_id(void)
+{
+#if defined (__linux__)
+    return syscall(SYS_gettid);
+#else
+    return getpid();
+#endif
+}
os-win32.c +5 -0
index c971d92..d6d54c6 100644
@@ -266,3 +266,8 @@ int qemu_create_pidfile(const char *filename)
     }
     return 0;
 }
+
+int qemu_get_thread_id(void)
+{
+    return GetCurrentThreadId();
+}
osdep.h +1 -0
index 27eedcf..748df54 100644
@@ -130,5 +130,6 @@ void qemu_vfree(void *ptr);
 int qemu_madvise(void *addr, size_t len, int advice);
 
 int qemu_create_pidfile(const char *filename);
+int qemu_get_thread_id(void);
 
 #endif
qmp-commands.hx +3 -0
index df40a3d..1f72a8d 100644
@@ -1194,6 +1194,7 @@ Return a json-array. Each CPU is represented by a json-object, which contains:
      "nip": PPC (json-int)
      "pc" and "npc": sparc (json-int)
      "PC": mips (json-int)
+- "thread_id": ID of the underlying host thread (json-int)
 
 Example:
 
@@ -1205,12 +1206,14 @@ Example:
             "current":true,
             "halted":false,
             "pc":3227107138
+            "thread_id":3134
          },
          {
             "CPU":1,
             "current":false,
             "halted":true,
             "pc":7108165
+            "thread_id":3135
          }
       ]
    }
Signature · 1 line
1.7.4