Skip to content

Commit 95d33bf

Browse files
codomaniasuryasaimadhu
authored andcommitted
x86/sev: Register GHCB memory when SEV-SNP is active
The SEV-SNP guest is required by the GHCB spec to register the GHCB's Guest Physical Address (GPA). This is because the hypervisor may prefer that a guest uses a consistent and/or specific GPA for the GHCB associated with a vCPU. For more information, see the GHCB specification section "GHCB GPA Registration". [ bp: Cleanup comments. ] Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lore.kernel.org/r/20220307213356.2797205-18-brijesh.singh@amd.com
1 parent 87294bd commit 95d33bf

File tree

5 files changed

+44
-14
lines changed

5 files changed

+44
-14
lines changed

arch/x86/include/asm/sev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
122122

123123
return rc;
124124
}
125+
void setup_ghcb(void);
125126
#else
126127
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
127128
static inline void sev_es_ist_exit(void) { }
@@ -130,6 +131,7 @@ static inline void sev_es_nmi_complete(void) { }
130131
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
131132
static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
132133
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
134+
static inline void setup_ghcb(void) { }
133135
#endif
134136

135137
#endif

arch/x86/kernel/cpu/common.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include <asm/uv/uv.h>
6161
#include <asm/sigframe.h>
6262
#include <asm/traps.h>
63+
#include <asm/sev.h>
6364

6465
#include "cpu.h"
6566

@@ -2124,6 +2125,9 @@ void cpu_init_exception_handling(void)
21242125

21252126
load_TR_desc();
21262127

2128+
/* GHCB needs to be setup to handle #VC. */
2129+
setup_ghcb();
2130+
21272131
/* Finally load the IDT */
21282132
load_current_idt();
21292133
}

arch/x86/kernel/head64.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,8 +597,10 @@ static void startup_64_load_idt(unsigned long physbase)
597597
void early_setup_idt(void)
598598
{
599599
/* VMM Communication Exception */
600-
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
600+
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
601+
setup_ghcb();
601602
set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
603+
}
602604

603605
bringup_idt_descr.address = (unsigned long)bringup_idt_table;
604606
native_load_idt(&bringup_idt_descr);

arch/x86/kernel/sev-shared.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static u64 get_hv_features(void)
6868
return GHCB_MSR_HV_FT_RESP_VAL(val);
6969
}
7070

71-
static void __maybe_unused snp_register_ghcb_early(unsigned long paddr)
71+
static void snp_register_ghcb_early(unsigned long paddr)
7272
{
7373
unsigned long pfn = paddr >> PAGE_SHIFT;
7474
u64 val;

arch/x86/kernel/sev.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
4141
* Needs to be in the .data section because we need it NULL before bss is
4242
* cleared
4343
*/
44-
static struct ghcb __initdata *boot_ghcb;
44+
static struct ghcb *boot_ghcb __section(".data");
4545

4646
/* Bitmap of SEV features supported by the hypervisor */
4747
static u64 sev_hv_features __ro_after_init;
@@ -647,15 +647,39 @@ static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
647647
return ret;
648648
}
649649

650-
/*
651-
* This function runs on the first #VC exception after the kernel
652-
* switched to virtual addresses.
653-
*/
654-
static bool __init sev_es_setup_ghcb(void)
650+
static void snp_register_per_cpu_ghcb(void)
655651
{
652+
struct sev_es_runtime_data *data;
653+
struct ghcb *ghcb;
654+
655+
data = this_cpu_read(runtime_data);
656+
ghcb = &data->ghcb_page;
657+
658+
snp_register_ghcb_early(__pa(ghcb));
659+
}
660+
661+
void setup_ghcb(void)
662+
{
663+
if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
664+
return;
665+
656666
/* First make sure the hypervisor talks a supported protocol. */
657667
if (!sev_es_negotiate_protocol())
658-
return false;
668+
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
669+
670+
/*
671+
* Check whether the runtime #VC exception handler is active. It uses
672+
* the per-CPU GHCB page which is set up by sev_es_init_vc_handling().
673+
*
674+
* If SNP is active, register the per-CPU GHCB page so that the runtime
675+
* exception handler can use it.
676+
*/
677+
if (initial_vc_handler == (unsigned long)kernel_exc_vmm_communication) {
678+
if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
679+
snp_register_per_cpu_ghcb();
680+
681+
return;
682+
}
659683

660684
/*
661685
* Clear the boot_ghcb. The first exception comes in before the bss
@@ -666,7 +690,9 @@ static bool __init sev_es_setup_ghcb(void)
666690
/* Alright - Make the boot-ghcb public */
667691
boot_ghcb = &boot_ghcb_page;
668692

669-
return true;
693+
/* SNP guest requires that GHCB GPA must be registered. */
694+
if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
695+
snp_register_ghcb_early(__pa(&boot_ghcb_page));
670696
}
671697

672698
#ifdef CONFIG_HOTPLUG_CPU
@@ -1397,10 +1423,6 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
13971423
struct es_em_ctxt ctxt;
13981424
enum es_result result;
13991425

1400-
/* Do initial setup or terminate the guest */
1401-
if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb()))
1402-
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
1403-
14041426
vc_ghcb_invalidate(boot_ghcb);
14051427

14061428
result = vc_init_em_ctxt(&ctxt, regs, exit_code);

0 commit comments

Comments
 (0)