mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	x86/sev-es: Handle NMI State
When running under SEV-ES, the kernel has to tell the hypervisor when to open the NMI window again after an NMI was injected. This is done with an NMI-complete message to the hypervisor. Add code to the kernel's NMI handler to send this message right at the beginning of do_nmi(). This always allows nesting NMIs. [ bp: Mark __sev_es_nmi_complete() noinstr: vmlinux.o: warning: objtool: exc_nmi()+0x17: call to __sev_es_nmi_complete() leaves .noinstr.text section While at it, use __pa_nodebug() for the same reason due to CONFIG_DEBUG_VIRTUAL=y: vmlinux.o: warning: objtool: __sev_es_nmi_complete()+0xd9: call to __phys_addr() leaves .noinstr.text section ] Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/20200907131613.12703-71-joro@8bytes.org
This commit is contained in:
		
							parent
							
								
									094794f597
								
							
						
					
					
						commit
						4ca68e023b
					
				
					 4 changed files with 32 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -96,10 +96,17 @@ static __always_inline void sev_es_ist_exit(void)
 | 
			
		|||
		__sev_es_ist_exit();
 | 
			
		||||
}
 | 
			
		||||
extern int sev_es_setup_ap_jump_table(struct real_mode_header *rmh);
 | 
			
		||||
extern void __sev_es_nmi_complete(void);
 | 
			
		||||
static __always_inline void sev_es_nmi_complete(void)
 | 
			
		||||
{
 | 
			
		||||
	if (static_branch_unlikely(&sev_es_enable_key))
 | 
			
		||||
		__sev_es_nmi_complete();
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
 | 
			
		||||
static inline void sev_es_ist_exit(void) { }
 | 
			
		||||
static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
 | 
			
		||||
static inline void sev_es_nmi_complete(void) { }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@
 | 
			
		|||
/* SEV-ES software-defined VMGEXIT events */
 | 
			
		||||
#define SVM_VMGEXIT_MMIO_READ			0x80000001
 | 
			
		||||
#define SVM_VMGEXIT_MMIO_WRITE			0x80000002
 | 
			
		||||
#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003
 | 
			
		||||
#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004
 | 
			
		||||
#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005
 | 
			
		||||
#define SVM_VMGEXIT_SET_AP_JUMP_TABLE		0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -478,6 +478,12 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
 | 
			
		|||
{
 | 
			
		||||
	bool irq_state;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Re-enable NMIs right here when running as an SEV-ES guest. This might
 | 
			
		||||
	 * cause nested NMIs, but those can be handled safely.
 | 
			
		||||
	 */
 | 
			
		||||
	sev_es_nmi_complete();
 | 
			
		||||
 | 
			
		||||
	if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -408,6 +408,24 @@ static bool vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
 | 
			
		|||
/* Include code shared with pre-decompression boot stage */
 | 
			
		||||
#include "sev-es-shared.c"
 | 
			
		||||
 | 
			
		||||
void noinstr __sev_es_nmi_complete(void)
 | 
			
		||||
{
 | 
			
		||||
	struct ghcb_state state;
 | 
			
		||||
	struct ghcb *ghcb;
 | 
			
		||||
 | 
			
		||||
	ghcb = sev_es_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_es_put_ghcb(&state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u64 get_jump_table_addr(void)
 | 
			
		||||
{
 | 
			
		||||
	struct ghcb_state state;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue