Index: 2007-05-14/xen/arch/x86/physdev.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/physdev.c 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/arch/x86/physdev.c 2007-05-14 14:40:35.000000000 +0200 @@ -143,6 +143,56 @@ 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 = rcu_lock_current_domain(); + else if ( IS_PRIV(current->domain) ) + d = rcu_lock_domain_by_id(send_nmi.domain); + else + break; + ret = -ESRCH; + if ( d == NULL ) + 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) && + !xchg(&v->nmi_pending, 1) ) + vcpu_kick(v); + } + ret = 0; + break; + case 0 ... MAX_VIRT_CPUS - 1: + if ( (v = d->vcpu[send_nmi.vcpu]) != NULL ) + { + if ( !xchg(&v->nmi_pending, 1) ) + vcpu_kick(v); + ret = 0; + } + break; + default: + ret = EINVAL; + break; + } + + rcu_unlock_domain(d); + break; + } + default: ret = -ENOSYS; break; Index: 2007-05-14/xen/arch/x86/traps.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/traps.c 2007-05-14 14:40:03.000000000 +0200 +++ 2007-05-14/xen/arch/x86/traps.c 2007-05-14 14:40:35.000000000 +0200 @@ -2517,6 +2517,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-05-14/xen/arch/x86/x86_32/asm-offsets.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_32/asm-offsets.c 2007-04-27 09:31:25.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_32/asm-offsets.c 2007-05-14 14:40:35.000000000 +0200 @@ -68,6 +68,7 @@ void __dummy__(void) OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags); OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt); OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr); + OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs); OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending); OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked); DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events); Index: 2007-05-14/xen/arch/x86/x86_32/entry.S =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_32/entry.S 2007-07-02 10:48:50.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_32/entry.S 2007-05-14 14:40:35.000000000 +0200 @@ -263,14 +263,15 @@ process_nmi: testb $1,VCPU_nmi_masked(%ebx) jnz test_guest_events movb $0,VCPU_nmi_pending(%ebx) - movl VCPU_nmi_addr(%ebx),%eax + movzwl VCPU_nmi_cs(%ebx),%eax + movl VCPU_nmi_addr(%ebx),%ecx test %eax,%eax jz test_guest_events movb $1,VCPU_nmi_masked(%ebx) 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) movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx) call create_bounce_frame jmp test_all_events Index: 2007-05-14/xen/arch/x86/x86_64/asm-offsets.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_64/asm-offsets.c 2007-04-27 09:31:25.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_64/asm-offsets.c 2007-05-14 14:40:35.000000000 +0200 @@ -77,6 +77,7 @@ void __dummy__(void) OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags); OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt); OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr); + OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs); OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending); OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked); DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events); Index: 2007-05-14/xen/arch/x86/x86_64/compat/entry.S =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_64/compat/entry.S 2007-07-02 10:48:18.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_64/compat/entry.S 2007-07-02 11:56:42.000000000 +0200 @@ -119,14 +119,15 @@ compat_process_nmi: testb $1,VCPU_nmi_masked(%rbx) jnz compat_test_guest_events movb $0,VCPU_nmi_pending(%rbx) - movl VCPU_nmi_addr(%rbx),%eax + movzwl VCPU_nmi_cs(%rbx),%eax + movl VCPU_nmi_addr(%rbx),%ecx testl %eax,%eax jz compat_test_guest_events movb $1,VCPU_nmi_masked(%rbx) sti leaq VCPU_trap_bounce(%rbx),%rdx - movl %eax,TRAPBOUNCE_eip(%rdx) - movw $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx) + movl %ecx,TRAPBOUNCE_eip(%rdx) + movw %ax,TRAPBOUNCE_cs(%rdx) movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) call compat_create_bounce_frame jmp compat_test_all_events Index: 2007-05-14/xen/arch/x86/x86_64/compat/traps.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_64/compat/traps.c 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_64/compat/traps.c 2007-05-14 14:40:35.000000000 +0200 @@ -288,6 +288,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-05-14/xen/arch/x86/x86_64/physdev.c =================================================================== --- 2007-05-14.orig/xen/arch/x86/x86_64/physdev.c 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/arch/x86/x86_64/physdev.c 2007-05-14 14:40:35.000000000 +0200 @@ -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-05-14/xen/common/kernel.c =================================================================== --- 2007-05-14.orig/xen/common/kernel.c 2007-05-14 14:33:33.000000000 +0200 +++ 2007-05-14/xen/common/kernel.c 2007-05-14 14:40:35.000000000 +0200 @@ -246,16 +246,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_pv_32on64_domain(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 ) v->nmi_pending = 1; #endif @@ -266,6 +270,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-05-14/xen/include/public/physdev.h =================================================================== --- 2007-05-14.orig/xen/include/public/physdev.h 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/include/public/physdev.h 2007-05-14 14:40:35.000000000 +0200 @@ -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-05-14/xen/include/xen/sched.h =================================================================== --- 2007-05-14.orig/xen/include/xen/sched.h 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/include/xen/sched.h 2007-05-14 14:40:35.000000000 +0200 @@ -128,7 +128,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-05-14/xen/include/xlat.lst =================================================================== --- 2007-05-14.orig/xen/include/xlat.lst 2007-07-02 10:37:50.000000000 +0200 +++ 2007-05-14/xen/include/xlat.lst 2007-05-14 14:40:35.000000000 +0200 @@ -35,6 +35,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