x86/nmi: fix shootdown of pcpus running in VMX non-root mode

c/s 7dd3b06ff "vmx: fix handling of NMI VMEXIT" fixed one issue but
inadvertently introduced a regression when it came to the NMI shootdown.  The
shootdown code worked by patching vector 2 in each IDT, but the introduced
direct call to do_nmi() bypassed this.

Instead of patching each IDT, take a different approach by updating the
existing dispatch table.  This allows for the removal of the remote IDT
patching and the removal of the nmi_crash() entry point.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Andrew Cooper authored and Jan Beulich committed 2015-02-11 17:18:27 +01:00
1 parent 52956401df
commit cbeeaa7da0
3 files changed
+23 -44

No files matched your search

+23 -34
View File
@@ -36,9 +36,11 @@ static unsigned int crashing_cpu;
static DEFINE_PER_CPU_READ_MOSTLY(bool_t, crash_save_done);
/* This becomes the NMI handler for non-crashing CPUs, when Xen is crashing. */
void do_nmi_crash(struct cpu_user_regs *regs)
static void noreturn do_nmi_crash(const struct cpu_user_regs *regs)
{
int cpu = smp_processor_id();
unsigned int cpu = smp_processor_id();
stac();
/* nmi_shootdown_cpus() should ensure that this assertion is correct. */
ASSERT(cpu != crashing_cpu);
@@ -113,11 +115,10 @@ void do_nmi_crash(struct cpu_user_regs *regs)
halt();
}
void nmi_crash(void);
static void nmi_shootdown_cpus(void)
{
unsigned long msecs;
int i, cpu = smp_processor_id();
unsigned int cpu = smp_processor_id();
disable_lapic_nmi_watchdog();
local_irq_disable();
@@ -127,38 +128,26 @@ static void nmi_shootdown_cpus(void)
cpumask_andnot(&waiting_to_crash, &cpu_online_map, cpumask_of(cpu));
/* Change NMI trap handlers. Non-crashing pcpus get nmi_crash which
* invokes do_nmi_crash (above), which cause them to write state and
* fall into a loop. The crashing pcpu gets the nop handler to
* cause it to return to this function ASAP.
/*
* Disable IST for MCEs to avoid stack corruption race conditions, and
* change the NMI handler to a nop to avoid deviation from this codepath.
*/
for ( i = 0; i < nr_cpu_ids; i++ )
{
if ( idt_tables[i] == NULL )
continue;
_set_gate_lower(&idt_tables[cpu][TRAP_nmi],
SYS_DESC_irq_gate, 0, &trap_nop);
set_ist(&idt_tables[cpu][TRAP_machine_check], IST_NONE);
if ( i == cpu )
{
/*
* Disable the interrupt stack tables for this cpu's MCE and NMI
* handlers, and alter the NMI handler to have no operation.
* Disabling the stack tables prevents stack corruption race
* conditions, while changing the handler helps prevent cascading
* faults; we are certainly going to crash by this point.
*
* This update is safe from a security point of view, as this pcpu
* is never going to try to sysret back to a PV vcpu.
*/
_set_gate_lower(&idt_tables[i][TRAP_nmi],
SYS_DESC_irq_gate, 0, &trap_nop);
set_ist(&idt_tables[i][TRAP_machine_check], IST_NONE);
}
else
{
/* Do not update stack table for other pcpus. */
_update_gate_addr_lower(&idt_tables[i][TRAP_nmi], &nmi_crash);
}
}
/*
* Ideally would be:
* exception_table[TRAP_nmi] = &do_nmi_crash;
*
* but the exception_table is read only. Borrow an unused fixmap entry
* to construct a writable mapping.
*/
set_fixmap(FIX_TBOOT_MAP_ADDRESS, __pa(&exception_table[TRAP_nmi]));
write_atomic((unsigned long *)
(fix_to_virt(FIX_TBOOT_MAP_ADDRESS) +
((unsigned long)&exception_table[TRAP_nmi] & ~PAGE_MASK)),
(unsigned long)&do_nmi_crash);
/* Ensure the new callback function is set before sending out the NMI. */
wmb();
-9
View File
@@ -669,15 +669,6 @@ handle_ist_exception:
je restore_all_guest
jmp compat_restore_all_guest
ENTRY(nmi_crash)
pushq $0
movl $TRAP_nmi,4(%rsp)
/* Set AC to reduce chance of further SMAP faults */
SAVE_ALL STAC
movq %rsp,%rdi
callq do_nmi_crash /* Does not return */
ud2
ENTRY(machine_check)
pushq $0
movl $TRAP_machine_check,4(%rsp)
-1
View File
@@ -530,7 +530,6 @@ DECLARE_TRAP_HANDLER(alignment_check);
void trap_nop(void);
void enable_nmis(void);
void noreturn do_nmi_crash(struct cpu_user_regs *regs);
void do_reserved_trap(struct cpu_user_regs *regs);
void syscall_enter(void);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.