Skip to content

Commit

Permalink
x86/sev-es: Support CPU offline/online
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Joerg Roedel authored and Borislav Petkov committed Sep 9, 2020
1 parent 3ecacdb commit 094794f
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/uapi/asm/svm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_AP_HLT_LOOP 0x80000004
#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005
#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0
#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1
Expand Down
63 changes: 63 additions & 0 deletions arch/x86/kernel/sev-es.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <asm/realmode.h>
#include <asm/traps.h>
#include <asm/svm.h>
#include <asm/smp.h>
#include <asm/cpu.h>

#define DR7_RESET_VALUE 0x400

Expand Down Expand Up @@ -518,6 +520,65 @@ static bool __init sev_es_setup_ghcb(void)
return true;
}

#ifdef CONFIG_HOTPLUG_CPU
static void sev_es_ap_hlt_loop(void)
{
struct ghcb_state state;
struct ghcb *ghcb;

ghcb = sev_es_get_ghcb(&state);

while (true) {
vc_ghcb_invalidate(ghcb);
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_HLT_LOOP);
ghcb_set_sw_exit_info_1(ghcb, 0);
ghcb_set_sw_exit_info_2(ghcb, 0);

sev_es_wr_ghcb_msr(__pa(ghcb));
VMGEXIT();

/* Wakeup signal? */
if (ghcb_sw_exit_info_2_is_valid(ghcb) &&
ghcb->save.sw_exit_info_2)
break;
}

sev_es_put_ghcb(&state);
}

/*
* 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.
*/
static void sev_es_play_dead(void)
{
play_dead_common();

/* IRQs now disabled */

sev_es_ap_hlt_loop();

/*
* If we get here, the VCPU was woken up again. Jump to CPU
* startup code to get it back online.
*/
start_cpu0();
}
#else /* CONFIG_HOTPLUG_CPU */
#define sev_es_play_dead native_play_dead
#endif /* CONFIG_HOTPLUG_CPU */

#ifdef CONFIG_SMP
static void __init sev_es_setup_play_dead(void)
{
smp_ops.play_dead = sev_es_play_dead;
}
#else
static inline void sev_es_setup_play_dead(void) { }
#endif

static void __init alloc_runtime_data(int cpu)
{
struct sev_es_runtime_data *data;
Expand Down Expand Up @@ -566,6 +627,8 @@ void __init sev_es_init_vc_handling(void)
setup_vc_stacks(cpu);
}

sev_es_setup_play_dead();

/* Secondary CPUs use the runtime #VC handler */
initial_vc_handler = (unsigned long)safe_stack_exc_vmm_communication;
}
Expand Down

0 comments on commit 094794f

Please sign in to comment.