// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Memory Encryption Support
*
* Copyright ( C ) 2019 SUSE
*
* Author : Joerg Roedel < jroedel @ suse . de >
*/
#define pr_fmt(fmt) "SEV: " fmt
#include <linux/bug.h>
#include <linux/kernel.h>
#include <asm /cpu_entry_area.h>
#include <asm /msr.h>
#include <asm /ptrace.h>
#include <asm /sev.h>
#include <asm /sev-internal.h>
static __always_inline bool on_vc_stack(struct pt_regs *regs)
{
unsigned long sp = regs->sp;
/* User-mode RSP is not trusted */
if (user_mode(regs))
return false ;
/* SYSCALL gap still has user-mode RSP */
if (ip_within_syscall_gap(regs))
return false ;
return ((sp >= __this_cpu_ist_bottom_va(VC)) && (sp < __this_cpu_ist_top_va(VC)));
}
/*
* This function handles the case when an NMI is raised in the # VC
* exception handler entry code , before the # VC handler has switched off
* its IST stack . In this case , the IST entry for # VC must be adjusted ,
* so that any nested # VC exception will not overwrite the stack
* contents of the interrupted # VC handler .
*
* The IST entry is adjusted unconditionally so that it can be also be
* unconditionally adjusted back in _ _ sev_es_ist_exit ( ) . Otherwise a
* nested sev_es_ist_exit ( ) call may adjust back the IST entry too
* early .
*
* The _ _ sev_es_ist_enter ( ) and _ _ sev_es_ist_exit ( ) functions always run
* on the NMI IST stack , as they are only called from NMI handling code
* right now .
*/
void noinstr __sev_es_ist_enter(struct pt_regs *regs)
{
unsigned long old_ist, new_ist;
/* Read old IST entry */
new_ist = old_ist = __this_cpu_read(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC]);
/*
* If NMI happened while on the # VC IST stack , set the new IST
* value below regs - > sp , so that the interrupted stack frame is
* not overwritten by subsequent # VC exceptions .
*/
if (on_vc_stack(regs))
new_ist = regs->sp;
/*
* Reserve additional 8 bytes and store old IST value so this
* adjustment can be unrolled in _ _ sev_es_ist_exit ( ) .
*/
new_ist -= sizeof (old_ist);
*(unsigned long *)new_ist = old_ist;
/* Set new IST entry */
this_cpu_write(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC], new_ist);
}
void noinstr __sev_es_ist_exit(void )
{
unsigned long ist;
/* Read IST entry */
ist = __this_cpu_read(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC]);
if (WARN_ON(ist == __this_cpu_ist_top_va(VC)))
return ;
/* Read back old IST entry and write it to the TSS */
this_cpu_write(cpu_tss_rw.x86_tss.ist[IST_INDEX_VC], *(unsigned long *)ist);
}
void noinstr __sev_es_nmi_complete(void )
{
struct ghcb_state state;
struct ghcb *ghcb;
ghcb = __sev_get_ghcb(&state);
vc_ghcb_invalidate(ghcb);
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_NMI_COMPLETE);
ghcb_set_sw_exit_info_1(ghcb, 0 );
ghcb_set_sw_exit_info_2(ghcb, 0 );
sev_es_wr_ghcb_msr(__pa_nodebug(ghcb));
VMGEXIT();
__sev_put_ghcb(&state);
}
Messung V0.5 in Prozent C=91 H=73 G=82
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland