Skip to contentSkip to conversation

Machine Check Support

PATCH New Christoph Egger 1 participant 1 message Jul 4, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Machine Check Support

Hi,

This introduces send_guest_trap() as preparation for machine check support. send_guest_trap() is designed to inject any trap into a vcpu from NMI/MCE context. This patch makes NMI use of it.

Signature · 12 lines
AMD Saxony, Dresden, Germany
Operating System Research Center

Legal Information:
AMD Saxony Limited Liability Company & Co. KG
Sitz (Geschäftsanschrift):
   Wilschdorfer Landstr. 101, 01109 Dresden, Deutschland
Registergericht Dresden: HRA 4896
vertretungsberechtigter Komplementär:
   AMD Saxony LLC (Sitz Wilmington, Delaware, USA)
Geschäftsführer der AMD Saxony LLC:
   Dr. Hans-R. Deppe, Thomas McCoy
xen/arch/x86/traps.c +64 -8
diff -r d90c5e8d4ac2 xen/arch/x86/traps.c
@@ -61,6 +61,7 @@
 #include <asm/msr.h>
 #include <asm/shared.h>
 #include <asm/x86_emulate.h>
+#include <asm/traps.h>
 #include <asm/hvm/vpt.h>
 #include <public/arch-x86/cpuid.h>
 
@@ -2678,25 +2679,51 @@ asmlinkage void do_general_protection(st
     panic("GENERAL PROTECTION FAULT\n[error_code=%04x]\n", regs->error_code);
 }
 
+static DEFINE_PER_CPU(struct softirq_trap, softirq_trap);
+
 static void nmi_mce_softirq(void)
 {
-    /* Only used to defer wakeup of dom0,vcpu0 to a safe (non-NMI) context. */
-    vcpu_kick(dom0->vcpu[0]);
+    int cpu = smp_processor_id();
+    struct softirq_trap *st = &per_cpu(softirq_trap, cpu);
+    cpumask_t affinity;
+
+    BUG_ON(st == NULL);
+    BUG_ON(st->vcpu == NULL);
+
+    /* Set the tmp value unconditionally, so that
+     * the check in the iret hypercall works. */
+    st->vcpu->cpu_affinity_tmp = st->vcpu->cpu_affinity;
+
+    if ((cpu != st->processor)
+       || (st->processor != st->vcpu->processor))
+    {
+        /* We are on a different physical cpu.
+         * Make sure to wakeup the vcpu on the
+         * specified processor.
+         */
+        cpus_clear(affinity);
+        cpu_set(st->processor, affinity);
+        vcpu_set_affinity(st->vcpu, &affinity);
+
+        /* Affinity is restored in the iret hypercall. */
+    }
+
+    /* Only used to defer wakeup of domain/vcpu to
+     * a safe (non-NMI/MCE) context.
+     */
+    vcpu_kick(st->vcpu);
 }
 
 static void nmi_dom0_report(unsigned int reason_idx)
 {
-    struct domain *d;
-    struct vcpu   *v;
+    struct domain *d = dom0;
 
-    if ( ((d = dom0) == NULL) || ((v = d->vcpu[0]) == NULL) )
+    if ( (d == NULL) || (d->vcpu[0] == NULL) )
         return;
 
     set_bit(reason_idx, nmi_reason(d));
 
-    /* Not safe to wake a vcpu here, or even to schedule a tasklet! */
-    if ( !test_and_set_bool(v->nmi_pending) )
-        raise_softirq(NMI_MCE_SOFTIRQ);
+    send_guest_trap(d, 0, TRAP_nmi);
 }
 
 asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
@@ -3010,6 +3037,35 @@ long unregister_guest_nmi_callback(void)
     return 0;
 }
 
+int send_guest_trap(struct domain *d, uint16_t vcpuid, unsigned int trap_nr)
+{
+    struct vcpu *v;
+    struct softirq_trap *st;
+
+    BUG_ON(d == NULL);
+    BUG_ON(vcpuid >= MAX_VIRT_CPUS);
+    v = d->vcpu[vcpuid];
+
+    switch (trap_nr) {
+    case TRAP_nmi:
+        if ( !test_and_set_bool(v->nmi_pending) ) {
+               st = &per_cpu(softirq_trap, smp_processor_id());
+               st->domain = dom0;
+               st->vcpu = dom0->vcpu[0];
+               st->processor = st->vcpu->processor;
+
+               /* not safe to wake up a vcpu here */
+               raise_softirq(NMI_MCE_SOFTIRQ);
+               return 0;
+        }
+        break;
+    }
+
+    /* delivery failed */
+    return -EIO;
+}
+
+
 long do_set_trap_table(XEN_GUEST_HANDLE(const_trap_info_t) traps)
 {
     struct trap_info cur;
xen/arch/x86/x86_32/traps.c +4 -0
diff -r d90c5e8d4ac2 xen/arch/x86/x86_32/traps.c
@@ -255,6 +255,10 @@ unsigned long do_iret(void)
             goto exit_and_crash;
     }
 
+    /* Restore affinity.  */
+    if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+        vcpu_set_affinity(v, &v->cpu_affinity_tmp);
+
     /* No longer in NMI context. */
     v->nmi_masked = 0;
 
xen/arch/x86/x86_64/compat/traps.c +4 -0
diff -r d90c5e8d4ac2 xen/arch/x86/x86_64/compat/traps.c
@@ -120,6 +120,10 @@ unsigned int compat_iret(void)
     }
     else
         regs->_esp += 16;
+
+    /* Restore affinity.  */
+    if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+        vcpu_set_affinity(v, &v->cpu_affinity_tmp);
 
     /* No longer in NMI context. */
     v->nmi_masked = 0;
xen/arch/x86/x86_64/traps.c +4 -0
diff -r d90c5e8d4ac2 xen/arch/x86/x86_64/traps.c
@@ -288,6 +288,10 @@ unsigned long do_iret(void)
         regs->rcx = iret_saved.rcx;
     }
 
+    /* Restore affinity.  */
+    if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
+        vcpu_set_affinity(v, &v->cpu_affinity_tmp);
+
     /* No longer in NMI context. */
     v->nmi_masked = 0;
 
xen/include/asm-x86/traps.h new file +40 -0
diff -r d90c5e8d4ac2 xen/include/asm-x86/traps.h
@@ -0,0 +1,40 @@
+/*
+ * 
+ * Copyright (c) 2007 Advanced Micro Devices, Inc.
+ * Author: Christoph Egger <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef ASM_TRAP_H
+#define ASM_TRAP_H
+
+struct softirq_trap {
+	struct domain *domain;  /* domain to inject trap */
+	struct vcpu *vcpu;	/* vcpu to inject trap */
+	int processor;		/* physical cpu to inject trap */
+};
+
+/**
+ * send_guest_trap
+ *
+ * delivers trap to guest analogous to send_guest_global_virq
+ * return 0 on successful delivery
+ */
+extern int send_guest_trap(struct domain *d, uint16_t vcpuid,
+				unsigned int trap_nr);
+
+
+#endif /* ASM_TRAP_H */
xen/include/xen/sched.h +2 -0
diff -r d90c5e8d4ac2 xen/include/xen/sched.h
@@ -130,6 +130,8 @@ struct vcpu
 
     /* Bitmask of CPUs on which this VCPU may run. */
     cpumask_t        cpu_affinity;
+    /* Used to change affinity temporarily. */
+    cpumask_t        cpu_affinity_tmp;
 
     /* Bitmask of CPUs which are holding onto this VCPU's state. */
     cpumask_t        vcpu_dirty_cpumask;

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel