diff -r d90c5e8d4ac2 xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Thu Jul 03 11:32:10 2008 +0100 +++ b/xen/arch/x86/traps.c Thu Jul 03 18:26:58 2008 +0200 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -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; diff -r d90c5e8d4ac2 xen/arch/x86/x86_32/traps.c --- a/xen/arch/x86/x86_32/traps.c Thu Jul 03 11:32:10 2008 +0100 +++ b/xen/arch/x86/x86_32/traps.c Thu Jul 03 18:26:58 2008 +0200 @@ -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; diff -r d90c5e8d4ac2 xen/arch/x86/x86_64/compat/traps.c --- a/xen/arch/x86/x86_64/compat/traps.c Thu Jul 03 11:32:10 2008 +0100 +++ b/xen/arch/x86/x86_64/compat/traps.c Thu Jul 03 18:26:58 2008 +0200 @@ -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; diff -r d90c5e8d4ac2 xen/arch/x86/x86_64/traps.c --- a/xen/arch/x86/x86_64/traps.c Thu Jul 03 11:32:10 2008 +0100 +++ b/xen/arch/x86/x86_64/traps.c Thu Jul 03 18:26:58 2008 +0200 @@ -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; diff -r d90c5e8d4ac2 xen/include/asm-x86/traps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/traps.h Thu Jul 03 18:26:58 2008 +0200 @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2007 Advanced Micro Devices, Inc. + * Author: Christoph Egger + * + * 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 */ diff -r d90c5e8d4ac2 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Thu Jul 03 11:32:10 2008 +0100 +++ b/xen/include/xen/sched.h Thu Jul 03 18:26:58 2008 +0200 @@ -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;