[RFC] Latched NMI handler

From: Mathieu Desnoyers
Date: Wed Dec 07 2011 - 20:51:54 EST


Hi!

Given the recent interest for latched NMI handler providing the ability
to fault and take exception within NMI handlers, I thought it would be
good if I wrote down the pseudo-code I got stucked in my brain since
this last discussion with Linus on the topic about a year ago. Feedback
is welcome, and hopefully it will be useful to Steven who is starting to
work a solution.

variables used:

stack-local int nmi_nest_count;
stack-local int nmi_latch;
__nmi_epilogue_begin (pointer to text)
__nmi_epilogue_end (pointer to text)
REAL_NMI_STACK: beginning of the stack used for real nmi handler
LATCHED_NMI_STACK: beginning of the stack used for latched nmi handler

int in_nmi_epilogue(void)
{
return (instruction_pointer() >= __nmi_epilogue_begin
&& instruction_pointer() < __nmi_epilogue_end);
}

int in_nmi(void)
{
return nmi_nest_count > 0;
}

/* Use REAL_NMI_STACK */
real_nmi_handler: /* always running with nmis disabled */
/*
* We disable interrupts to ensure we don't have to deal with IRQs
* when NMIs get re-enabled due to an iret from a fault/exception.
*/
local_irq_disable();
if (in_nmi_epilogue()) {
nmi_latch = 0;
/* set stack pointer to start of LATCHED_NMI_STACK */
goto latched_nmi_handler;
}
if (in_nmi()) {
nmi_latch = 1;
iret
}
nmi_nest_count++;
/* set stack pointer to start of LATCHED_NMI_STACK */
goto latched_nmi_handler;


/* Use LATCHED_NMI_STACK */
latched_nmi_handler: /* Can fault and reenable NMIs. */

[ execute actual system NMI handler, including faults, int3, ... ]

/*
* note: test nmi_latch and iret instruction are within the
* epilogue range to deal with latch test vs iret non-atomicity. If a
* real nmi nests over this range, it clears the nmi_latch flag and
* just restarts the latched nmi handler. No
* faults/exceptions/interrupts are permitted in this region, except
* for the real NMI and MCEs (TODO).
*/
__nmi_epilogue_begin:
/*
* here we are restarting the latched nmi handler if an nmi happened
* while nested within the nmi nest count.
*/
if (nmi_latch) {
nmi_latch = 0;
goto latched_nmi_handler;
}
nmi_nest_count--;
iret /* restores interrupts */
__nmi_epilogue_end:

--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/