mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 13:41:55 +00:00
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
This commit is contained in:
parent
87294bdb7b
commit
95d33bfaa3
@ -122,6 +122,7 @@ static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate)
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
void setup_ghcb(void);
|
||||||
#else
|
#else
|
||||||
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
|
||||||
static inline void sev_es_ist_exit(void) { }
|
static inline void sev_es_ist_exit(void) { }
|
||||||
@ -130,6 +131,7 @@ static inline void sev_es_nmi_complete(void) { }
|
|||||||
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
|
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
|
||||||
static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
|
static inline int pvalidate(unsigned long vaddr, bool rmp_psize, bool validate) { return 0; }
|
||||||
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
|
static inline int rmpadjust(unsigned long vaddr, bool rmp_psize, unsigned long attrs) { return 0; }
|
||||||
|
static inline void setup_ghcb(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#include <asm/uv/uv.h>
|
#include <asm/uv/uv.h>
|
||||||
#include <asm/sigframe.h>
|
#include <asm/sigframe.h>
|
||||||
#include <asm/traps.h>
|
#include <asm/traps.h>
|
||||||
|
#include <asm/sev.h>
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
@ -2124,6 +2125,9 @@ void cpu_init_exception_handling(void)
|
|||||||
|
|
||||||
load_TR_desc();
|
load_TR_desc();
|
||||||
|
|
||||||
|
/* GHCB needs to be setup to handle #VC. */
|
||||||
|
setup_ghcb();
|
||||||
|
|
||||||
/* Finally load the IDT */
|
/* Finally load the IDT */
|
||||||
load_current_idt();
|
load_current_idt();
|
||||||
}
|
}
|
||||||
|
@ -597,8 +597,10 @@ static void startup_64_load_idt(unsigned long physbase)
|
|||||||
void early_setup_idt(void)
|
void early_setup_idt(void)
|
||||||
{
|
{
|
||||||
/* VMM Communication Exception */
|
/* VMM Communication Exception */
|
||||||
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT))
|
if (IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)) {
|
||||||
|
setup_ghcb();
|
||||||
set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
|
set_bringup_idt_handler(bringup_idt_table, X86_TRAP_VC, vc_boot_ghcb);
|
||||||
|
}
|
||||||
|
|
||||||
bringup_idt_descr.address = (unsigned long)bringup_idt_table;
|
bringup_idt_descr.address = (unsigned long)bringup_idt_table;
|
||||||
native_load_idt(&bringup_idt_descr);
|
native_load_idt(&bringup_idt_descr);
|
||||||
|
@ -68,7 +68,7 @@ static u64 get_hv_features(void)
|
|||||||
return GHCB_MSR_HV_FT_RESP_VAL(val);
|
return GHCB_MSR_HV_FT_RESP_VAL(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __maybe_unused snp_register_ghcb_early(unsigned long paddr)
|
static void snp_register_ghcb_early(unsigned long paddr)
|
||||||
{
|
{
|
||||||
unsigned long pfn = paddr >> PAGE_SHIFT;
|
unsigned long pfn = paddr >> PAGE_SHIFT;
|
||||||
u64 val;
|
u64 val;
|
||||||
|
@ -41,7 +41,7 @@ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
|
|||||||
* Needs to be in the .data section because we need it NULL before bss is
|
* Needs to be in the .data section because we need it NULL before bss is
|
||||||
* cleared
|
* cleared
|
||||||
*/
|
*/
|
||||||
static struct ghcb __initdata *boot_ghcb;
|
static struct ghcb *boot_ghcb __section(".data");
|
||||||
|
|
||||||
/* Bitmap of SEV features supported by the hypervisor */
|
/* Bitmap of SEV features supported by the hypervisor */
|
||||||
static u64 sev_hv_features __ro_after_init;
|
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)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void snp_register_per_cpu_ghcb(void)
|
||||||
* This function runs on the first #VC exception after the kernel
|
|
||||||
* switched to virtual addresses.
|
|
||||||
*/
|
|
||||||
static bool __init sev_es_setup_ghcb(void)
|
|
||||||
{
|
{
|
||||||
|
struct sev_es_runtime_data *data;
|
||||||
|
struct ghcb *ghcb;
|
||||||
|
|
||||||
|
data = this_cpu_read(runtime_data);
|
||||||
|
ghcb = &data->ghcb_page;
|
||||||
|
|
||||||
|
snp_register_ghcb_early(__pa(ghcb));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_ghcb(void)
|
||||||
|
{
|
||||||
|
if (!cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT))
|
||||||
|
return;
|
||||||
|
|
||||||
/* First make sure the hypervisor talks a supported protocol. */
|
/* First make sure the hypervisor talks a supported protocol. */
|
||||||
if (!sev_es_negotiate_protocol())
|
if (!sev_es_negotiate_protocol())
|
||||||
return false;
|
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the runtime #VC exception handler is active. It uses
|
||||||
|
* the per-CPU GHCB page which is set up by sev_es_init_vc_handling().
|
||||||
|
*
|
||||||
|
* If SNP is active, register the per-CPU GHCB page so that the runtime
|
||||||
|
* exception handler can use it.
|
||||||
|
*/
|
||||||
|
if (initial_vc_handler == (unsigned long)kernel_exc_vmm_communication) {
|
||||||
|
if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
|
||||||
|
snp_register_per_cpu_ghcb();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the boot_ghcb. The first exception comes in before the bss
|
* Clear the boot_ghcb. The first exception comes in before the bss
|
||||||
@ -666,7 +690,9 @@ static bool __init sev_es_setup_ghcb(void)
|
|||||||
/* Alright - Make the boot-ghcb public */
|
/* Alright - Make the boot-ghcb public */
|
||||||
boot_ghcb = &boot_ghcb_page;
|
boot_ghcb = &boot_ghcb_page;
|
||||||
|
|
||||||
return true;
|
/* SNP guest requires that GHCB GPA must be registered. */
|
||||||
|
if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
|
||||||
|
snp_register_ghcb_early(__pa(&boot_ghcb_page));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
@ -1397,10 +1423,6 @@ bool __init handle_vc_boot_ghcb(struct pt_regs *regs)
|
|||||||
struct es_em_ctxt ctxt;
|
struct es_em_ctxt ctxt;
|
||||||
enum es_result result;
|
enum es_result result;
|
||||||
|
|
||||||
/* Do initial setup or terminate the guest */
|
|
||||||
if (unlikely(boot_ghcb == NULL && !sev_es_setup_ghcb()))
|
|
||||||
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SEV_ES_GEN_REQ);
|
|
||||||
|
|
||||||
vc_ghcb_invalidate(boot_ghcb);
|
vc_ghcb_invalidate(boot_ghcb);
|
||||||
|
|
||||||
result = vc_init_em_ctxt(&ctxt, regs, exit_code);
|
result = vc_init_em_ctxt(&ctxt, regs, exit_code);
|
||||||
|
Loading…
Reference in New Issue
Block a user