Skip to content

Commit

Permalink
x86/efi: Add GHCB mappings when SEV-ES is active
Browse files Browse the repository at this point in the history
Calling down to EFI runtime services can result in the firmware
performing VMGEXIT calls. The firmware is likely to use the GHCB of the
OS (e.g., for setting EFI variables), so each GHCB in the system needs
to be identity-mapped in the EFI page tables, as unencrypted, to avoid
page faults.

Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
[ jroedel@suse.de: Moved GHCB mapping loop to sev-es.c ]
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lkml.kernel.org/r/20200907131613.12703-72-joro@8bytes.org
  • Loading branch information
Tom Lendacky authored and Borislav Petkov committed Sep 10, 2020
1 parent 4ca68e0 commit 39336f4
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/x86/boot/compressed/sev-es.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
#include "misc.h"

#include <asm/pgtable_types.h>
#include <asm/sev-es.h>
#include <asm/trapnr.h>
#include <asm/trap_pf.h>
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/sev-es.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ static __always_inline void sev_es_nmi_complete(void)
if (static_branch_unlikely(&sev_es_enable_key))
__sev_es_nmi_complete();
}
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
#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) { }
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
#endif

#endif
30 changes: 30 additions & 0 deletions arch/x86/kernel/sev-es.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,36 @@ int sev_es_setup_ap_jump_table(struct real_mode_header *rmh)
return 0;
}

/*
* This is needed by the OVMF UEFI firmware which will use whatever it finds in
* the GHCB MSR as its GHCB to talk to the hypervisor. So make sure the per-cpu
* runtime GHCBs used by the kernel are also mapped in the EFI page-table.
*/
int __init sev_es_efi_map_ghcbs(pgd_t *pgd)
{
struct sev_es_runtime_data *data;
unsigned long address, pflags;
int cpu;
u64 pfn;

if (!sev_es_active())
return 0;

pflags = _PAGE_NX | _PAGE_RW;

for_each_possible_cpu(cpu) {
data = per_cpu(runtime_data, cpu);

address = __pa(&data->ghcb_page);
pfn = address >> PAGE_SHIFT;

if (kernel_map_pages_in_pgd(pgd, pfn, address, 1, pflags))
return 1;
}

return 0;
}

static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
{
struct pt_regs *regs = ctxt->regs;
Expand Down
10 changes: 10 additions & 0 deletions arch/x86/platform/efi/efi_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <asm/realmode.h>
#include <asm/time.h>
#include <asm/pgalloc.h>
#include <asm/sev-es.h>

/*
* We allocate runtime services regions top-down, starting from -4G, i.e.
Expand Down Expand Up @@ -229,6 +230,15 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
return 1;
}

/*
* When SEV-ES is active, the GHCB as set by the kernel will be used
* by firmware. Create a 1:1 unencrypted mapping for each GHCB.
*/
if (sev_es_efi_map_ghcbs(pgd)) {
pr_err("Failed to create 1:1 mapping for the GHCBs!\n");
return 1;
}

/*
* When making calls to the firmware everything needs to be 1:1
* mapped and addressable with 32-bit pointers. Map the kernel
Expand Down

0 comments on commit 39336f4

Please sign in to comment.