Skip to content

Commit 39336f4

Browse files
tlendackysuryasaimadhu
authored andcommitted
x86/efi: Add GHCB mappings when SEV-ES is active
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
1 parent 4ca68e0 commit 39336f4

4 files changed

Lines changed: 43 additions & 0 deletions

File tree

arch/x86/boot/compressed/sev-es.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
#include "misc.h"
1414

15+
#include <asm/pgtable_types.h>
1516
#include <asm/sev-es.h>
1617
#include <asm/trapnr.h>
1718
#include <asm/trap_pf.h>

arch/x86/include/asm/sev-es.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ static __always_inline void sev_es_nmi_complete(void)
102102
if (static_branch_unlikely(&sev_es_enable_key))
103103
__sev_es_nmi_complete();
104104
}
105+
extern int __init sev_es_efi_map_ghcbs(pgd_t *pgd);
105106
#else
106107
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
107108
static inline void sev_es_ist_exit(void) { }
108109
static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
109110
static inline void sev_es_nmi_complete(void) { }
111+
static inline int sev_es_efi_map_ghcbs(pgd_t *pgd) { return 0; }
110112
#endif
111113

112114
#endif

arch/x86/kernel/sev-es.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,36 @@ int sev_es_setup_ap_jump_table(struct real_mode_header *rmh)
491491
return 0;
492492
}
493493

494+
/*
495+
* This is needed by the OVMF UEFI firmware which will use whatever it finds in
496+
* the GHCB MSR as its GHCB to talk to the hypervisor. So make sure the per-cpu
497+
* runtime GHCBs used by the kernel are also mapped in the EFI page-table.
498+
*/
499+
int __init sev_es_efi_map_ghcbs(pgd_t *pgd)
500+
{
501+
struct sev_es_runtime_data *data;
502+
unsigned long address, pflags;
503+
int cpu;
504+
u64 pfn;
505+
506+
if (!sev_es_active())
507+
return 0;
508+
509+
pflags = _PAGE_NX | _PAGE_RW;
510+
511+
for_each_possible_cpu(cpu) {
512+
data = per_cpu(runtime_data, cpu);
513+
514+
address = __pa(&data->ghcb_page);
515+
pfn = address >> PAGE_SHIFT;
516+
517+
if (kernel_map_pages_in_pgd(pgd, pfn, address, 1, pflags))
518+
return 1;
519+
}
520+
521+
return 0;
522+
}
523+
494524
static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
495525
{
496526
struct pt_regs *regs = ctxt->regs;

arch/x86/platform/efi/efi_64.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <asm/realmode.h>
4848
#include <asm/time.h>
4949
#include <asm/pgalloc.h>
50+
#include <asm/sev-es.h>
5051

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

233+
/*
234+
* When SEV-ES is active, the GHCB as set by the kernel will be used
235+
* by firmware. Create a 1:1 unencrypted mapping for each GHCB.
236+
*/
237+
if (sev_es_efi_map_ghcbs(pgd)) {
238+
pr_err("Failed to create 1:1 mapping for the GHCBs!\n");
239+
return 1;
240+
}
241+
232242
/*
233243
* When making calls to the firmware everything needs to be 1:1
234244
* mapped and addressable with 32-bit pointers. Map the kernel

0 commit comments

Comments
 (0)