From: Huang Ying <ying.huang@intel.com>
To: Avi Kivity <avi@redhat.com>,
Anthony Liguori <anthony@codemonkey.ws>,
Andi Kleen <andi@firstfloor.org>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>
Subject: [PATCH -v5 2/2] QEMU-KVM: MCE: Add MCE simulation support to qemu/kvm
Date: Tue, 09 Jun 2009 14:28:17 +0800 [thread overview]
Message-ID: <1244528897.8361.625.camel@yhuang-dev.sh.intel.com> (raw)
KVM ioctls are used to initialize MCE simulation and inject MCE. The
real MCE simulation is implemented in Linux kernel.
ChangeLog:
v5:
- Re-based on latest qemu-kvm.git
v3:
- Re-based on qemu/tcg MCE support patch
v2:
- Use new kernel MCE capability exportion interface.
Signed-off-by: Huang Ying <ying.huang@intel.com>
---
kvm/include/linux/kvm.h | 21 +++++++++++++++++++++
kvm/include/x86/asm/kvm.h | 1 +
libkvm-all.h | 4 ++++
qemu-kvm-x86.c | 22 ++++++++++++++++++++++
qemu-kvm.c | 40 ++++++++++++++++++++++++++++++++++++++++
qemu-kvm.h | 3 +++
target-i386/helper.c | 5 +++++
target-i386/libkvm.c | 33 +++++++++++++++++++++++++++++++++
target-i386/machine.c | 4 ++--
9 files changed, 131 insertions(+), 2 deletions(-)
--- a/target-i386/libkvm.c
+++ b/target-i386/libkvm.c
@@ -380,6 +380,39 @@ int kvm_set_msrs(kvm_vcpu_context_t vcpu
return r;
}
+int kvm_get_mce_cap_supported(kvm_context_t kvm, uint64_t *mce_cap,
+ int *max_banks)
+{
+#ifdef KVM_CAP_MCE
+ int r;
+
+ r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_MCE);
+ if (r > 0) {
+ *max_banks = r;
+ return ioctl(kvm->fd, KVM_X86_GET_MCE_CAP_SUPPORTED, mce_cap);
+ }
+#endif
+ return -ENOSYS;
+}
+
+int kvm_setup_mce(kvm_vcpu_context_t vcpu, uint64_t *mcg_cap)
+{
+#ifdef KVM_CAP_MCE
+ return ioctl(vcpu->fd, KVM_X86_SETUP_MCE, mcg_cap);
+#else
+ return -ENOSYS;
+#endif
+}
+
+int kvm_set_mce(kvm_vcpu_context_t vcpu, struct kvm_x86_mce *m)
+{
+#ifdef KVM_CAP_MCE
+ return ioctl(vcpu->fd, KVM_X86_SET_MCE, m);
+#else
+ return -ENOSYS;
+#endif
+}
+
static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
{
fprintf(stderr,
--- a/qemu-kvm-x86.c
+++ b/qemu-kvm-x86.c
@@ -598,6 +598,28 @@ int kvm_arch_qemu_init_env(CPUState *cen
kvm_trim_features(&cenv->cpuid_ext3_features,
kvm_arch_get_supported_cpuid(cenv, 0x80000001, R_ECX));
+#ifdef KVM_CAP_MCE
+ if (((cenv->cpuid_version >> 8)&0xF) >= 6
+ && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
+ && kvm_check_extension(kvm_context, KVM_CAP_MCE) > 0) {
+ uint64_t mcg_cap;
+ int banks;
+
+ if (kvm_get_mce_cap_supported(kvm_context, &mcg_cap, &banks))
+ perror("kvm_get_mce_cap_supported FAILED");
+ else {
+ if (banks > MCE_BANKS_DEF)
+ banks = MCE_BANKS_DEF;
+ mcg_cap &= MCE_CAP_DEF;
+ mcg_cap |= banks;
+ if (kvm_setup_mce(cenv->kvm_cpu_state.vcpu_ctx, &mcg_cap))
+ perror("kvm_setup_mce FAILED");
+ else
+ cenv->mcg_cap = mcg_cap;
+ }
+ }
+#endif
+
return 0;
}
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -245,4 +245,7 @@ static inline int kvm_set_migration_log(
return kvm_physical_memory_set_dirty_tracking(enable);
}
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+ uint64_t mcg_status, uint64_t addr, uint64_t misc);
+
#endif
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1445,6 +1445,11 @@ void cpu_inject_x86_mce(CPUState *cenv,
unsigned bank_num = mcg_cap & 0xff;
uint64_t *banks = cenv->mce_banks;
+ if (kvm_enabled()) {
+ kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc);
+ return;
+ }
+
if (bank >= bank_num || !(status & MCI_STATUS_VAL))
return;
--- a/kvm/include/linux/kvm.h
+++ b/kvm/include/linux/kvm.h
@@ -463,6 +463,9 @@ struct kvm_trace_rec {
#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
+#ifdef __KVM_HAVE_MCE
+#define KVM_CAP_MCE 31
+#endif
#define KVM_CAP_PIT2 33
#ifdef KVM_CAP_IRQ_ROUTING
@@ -503,6 +506,20 @@ struct kvm_irq_routing {
#endif
+#ifdef KVM_CAP_MCE
+/* x86 MCE */
+struct kvm_x86_mce {
+ __u64 status;
+ __u64 addr;
+ __u64 misc;
+ __u64 mcg_status;
+ __u8 bank;
+ __u8 pad1;
+ __u16 pad2;
+ __u32 pad3;
+};
+#endif
+
/*
* ioctls for VM fds
*/
@@ -591,6 +608,10 @@ struct kvm_irq_routing {
#define KVM_NMI _IO(KVMIO, 0x9a)
/* Available with KVM_CAP_SET_GUEST_DEBUG */
#define KVM_SET_GUEST_DEBUG _IOW(KVMIO, 0x9b, struct kvm_guest_debug)
+/* MCE for x86 */
+#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
+#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
+#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
/*
* Deprecated interfaces
--- a/kvm/include/x86/asm/kvm.h
+++ b/kvm/include/x86/asm/kvm.h
@@ -57,6 +57,7 @@
#define __KVM_HAVE_USER_NMI
#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_MSIX
+#define __KVM_HAVE_MCE
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1439,3 +1439,43 @@ void qemu_kvm_cpu_stop(CPUState *env)
if (kvm_enabled())
env->kvm_cpu_state.stopped = 1;
}
+
+#ifdef TARGET_I386
+#ifdef KVM_CAP_MCE
+struct kvm_x86_mce_data
+{
+ CPUState *env;
+ struct kvm_x86_mce *mce;
+};
+
+static void kvm_do_inject_x86_mce(void *_data)
+{
+ struct kvm_x86_mce_data *data = _data;
+ int r;
+
+ r = kvm_set_mce(data->env->kvm_cpu_state.vcpu_ctx, data->mce);
+ if (r < 0)
+ perror("kvm_set_mce FAILED");
+}
+#endif
+
+void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
+ uint64_t mcg_status, uint64_t addr, uint64_t misc)
+{
+#ifdef KVM_CAP_MCE
+ struct kvm_x86_mce mce = {
+ .bank = bank,
+ .status = status,
+ .mcg_status = mcg_status,
+ .addr = addr,
+ .misc = misc,
+ };
+ struct kvm_x86_mce_data data = {
+ .env = cenv,
+ .mce = &mce,
+ };
+
+ on_vcpu(cenv, kvm_do_inject_x86_mce, &data);
+#endif
+}
+#endif
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -163,7 +163,7 @@ void cpu_save(QEMUFile *f, void *opaque)
/* MCE */
qemu_put_be64s(f, &env->mcg_cap);
- if (env->mcg_cap) {
+ if (env->mcg_cap && !kvm_enabled()) {
qemu_put_be64s(f, &env->mcg_status);
qemu_put_be64s(f, &env->mcg_ctl);
for (i = 0; i < (env->mcg_cap & 0xff); i++) {
@@ -393,7 +393,7 @@ int cpu_load(QEMUFile *f, void *opaque,
if (version_id >= 10) {
qemu_get_be64s(f, &env->mcg_cap);
- if (env->mcg_cap) {
+ if (env->mcg_cap && !kvm_enabled()) {
qemu_get_be64s(f, &env->mcg_status);
qemu_get_be64s(f, &env->mcg_ctl);
for (i = 0; i < (env->mcg_cap & 0xff); i++) {
--- a/libkvm-all.h
+++ b/libkvm-all.h
@@ -29,6 +29,10 @@ typedef struct kvm_vcpu_context *kvm_vcp
struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
int kvm_get_msrs(kvm_vcpu_context_t, struct kvm_msr_entry *msrs, int n);
int kvm_set_msrs(kvm_vcpu_context_t, struct kvm_msr_entry *msrs, int n);
+int kvm_get_mce_cap_supported(kvm_context_t, uint64_t *mce_cap, int *max_banks);
+int kvm_setup_mce(kvm_vcpu_context_t vcpu, uint64_t *mcg_cap);
+struct kvm_x86_mce;
+int kvm_set_mce(kvm_vcpu_context_t vcpu, struct kvm_x86_mce *mce);
#endif
/*!
reply other threads:[~2009-06-09 6:28 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1244528897.8361.625.camel@yhuang-dev.sh.intel.com \
--to=ying.huang@intel.com \
--cc=andi@firstfloor.org \
--cc=anthony@codemonkey.ws \
--cc=avi@redhat.com \
--cc=kvm@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.