Skip to content

Commit

Permalink
x86/fred: Add a NMI entry stub for FRED
Browse files Browse the repository at this point in the history
On a FRED system, NMIs nest both with themselves and faults, transient
information is saved into the stack frame, and NMI unblocking only
happens when the stack frame indicates that so should happen.

Thus, the NMI entry stub for FRED is really quite small...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Xin Li <xin3.li@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Tested-by: Shan Kang <shan.kang@intel.com>
Link: https://lore.kernel.org/r/20231216063139.25567-1-xin3.li@intel.com
  • Loading branch information
H. Peter Anvin (Intel) authored and Borislav Petkov (AMD) committed Jan 31, 2024
1 parent 99fcc96 commit f8b8ee4
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions arch/x86/kernel/nmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <asm/nospec-branch.h>
#include <asm/microcode.h>
#include <asm/sev.h>
#include <asm/fred.h>

#define CREATE_TRACE_POINTS
#include <trace/events/nmi.h>
Expand Down Expand Up @@ -651,6 +652,47 @@ void nmi_backtrace_stall_check(const struct cpumask *btp)

#endif

#ifdef CONFIG_X86_FRED
/*
* With FRED, CR2/DR6 is pushed to #PF/#DB stack frame during FRED
* event delivery, i.e., there is no problem of transient states.
* And NMI unblocking only happens when the stack frame indicates
* that so should happen.
*
* Thus, the NMI entry stub for FRED is really straightforward and
* as simple as most exception handlers. As such, #DB is allowed
* during NMI handling.
*/
DEFINE_FREDENTRY_NMI(exc_nmi)
{
irqentry_state_t irq_state;

if (arch_cpu_is_offline(smp_processor_id())) {
if (microcode_nmi_handler_enabled())
microcode_offline_nmi_handler();
return;
}

/*
* Save CR2 for eventual restore to cover the case where the NMI
* hits the VMENTER/VMEXIT region where guest CR2 is life. This
* prevents guest state corruption in case that the NMI handler
* takes a page fault.
*/
this_cpu_write(nmi_cr2, read_cr2());

irq_state = irqentry_nmi_enter(regs);

inc_irq_stat(__nmi_count);
default_do_nmi(regs);

irqentry_nmi_exit(regs, irq_state);

if (unlikely(this_cpu_read(nmi_cr2) != read_cr2()))
write_cr2(this_cpu_read(nmi_cr2));
}
#endif

void stop_nmi(void)
{
ignore_nmis++;
Expand Down

0 comments on commit f8b8ee4

Please sign in to comment.