Index: 2007-02-20/xen/arch/x86/physdev.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/physdev.c 2007-02-20 10:41:50.000000000 +0100 +++ 2007-02-20/xen/arch/x86/physdev.c 2007-02-20 10:56:30.000000000 +0100 @@ -143,6 +143,57 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H break; } + case PHYSDEVOP_send_nmi: { + struct physdev_send_nmi send_nmi; + struct domain *d; + + ret = -EFAULT; + if ( copy_from_guest(&send_nmi, arg, 1) != 0 ) + break; + + ret = -EPERM; + if ( send_nmi.domain == DOMID_SELF ) + d = current->domain; + else if ( !IS_PRIV(current->domain) ) + break; + else + d = find_domain_by_id(send_nmi.domain); + ret = -ESRCH; + if ( !d ) + break; + + switch ( send_nmi.vcpu ) + { + struct vcpu *v; + + case XEN_SEND_NMI_ALL: + case XEN_SEND_NMI_ALL_BUT_SELF: + for_each_vcpu(d, v) + { + if ( (send_nmi.vcpu == XEN_SEND_NMI_ALL || v != current) && + !test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) ) + vcpu_kick(v); + } + ret = 0; + break; + case 0 ... MAX_VIRT_CPUS - 1: + if ( (v = d->vcpu[send_nmi.vcpu]) != NULL ) + { + if ( !test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) ) + vcpu_kick(v); + ret = 0; + } + break; + default: + ret = EINVAL; + break; + } + + if ( send_nmi.domain != DOMID_SELF ) + put_domain(d); + break; + } + default: ret = -ENOSYS; break; Index: 2007-02-20/xen/arch/x86/traps.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/traps.c 2007-02-20 10:56:27.000000000 +0100 +++ 2007-02-20/xen/arch/x86/traps.c 2007-02-20 10:56:30.000000000 +0100 @@ -2516,6 +2516,12 @@ long do_set_trap_table(XEN_GUEST_HANDLE( if ( cur.address == 0 ) break; + if ( cur.vector == 2 && !TI_GET_IF(&cur) ) + { + rc = -EINVAL; + break; + } + fixup_guest_code_selector(current->domain, cur.cs); memcpy(&dst[cur.vector], &cur, sizeof(cur)); Index: 2007-02-20/xen/arch/x86/x86_32/asm-offsets.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_32/asm-offsets.c 2006-12-13 11:15:54.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_32/asm-offsets.c 2007-02-20 10:56:30.000000000 +0100 @@ -68,6 +68,7 @@ void __dummy__(void) OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt); OFFSET(VCPU_flags, struct vcpu, vcpu_flags); OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr); + OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs); DEFINE(_VCPUF_nmi_pending, _VCPUF_nmi_pending); DEFINE(_VCPUF_nmi_masked, _VCPUF_nmi_masked); DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events); Index: 2007-02-20/xen/arch/x86/x86_32/entry.S =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_32/entry.S 2007-02-20 10:56:03.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_32/entry.S 2007-02-20 10:56:30.000000000 +0100 @@ -232,7 +232,7 @@ test_all_events: shl $IRQSTAT_shift,%eax test %ecx,irq_stat(%eax,1) jnz process_softirqs - btr $_VCPUF_nmi_pending,VCPU_flags(%ebx) + lock btrl $_VCPUF_nmi_pending,VCPU_flags(%ebx) jc process_nmi test_guest_events: movl VCPU_vcpu_info(%ebx),%eax @@ -259,19 +259,20 @@ process_softirqs: ALIGN process_nmi: - movl VCPU_nmi_addr(%ebx),%eax + movzwl VCPU_nmi_cs(%ebx),%eax + movl VCPU_nmi_addr(%ebx),%ecx test %eax,%eax jz test_all_events - bts $_VCPUF_nmi_masked,VCPU_flags(%ebx) + lock btsl $_VCPUF_nmi_masked,VCPU_flags(%ebx) jc 1f sti leal VCPU_trap_bounce(%ebx),%edx - movl %eax,TRAPBOUNCE_eip(%edx) - movw $FLAT_KERNEL_CS,TRAPBOUNCE_cs(%edx) + movl %ecx,TRAPBOUNCE_eip(%edx) + movw %ax,TRAPBOUNCE_cs(%edx) movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx) call create_bounce_frame jmp test_all_events -1: bts $_VCPUF_nmi_pending,VCPU_flags(%ebx) +1: lock btsl $_VCPUF_nmi_pending,VCPU_flags(%ebx) jmp test_guest_events bad_hypercall: Index: 2007-02-20/xen/arch/x86/x86_64/asm-offsets.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_64/asm-offsets.c 2007-02-20 10:41:52.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_64/asm-offsets.c 2007-02-20 10:56:30.000000000 +0100 @@ -76,6 +76,7 @@ void __dummy__(void) OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt); OFFSET(VCPU_flags, struct vcpu, vcpu_flags); OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr); + OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs); DEFINE(_VCPUF_nmi_pending, _VCPUF_nmi_pending); DEFINE(_VCPUF_nmi_masked, _VCPUF_nmi_masked); DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events); Index: 2007-02-20/xen/arch/x86/x86_64/compat/entry.S =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_64/compat/entry.S 2007-02-20 10:56:03.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_64/compat/entry.S 2007-02-20 10:56:30.000000000 +0100 @@ -68,7 +68,7 @@ compat_test_all_events: leaq irq_stat(%rip),%rcx testl $~0,(%rcx,%rax,1) jnz compat_process_softirqs - btrq $_VCPUF_nmi_pending,VCPU_flags(%rbx) + lock btrl $_VCPUF_nmi_pending,VCPU_flags(%rbx) jc compat_process_nmi compat_test_guest_events: movq VCPU_vcpu_info(%rbx),%rax @@ -82,7 +82,7 @@ compat_test_guest_events: movl VCPU_event_addr(%rbx),%eax movl %eax,TRAPBOUNCE_eip(%rdx) movl VCPU_event_sel(%rbx),%eax - movl %eax,TRAPBOUNCE_cs(%rdx) + movw %ax,TRAPBOUNCE_cs(%rdx) movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) call compat_create_bounce_frame jmp compat_test_all_events @@ -97,20 +97,21 @@ compat_process_softirqs: ALIGN /* %rbx: struct vcpu */ compat_process_nmi: - movl VCPU_nmi_addr(%rbx),%eax + movzwl VCPU_nmi_cs(%rbx),%eax + movl VCPU_nmi_addr(%rbx),%ecx testl %eax,%eax jz compat_test_all_events - btsq $_VCPUF_nmi_masked,VCPU_flags(%rbx) + lock btsl $_VCPUF_nmi_masked,VCPU_flags(%rbx) jc 1f sti leaq VCPU_trap_bounce(%rbx),%rdx - movl %eax,TRAPBOUNCE_eip(%rdx) - movl $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx) + movl %ecx,TRAPBOUNCE_eip(%rdx) + movw %ax,TRAPBOUNCE_cs(%rdx) movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) call compat_create_bounce_frame jmp compat_test_all_events 1: - btsq $_VCPUF_nmi_pending,VCPU_flags(%rbx) + lock btsl $_VCPUF_nmi_pending,VCPU_flags(%rbx) jmp compat_test_guest_events compat_bad_hypercall: @@ -145,7 +146,7 @@ compat_failsafe_callback: movl VCPU_failsafe_addr(%rbx),%eax movl %eax,TRAPBOUNCE_eip(%rdx) movl VCPU_failsafe_sel(%rbx),%eax - movl %eax,TRAPBOUNCE_cs(%rdx) + movw %ax,TRAPBOUNCE_cs(%rdx) movw $TBF_FAILSAFE,TRAPBOUNCE_flags(%rdx) btq $_VGCF_failsafe_disables_events,VCPU_guest_context_flags(%rbx) jnc 1f Index: 2007-02-20/xen/arch/x86/x86_64/compat/traps.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_64/compat/traps.c 2007-02-20 10:41:57.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_64/compat/traps.c 2007-02-20 10:56:30.000000000 +0100 @@ -287,6 +287,12 @@ int compat_set_trap_table(XEN_GUEST_HAND if ( cur.address == 0 ) break; + if ( cur.vector == 2 && !TI_GET_IF(&cur) ) + { + rc = -EINVAL; + break; + } + fixup_guest_code_selector(current->domain, cur.cs); XLAT_trap_info(dst + cur.vector, &cur); Index: 2007-02-20/xen/arch/x86/x86_64/entry.S =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_64/entry.S 2007-02-20 10:56:03.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_64/entry.S 2007-02-20 10:56:30.000000000 +0100 @@ -177,7 +177,7 @@ test_all_events: leaq irq_stat(%rip),%rcx testl $~0,(%rcx,%rax,1) jnz process_softirqs - btr $_VCPUF_nmi_pending,VCPU_flags(%rbx) + lock btrl $_VCPUF_nmi_pending,VCPU_flags(%rbx) jc process_nmi test_guest_events: movq VCPU_vcpu_info(%rbx),%rax @@ -207,7 +207,7 @@ process_nmi: movq VCPU_nmi_addr(%rbx),%rax test %rax,%rax jz test_all_events - bts $_VCPUF_nmi_masked,VCPU_flags(%rbx) + lock btsl $_VCPUF_nmi_masked,VCPU_flags(%rbx) jc 1f sti leaq VCPU_trap_bounce(%rbx),%rdx @@ -215,7 +215,7 @@ process_nmi: movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) call create_bounce_frame jmp test_all_events -1: bts $_VCPUF_nmi_pending,VCPU_flags(%rbx) +1: lock btsl $_VCPUF_nmi_pending,VCPU_flags(%rbx) jmp test_guest_events bad_hypercall: Index: 2007-02-20/xen/arch/x86/x86_64/physdev.c =================================================================== --- 2007-02-20.orig/xen/arch/x86/x86_64/physdev.c 2007-02-20 10:41:50.000000000 +0100 +++ 2007-02-20/xen/arch/x86/x86_64/physdev.c 2007-02-20 10:56:30.000000000 +0100 @@ -30,6 +30,10 @@ #define physdev_irq_status_query compat_physdev_irq_status_query #define physdev_irq_status_query_t physdev_irq_status_query_compat_t +#define xen_physdev_send_nmi physdev_send_nmi +CHECK_physdev_send_nmi; +#undef xen_physdev_send_nmi + #define COMPAT #undef guest_handle_okay #define guest_handle_okay compat_handle_okay Index: 2007-02-20/xen/common/kernel.c =================================================================== --- 2007-02-20.orig/xen/common/kernel.c 2007-02-20 10:41:46.000000000 +0100 +++ 2007-02-20/xen/common/kernel.c 2007-02-20 10:56:30.000000000 +0100 @@ -247,16 +247,20 @@ long register_guest_nmi_callback(unsigne struct vcpu *v = current; struct domain *d = current->domain; - if ( (d->domain_id != 0) || (v->vcpu_id != 0) ) - return -EINVAL; - v->nmi_addr = address; #ifdef CONFIG_X86 + v->arch.guest_context.trap_ctxt[2].vector = 2; + v->arch.guest_context.trap_ctxt[2].flags = 0; + TI_SET_IF(v->arch.guest_context.trap_ctxt + 2, 1); + v->arch.guest_context.trap_ctxt[2].cs = + !IS_COMPAT(d) ? FLAT_KERNEL_CS : FLAT_COMPAT_KERNEL_CS; + /* * If no handler was registered we can 'lose the NMI edge'. Re-assert it * now. */ - if ( arch_get_nmi_reason(d) != 0 ) + if ( d->domain_id == 0 && v->vcpu_id == 0 && + arch_get_nmi_reason(d) != 0 ) set_bit(_VCPUF_nmi_pending, &v->vcpu_flags); #endif @@ -267,6 +271,11 @@ long unregister_guest_nmi_callback(void) { struct vcpu *v = current; +#ifdef CONFIG_X86 + v->arch.guest_context.trap_ctxt[2].cs = 0; + v->arch.guest_context.trap_ctxt[2].vector = 0; + v->arch.guest_context.trap_ctxt[2].flags = 0; +#endif v->nmi_addr = 0; return 0; Index: 2007-02-20/xen/include/public/physdev.h =================================================================== --- 2007-02-20.orig/xen/include/public/physdev.h 2006-12-13 11:15:56.000000000 +0100 +++ 2007-02-20/xen/include/public/physdev.h 2007-02-20 10:56:30.000000000 +0100 @@ -119,6 +119,22 @@ typedef struct physdev_irq physdev_irq_t DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); /* + * Allocate or free a physical upcall vector for the specified IRQ line. + * @arg == pointer to physdev_irq structure. + */ +#define PHYSDEVOP_send_nmi 13 +struct physdev_send_nmi { + /* IN */ + domid_t domain; + uint32_t vcpu; +}; +typedef struct physdev_send_nmi physdev_send_nmi_t; +DEFINE_XEN_GUEST_HANDLE(physdev_send_nmi_t); + +#define XEN_SEND_NMI_ALL (~(uint32_t)0) +#define XEN_SEND_NMI_ALL_BUT_SELF (~(uint32_t)1) + +/* * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() * hypercall since 0x00030202. */ Index: 2007-02-20/xen/include/xen/sched.h =================================================================== --- 2007-02-20.orig/xen/include/xen/sched.h 2007-02-20 10:42:03.000000000 +0100 +++ 2007-02-20/xen/include/xen/sched.h 2007-02-20 10:56:30.000000000 +0100 @@ -108,7 +108,11 @@ struct vcpu /* Bitmask of CPUs on which this VCPU may run. */ cpumask_t cpu_affinity; +#ifndef CONFIG_X86 unsigned long nmi_addr; /* NMI callback address. */ +#else +# define nmi_addr arch.guest_context.trap_ctxt[2].address +#endif /* Bitmask of CPUs which are holding onto this VCPU's state. */ cpumask_t vcpu_dirty_cpumask; Index: 2007-02-20/xen/include/xlat.lst =================================================================== --- 2007-02-20.orig/xen/include/xlat.lst 2007-02-20 10:41:58.000000000 +0100 +++ 2007-02-20/xen/include/xlat.lst 2007-02-20 10:56:30.000000000 +0100 @@ -40,6 +40,7 @@ ! memory_map memory.h ! memory_reservation memory.h ! translate_gpfn_list memory.h +? physdev_send_nmi physdev.h ! sched_poll sched.h ? sched_remote_shutdown sched.h ? sched_shutdown sched.h