From: Marcelo Tosatti <mtosatti@redhat.com>
To: kvm@vger.kernel.org
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Subject: [patch 3/3] Add mce test
Date: Thu, 02 Sep 2010 20:36:55 -0300 [thread overview]
Message-ID: <20100902233712.767024334@redhat.com> (raw)
In-Reply-To: 20100902233652.853027771@redhat.com
[-- Attachment #1: mce --]
[-- Type: text/plain, Size: 8184 bytes --]
Test mce injection, triggered via monitor interface.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Index: kvm-unit-tests/config-x86-common.mak
===================================================================
--- kvm-unit-tests.orig/config-x86-common.mak
+++ kvm-unit-tests/config-x86-common.mak
@@ -27,7 +27,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $
$(TEST_DIR)/smptest.flat $(TEST_DIR)/port80.flat \
$(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \
$(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \
- $(TEST_DIR)/kvmclock_test.flat
+ $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/mce.flat
tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg
@@ -74,6 +74,8 @@ $(TEST_DIR)/svm.flat: $(cstart.o) $(TEST
$(TEST_DIR)/kvmclock_test.flat: $(cstart.o) $(TEST_DIR)/kvmclock.o \
$(TEST_DIR)/kvmclock_test.o
+$(TEST_DIR)/mce.flat: $(cstart.o) $(TEST_DIR)/mce.o $(TEST_DIR)/vm.o
+
arch_clean:
$(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat \
$(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o
Index: kvm-unit-tests/x86/mce.c
===================================================================
--- /dev/null
+++ kvm-unit-tests/x86/mce.c
@@ -0,0 +1,267 @@
+#include "libcflat.h"
+#include "processor.h"
+#include "smp.h"
+#include "apic.h"
+
+typedef struct {
+ unsigned short offset0;
+ unsigned short selector;
+ unsigned short ist : 3;
+ unsigned short : 5;
+ unsigned short type : 4;
+ unsigned short : 1;
+ unsigned short dpl : 2;
+ unsigned short p : 1;
+ unsigned short offset1;
+#ifdef __x86_64__
+ unsigned offset2;
+ unsigned reserved;
+#endif
+} idt_entry_t;
+
+typedef struct {
+ ulong regs[sizeof(ulong)*2];
+ ulong func;
+ ulong rip;
+ ulong cs;
+ ulong rflags;
+} isr_regs_t;
+
+#ifdef __x86_64__
+# define R "r"
+#else
+# define R "e"
+#endif
+
+extern char isr_entry_point[];
+
+asm (
+ "isr_entry_point: \n"
+#ifdef __x86_64__
+ "push %r15 \n\t"
+ "push %r14 \n\t"
+ "push %r13 \n\t"
+ "push %r12 \n\t"
+ "push %r11 \n\t"
+ "push %r10 \n\t"
+ "push %r9 \n\t"
+ "push %r8 \n\t"
+#endif
+ "push %"R "di \n\t"
+ "push %"R "si \n\t"
+ "push %"R "bp \n\t"
+ "push %"R "sp \n\t"
+ "push %"R "bx \n\t"
+ "push %"R "dx \n\t"
+ "push %"R "cx \n\t"
+ "push %"R "ax \n\t"
+#ifdef __x86_64__
+ "mov %rsp, %rdi \n\t"
+ "callq *8*16(%rsp) \n\t"
+#else
+ "push %esp \n\t"
+ "calll *4+4*8(%esp) \n\t"
+ "add $4, %esp \n\t"
+#endif
+ "pop %"R "ax \n\t"
+ "pop %"R "cx \n\t"
+ "pop %"R "dx \n\t"
+ "pop %"R "bx \n\t"
+ "pop %"R "bp \n\t"
+ "pop %"R "bp \n\t"
+ "pop %"R "si \n\t"
+ "pop %"R "di \n\t"
+#ifdef __x86_64__
+ "pop %r8 \n\t"
+ "pop %r9 \n\t"
+ "pop %r10 \n\t"
+ "pop %r11 \n\t"
+ "pop %r12 \n\t"
+ "pop %r13 \n\t"
+ "pop %r14 \n\t"
+ "pop %r15 \n\t"
+#endif
+#ifdef __x86_64__
+ "add $8, %rsp \n\t"
+ "iretq \n\t"
+#else
+ "add $4, %esp \n\t"
+ "iretl \n\t"
+#endif
+ );
+
+static idt_entry_t idt[256];
+
+static void init_idt(void)
+{
+ struct {
+ u16 limit;
+ ulong idt;
+ } __attribute__((packed)) idt_ptr = {
+ sizeof(idt_entry_t) * 256 - 1,
+ (ulong)&idt,
+ };
+
+ asm volatile("lidt %0" : : "m"(idt_ptr));
+}
+
+u8 code[50];
+
+static void set_idt_entry(unsigned vec, void (*func)(isr_regs_t *regs))
+{
+ u8 *thunk = code;
+ ulong ptr = (ulong)thunk;
+ idt_entry_t ent = {
+ .offset0 = ptr,
+ .selector = read_cs(),
+ .ist = 0,
+ .type = 14,
+ .dpl = 0,
+ .p = 1,
+ .offset1 = ptr >> 16,
+#ifdef __x86_64__
+ .offset2 = ptr >> 32,
+#endif
+ };
+#ifdef __x86_64__
+ /* sub $8, %rsp */
+ *thunk++ = 0x48; *thunk++ = 0x83; *thunk++ = 0xec; *thunk++ = 0x08;
+ /* mov $func_low, %(rsp) */
+ *thunk++ = 0xc7; *thunk++ = 0x04; *thunk++ = 0x24;
+ *(u32 *)thunk = (ulong)func; thunk += 4;
+ /* mov $func_high, %(rsp+4) */
+ *thunk++ = 0xc7; *thunk++ = 0x44; *thunk++ = 0x24; *thunk++ = 0x04;
+ *(u32 *)thunk = (ulong)func >> 32; thunk += 4;
+ /* jmp isr_entry_point */
+ *thunk ++ = 0xe9;
+ *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#else
+ /* push $func */
+ *thunk++ = 0x68;
+ *(u32 *)thunk = (ulong)func;
+ /* jmp isr_entry_point */
+ *thunk ++ = 0xe9;
+ *(u32 *)thunk = (ulong)isr_entry_point - (ulong)(thunk + 4);
+#endif
+ idt[vec] = ent;
+}
+
+#define MCI_STATUS_VAL (1ULL<<63) /* valid error */
+#define MCI_STATUS_OVER (1ULL<<62) /* previous errors lost */
+#define MCI_STATUS_UC (1ULL<<61) /* uncorrected error */
+#define MCI_STATUS_EN (1ULL<<60) /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59) /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58) /* addr reg. valid */
+#define MCI_STATUS_PCC (1ULL<<57) /* processor context corrupt */
+#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */
+#define MCI_STATUS_AR (1ULL<<55) /* Action required */
+
+#define MSR_IA32_MCG_CAP 0x00000179
+#define MSR_IA32_MCG_STATUS 0x0000017a
+#define MSR_IA32_MCG_CTL 0x0000017b
+
+#define MSR_IA32_MC0_CTL 0x00000400
+#define MSR_IA32_MC0_STATUS 0x00000401
+#define MSR_IA32_MC0_ADDR 0x00000402
+#define MSR_IA32_MC0_MISC 0x00000403
+
+#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x))
+#define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x))
+#define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x))
+#define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x))
+
+#define X86_CR4_MCE 0x00000040 /* Machine check enable */
+
+
+volatile int ex_done;
+unsigned long long ex_bank, ex_status, ex_cpu, ex_addr;
+
+static void do_handle_mce(isr_regs_t *regs)
+{
+ int i;
+ int nr_banks = rdmsr(MSR_IA32_MCG_CAP) & 0xff;
+ unsigned long status = 0;
+
+ for (i = 0; i < nr_banks; i++) {
+ status = rdmsr(MSR_IA32_MCx_STATUS(i));
+
+ if (status & MCI_STATUS_VAL)
+ break;
+ }
+ ex_bank = i;
+ ex_status = status;
+ ex_cpu = smp_id();
+ ex_addr = rdmsr(MSR_IA32_MCx_ADDR(i));
+ ex_done = 1;
+#ifdef _DEBUG_
+ printf("cpu%d bank=%lx status=%lx addr=%lx\n",
+ ex_cpu, ex_bank, ex_status, ex_addr);
+#endif
+}
+
+int fail = 0;
+
+static void report(const char *name, int cpu, int bank,
+ unsigned long long status, unsigned long long addr)
+{
+ if (ex_cpu != cpu || bank != ex_bank || status != ex_status ||
+ addr != ex_addr) {
+ printf("MCE %s: FAIL\n", name);
+ fail = 1;
+ } else
+ printf("MCE %s: PASS\n", name);
+}
+
+static void enable_mce(void *data)
+{
+ init_idt();
+ write_cr4(read_cr4() | X86_CR4_MCE);
+}
+
+int main(void)
+{
+ unsigned long long status, addr;
+ int bank;
+
+ smp_init();
+ init_idt();
+ set_idt_entry(18, do_handle_mce);
+
+ write_cr4(read_cr4() | X86_CR4_MCE);
+
+ wrmsr(MSR_IA32_MCG_CTL, ~0ULL);
+ wrmsr(MSR_IA32_MC0_CTL, ~0ULL);
+
+ status = MCI_STATUS_VAL|MCI_STATUS_UC;
+ addr = 0x7ffffff;
+ bank = 0;
+ ex_done = 0;
+ /* mce cpu bank status mcgstatus addr misc */
+ monitor_printf("mce %d %d 0x%llx 1 0x%llx 1\n", 0, bank, status, addr);
+ while (!ex_done);
+ report("test 1", 0, bank, status, addr);
+
+ wrmsr(MSR_IA32_MCG_STATUS, 0);
+ wrmsr(MSR_IA32_MCx_STATUS(bank), 0);
+ addr = 0x8fffff;
+ bank = 9;
+ ex_done = 0;
+ monitor_printf("mce %d %d 0x%llx 1 0x%llx 1\n", 0, bank, status, addr);
+ while (!ex_done);
+ report("test 2", 0, bank, status, addr);
+
+ if (cpu_count() == 1)
+ return fail;
+
+ on_cpu(1, enable_mce, 0);
+ wrmsr(MSR_IA32_MCG_STATUS, 0);
+ wrmsr(MSR_IA32_MCx_STATUS(bank), 0);
+ addr = 0x9fffff;
+ bank = 3;
+ ex_done = 0;
+ monitor_printf("mce %d %d 0x%llx 1 0x%llx 1\n", 1, bank, status, addr);
+ while (!ex_done);
+ report("test 3", 1, bank, status, addr);
+
+ return fail;
+}
next prev parent reply other threads:[~2010-09-02 23:50 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-09-02 23:36 [patch 0/3] add mce test Marcelo Tosatti
2010-09-02 23:36 ` [patch 1/3] kvm test: add monitor_printf Marcelo Tosatti
2010-09-03 7:56 ` Paolo Bonzini
2010-09-03 16:48 ` Marcelo Tosatti
2010-09-03 17:23 ` [patch 1/3] kvm test: add monitor_printf (v2) Marcelo Tosatti
2010-09-02 23:36 ` [patch 2/3] kvm test: add kvm-unit.cfg Marcelo Tosatti
2010-09-02 23:36 ` Marcelo Tosatti [this message]
2010-09-05 8:15 ` [patch 3/3] Add mce test Avi Kivity
2010-09-05 21:17 ` Marcelo Tosatti
2010-09-06 14:53 ` Avi Kivity
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=20100902233712.767024334@redhat.com \
--to=mtosatti@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.