Skip to content

Commit 094794f

Browse files
joergroedelsuryasaimadhu
authored andcommitted
x86/sev-es: Support CPU offline/online
Add a play_dead handler when running under SEV-ES. This is needed because the hypervisor can't deliver an SIPI request to restart the AP. Instead, the kernel has to issue a VMGEXIT to halt the VCPU until the hypervisor wakes it up again. Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/20200907131613.12703-70-joro@8bytes.org
1 parent 3ecacdb commit 094794f

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

arch/x86/include/uapi/asm/svm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
/* SEV-ES software-defined VMGEXIT events */
8585
#define SVM_VMGEXIT_MMIO_READ 0x80000001
8686
#define SVM_VMGEXIT_MMIO_WRITE 0x80000002
87+
#define SVM_VMGEXIT_AP_HLT_LOOP 0x80000004
8788
#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005
8889
#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0
8990
#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1

arch/x86/kernel/sev-es.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include <asm/realmode.h>
3030
#include <asm/traps.h>
3131
#include <asm/svm.h>
32+
#include <asm/smp.h>
33+
#include <asm/cpu.h>
3234

3335
#define DR7_RESET_VALUE 0x400
3436

@@ -518,6 +520,65 @@ static bool __init sev_es_setup_ghcb(void)
518520
return true;
519521
}
520522

523+
#ifdef CONFIG_HOTPLUG_CPU
524+
static void sev_es_ap_hlt_loop(void)
525+
{
526+
struct ghcb_state state;
527+
struct ghcb *ghcb;
528+
529+
ghcb = sev_es_get_ghcb(&state);
530+
531+
while (true) {
532+
vc_ghcb_invalidate(ghcb);
533+
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_HLT_LOOP);
534+
ghcb_set_sw_exit_info_1(ghcb, 0);
535+
ghcb_set_sw_exit_info_2(ghcb, 0);
536+
537+
sev_es_wr_ghcb_msr(__pa(ghcb));
538+
VMGEXIT();
539+
540+
/* Wakeup signal? */
541+
if (ghcb_sw_exit_info_2_is_valid(ghcb) &&
542+
ghcb->save.sw_exit_info_2)
543+
break;
544+
}
545+
546+
sev_es_put_ghcb(&state);
547+
}
548+
549+
/*
550+
* Play_dead handler when running under SEV-ES. This is needed because
551+
* the hypervisor can't deliver an SIPI request to restart the AP.
552+
* Instead the kernel has to issue a VMGEXIT to halt the VCPU until the
553+
* hypervisor wakes it up again.
554+
*/
555+
static void sev_es_play_dead(void)
556+
{
557+
play_dead_common();
558+
559+
/* IRQs now disabled */
560+
561+
sev_es_ap_hlt_loop();
562+
563+
/*
564+
* If we get here, the VCPU was woken up again. Jump to CPU
565+
* startup code to get it back online.
566+
*/
567+
start_cpu0();
568+
}
569+
#else /* CONFIG_HOTPLUG_CPU */
570+
#define sev_es_play_dead native_play_dead
571+
#endif /* CONFIG_HOTPLUG_CPU */
572+
573+
#ifdef CONFIG_SMP
574+
static void __init sev_es_setup_play_dead(void)
575+
{
576+
smp_ops.play_dead = sev_es_play_dead;
577+
}
578+
#else
579+
static inline void sev_es_setup_play_dead(void) { }
580+
#endif
581+
521582
static void __init alloc_runtime_data(int cpu)
522583
{
523584
struct sev_es_runtime_data *data;
@@ -566,6 +627,8 @@ void __init sev_es_init_vc_handling(void)
566627
setup_vc_stacks(cpu);
567628
}
568629

630+
sev_es_setup_play_dead();
631+
569632
/* Secondary CPUs use the runtime #VC handler */
570633
initial_vc_handler = (unsigned long)safe_stack_exc_vmm_communication;
571634
}

0 commit comments

Comments
 (0)