Skip to content

Commit 8940ac9

Browse files
tlendackysuryasaimadhu
authored andcommitted
x86/realmode: Setup AP jump table
As part of the GHCB specification, the booting of APs under SEV-ES requires an AP jump table when transitioning from one layer of code to another (e.g. when going from UEFI to the OS). As a result, each layer that parks an AP must provide the physical address of an AP jump table to the next layer via the hypervisor. Upon booting of the kernel, read the AP jump table address from the hypervisor. Under SEV-ES, APs are started using the INIT-SIPI-SIPI sequence. Before issuing the first SIPI request for an AP, the start CS and IP is programmed into the AP jump table. Upon issuing the SIPI request, the AP will awaken and jump to that start CS:IP address. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> [ jroedel@suse.de: - Adapted to different code base - Moved AP table setup from SIPI sending path to real-mode setup code - Fix sparse warnings ] Co-developed-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/20200907131613.12703-67-joro@8bytes.org
1 parent bf5ff27 commit 8940ac9

4 files changed

Lines changed: 93 additions & 2 deletions

File tree

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ static inline u64 lower_bits(u64 val, unsigned int bits)
7373
return (val & mask);
7474
}
7575

76+
struct real_mode_header;
77+
enum stack_type;
78+
7679
/* Early IDT entry points for #VC handler */
7780
extern void vc_no_ghcb(void);
7881
extern void vc_boot_ghcb(void);
@@ -92,9 +95,11 @@ static __always_inline void sev_es_ist_exit(void)
9295
if (static_branch_unlikely(&sev_es_enable_key))
9396
__sev_es_ist_exit();
9497
}
98+
extern int sev_es_setup_ap_jump_table(struct real_mode_header *rmh);
9599
#else
96100
static inline void sev_es_ist_enter(struct pt_regs *regs) { }
97101
static inline void sev_es_ist_exit(void) { }
102+
static inline int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) { return 0; }
98103
#endif
99104

100105
#endif

arch/x86/include/uapi/asm/svm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
/* SEV-ES software-defined VMGEXIT events */
8585
#define SVM_VMGEXIT_MMIO_READ 0x80000001
8686
#define SVM_VMGEXIT_MMIO_WRITE 0x80000002
87+
#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005
88+
#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0
89+
#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1
8790
#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
8891

8992
#define SVM_EXIT_ERR -1

arch/x86/kernel/sev-es.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/mm.h>
2222

2323
#include <asm/cpu_entry_area.h>
24+
#include <asm/stacktrace.h>
2425
#include <asm/sev-es.h>
2526
#include <asm/insn-eval.h>
2627
#include <asm/fpu/internal.h>
@@ -214,6 +215,9 @@ static __always_inline void sev_es_put_ghcb(struct ghcb_state *state)
214215
}
215216
}
216217

218+
/* Needed in vc_early_forward_exception */
219+
void do_early_exception(struct pt_regs *regs, int trapnr);
220+
217221
static inline u64 sev_es_rd_ghcb_msr(void)
218222
{
219223
return __rdmsr(MSR_AMD64_SEV_ES_GHCB);
@@ -402,6 +406,71 @@ static bool vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt *ctxt,
402406
/* Include code shared with pre-decompression boot stage */
403407
#include "sev-es-shared.c"
404408

409+
static u64 get_jump_table_addr(void)
410+
{
411+
struct ghcb_state state;
412+
unsigned long flags;
413+
struct ghcb *ghcb;
414+
u64 ret = 0;
415+
416+
local_irq_save(flags);
417+
418+
ghcb = sev_es_get_ghcb(&state);
419+
420+
vc_ghcb_invalidate(ghcb);
421+
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_JUMP_TABLE);
422+
ghcb_set_sw_exit_info_1(ghcb, SVM_VMGEXIT_GET_AP_JUMP_TABLE);
423+
ghcb_set_sw_exit_info_2(ghcb, 0);
424+
425+
sev_es_wr_ghcb_msr(__pa(ghcb));
426+
VMGEXIT();
427+
428+
if (ghcb_sw_exit_info_1_is_valid(ghcb) &&
429+
ghcb_sw_exit_info_2_is_valid(ghcb))
430+
ret = ghcb->save.sw_exit_info_2;
431+
432+
sev_es_put_ghcb(&state);
433+
434+
local_irq_restore(flags);
435+
436+
return ret;
437+
}
438+
439+
int sev_es_setup_ap_jump_table(struct real_mode_header *rmh)
440+
{
441+
u16 startup_cs, startup_ip;
442+
phys_addr_t jump_table_pa;
443+
u64 jump_table_addr;
444+
u16 __iomem *jump_table;
445+
446+
jump_table_addr = get_jump_table_addr();
447+
448+
/* On UP guests there is no jump table so this is not a failure */
449+
if (!jump_table_addr)
450+
return 0;
451+
452+
/* Check if AP Jump Table is page-aligned */
453+
if (jump_table_addr & ~PAGE_MASK)
454+
return -EINVAL;
455+
456+
jump_table_pa = jump_table_addr & PAGE_MASK;
457+
458+
startup_cs = (u16)(rmh->trampoline_start >> 4);
459+
startup_ip = (u16)(rmh->sev_es_trampoline_start -
460+
rmh->trampoline_start);
461+
462+
jump_table = ioremap_encrypted(jump_table_pa, PAGE_SIZE);
463+
if (!jump_table)
464+
return -EIO;
465+
466+
writew(startup_ip, &jump_table[0]);
467+
writew(startup_cs, &jump_table[1]);
468+
469+
iounmap(jump_table);
470+
471+
return 0;
472+
}
473+
405474
static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt)
406475
{
407476
struct pt_regs *regs = ctxt->regs;

arch/x86/realmode/init.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <asm/realmode.h>
1010
#include <asm/tlbflush.h>
1111
#include <asm/crash.h>
12+
#include <asm/sev-es.h>
1213

1314
struct real_mode_header *real_mode_header;
1415
u32 *trampoline_cr4_features;
@@ -38,6 +39,19 @@ void __init reserve_real_mode(void)
3839
crash_reserve_low_1M();
3940
}
4041

42+
static void sme_sev_setup_real_mode(struct trampoline_header *th)
43+
{
44+
#ifdef CONFIG_AMD_MEM_ENCRYPT
45+
if (sme_active())
46+
th->flags |= TH_FLAGS_SME_ACTIVE;
47+
48+
if (sev_es_active()) {
49+
if (sev_es_setup_ap_jump_table(real_mode_header))
50+
panic("Failed to get/update SEV-ES AP Jump Table");
51+
}
52+
#endif
53+
}
54+
4155
static void __init setup_real_mode(void)
4256
{
4357
u16 real_mode_seg;
@@ -104,13 +118,13 @@ static void __init setup_real_mode(void)
104118
*trampoline_cr4_features = mmu_cr4_features;
105119

106120
trampoline_header->flags = 0;
107-
if (sme_active())
108-
trampoline_header->flags |= TH_FLAGS_SME_ACTIVE;
109121

110122
trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
111123
trampoline_pgd[0] = trampoline_pgd_entry.pgd;
112124
trampoline_pgd[511] = init_top_pgt[511].pgd;
113125
#endif
126+
127+
sme_sev_setup_real_mode(trampoline_header);
114128
}
115129

116130
/*

0 commit comments

Comments
 (0)