diff --git a/xen/arch/x86/x86_64/entry-fred.S b/xen/arch/x86/x86_64/entry-fred.S index e9c84423da..1ad9694a04 100644 --- a/xen/arch/x86/x86_64/entry-fred.S +++ b/xen/arch/x86/x86_64/entry-fred.S @@ -20,6 +20,12 @@ FUNC(entry_FRED_R3, 4096) GET_STACK_END(14) movq STACK_CPUINFO_FIELD(current_vcpu)(%r14), %rbx + /* NMIs need special handling on return to guest. */ + movzbl UREGS_ss + 6(%rsp), %eax + and $0xf, %eax + cmp $X86_ET_NMI, %al + je nmi_exit_to_guest + jmp test_all_events #else BUG /* Not Reached */ diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index e10444c1ff..33f6788984 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -147,6 +147,35 @@ process_trap: jmp test_all_events END(switch_to_kernel) +/* + * When returning to guest from an NMI, we must execute an IRET/ERETU to + * re-enable NMIs, and must not process softirqs which can e.g. schedule + * rather than returning to guest context. + * + * If a softirq is pending, send ourselves an EVENT_CHECK IPI to compensate. + * This will cause softirq processing to occur upon leaving NMI context. + * + * %rbx: struct vcpu, %r14 stack_end + */ +FUNC(nmi_exit_to_guest) + mov STACK_CPUINFO_FIELD(processor_id)(%r14), %eax + shl $IRQSTAT_shift, %eax + lea irq_stat + IRQSTAT_softirq_pending(%rip), %rcx + cmpl $0, (%rcx, %rax, 1) + je 1f + mov $EVENT_CHECK_VECTOR, %edi + call send_IPI_self +1: + /* For restore_all_guest. */ + mov STACK_CPUINFO_FIELD(current_vcpu)(%r14), %rbx +#ifdef CONFIG_PV32 + mov VCPU_domain(%rbx), %rax + cmpb $0, DOMAIN_is_32bit_pv(%rax) + jne compat_restore_all_guest +#endif + jmp restore_all_guest +END(nmi_exit_to_guest) + .section .text.entry, "ax", @progbits /* %rbx: struct vcpu, interrupts disabled */ @@ -1193,25 +1222,7 @@ FUNC(handle_ist_exception) #ifdef CONFIG_PV testb $3,UREGS_cs(%rsp) jz restore_all_xen - /* Send an IPI to ourselves to cover for the lack of event checking. */ - mov STACK_CPUINFO_FIELD(processor_id)(%r14), %eax - shll $IRQSTAT_shift,%eax - leaq irq_stat+IRQSTAT_softirq_pending(%rip),%rcx - cmpl $0,(%rcx,%rax,1) - je 1f - movl $EVENT_CHECK_VECTOR,%edi - call send_IPI_self -1: - /* For restore_all_guest. */ - mov STACK_CPUINFO_FIELD(current_vcpu)(%r14), %rbx -#ifdef CONFIG_PV32 - movq VCPU_domain(%rbx),%rax - cmpb $0,DOMAIN_is_32bit_pv(%rax) - je restore_all_guest - jmp compat_restore_all_guest -#else - jmp restore_all_guest -#endif + jmp nmi_exit_to_guest #else ASSERT_CONTEXT_IS_XEN jmp restore_all_xen