Message ID | 20200824085511.7553-70-joro@8bytes.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | x86: SEV-ES Guest Support | expand |
On Mon, Aug 24, 2020 at 10:55:04AM +0200, Joerg Roedel wrote: > diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h > index 8f36ae021a7f..a19ce9681ec2 100644 > --- a/arch/x86/include/uapi/asm/svm.h > +++ b/arch/x86/include/uapi/asm/svm.h > @@ -84,6 +84,9 @@ > /* SEV-ES software-defined VMGEXIT events */ > #define SVM_VMGEXIT_MMIO_READ 0x80000001 > #define SVM_VMGEXIT_MMIO_WRITE 0x80000002 > +#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005 > +#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0 > +#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 ^^^^^^^^^^^^ One tab too many here. > #define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff > > #define SVM_EXIT_ERR -1 > diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c > index 28fe95ecd508..09a45ccd6c1d 100644 > --- a/arch/x86/kernel/sev-es.c > +++ b/arch/x86/kernel/sev-es.c > @@ -21,6 +21,8 @@ > #include <linux/mm.h> > > #include <asm/cpu_entry_area.h> > +#include <asm/stacktrace.h> > +#include <asm/realmode.h> > #include <asm/sev-es.h> > #include <asm/insn-eval.h> > #include <asm/fpu/internal.h> > @@ -219,6 +221,9 @@ static __always_inline void sev_es_put_ghcb(struct ghcb_state *state) > } > } > > +/* Needed in vc_early_vc_forward_exception */ vc_early_forward_exception() > +void do_early_exception(struct pt_regs *regs, int trapnr); > + > static inline u64 sev_es_rd_ghcb_msr(void) > { > return native_read_msr(MSR_AMD64_SEV_ES_GHCB); > @@ -407,6 +412,69 @@ static bool vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt *ctxt, > /* Include code shared with pre-decompression boot stage */ > #include "sev-es-shared.c" > > +static u64 sev_es_get_jump_table_addr(void) Static and used here only once - you can drop the previx "sev_es". > +{ > + struct ghcb_state state; > + unsigned long flags; > + struct ghcb *ghcb; > + u64 ret; > + > + local_irq_save(flags); > + > + ghcb = sev_es_get_ghcb(&state); > + > + vc_ghcb_invalidate(ghcb); > + ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_JUMP_TABLE); > + ghcb_set_sw_exit_info_1(ghcb, SVM_VMGEXIT_GET_AP_JUMP_TABLE); > + ghcb_set_sw_exit_info_2(ghcb, 0); > + > + sev_es_wr_ghcb_msr(__pa(ghcb)); > + VMGEXIT(); > + > + if (!ghcb_sw_exit_info_1_is_valid(ghcb) || > + !ghcb_sw_exit_info_2_is_valid(ghcb)) > + ret = 0; > + > + ret = ghcb->save.sw_exit_info_2; > + > + sev_es_put_ghcb(&state); > + > + local_irq_restore(flags); > + > + return ret; > +} > + > +int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) > +{ > + u16 startup_cs, startup_ip; > + phys_addr_t jump_table_pa; > + u64 jump_table_addr; > + u16 __iomem *jump_table; > + > + jump_table_addr = sev_es_get_jump_table_addr(); > + > + /* Check if AP Jump Table is non-zero and page-aligned */ > + if (!jump_table_addr || jump_table_addr & ~PAGE_MASK) > + return 0; I think you need to return !0 here so that the panic() below fires with a modified message: panic("Failed to get/update SEV-ES AP Jump Table"); or are we gonna boot an UP guest still? If not panic, at least a warning that at least some APs didn't come up...
On Mon, Aug 31, 2020 at 07:09:37PM +0200, Borislav Petkov wrote: > On Mon, Aug 24, 2020 at 10:55:04AM +0200, Joerg Roedel wrote: > > + /* Check if AP Jump Table is non-zero and page-aligned */ > > + if (!jump_table_addr || jump_table_addr & ~PAGE_MASK) > > + return 0; > > I think you need to return !0 here so that the panic() below fires with > a modified message: > > panic("Failed to get/update SEV-ES AP Jump Table"); > > or are we gonna boot an UP guest still? Right, this needs a !0 return value. This code runs once on the boot CPU before the kernel starts the secondary CPUs, so a panic() is the right thing to do if this fails. Regards, Joerg
diff --git a/arch/x86/include/asm/sev-es.h b/arch/x86/include/asm/sev-es.h index 2dd19932a60d..6ca38dc378e0 100644 --- a/arch/x86/include/asm/sev-es.h +++ b/arch/x86/include/asm/sev-es.h @@ -73,6 +73,9 @@ static inline u64 lower_bits(u64 val, unsigned int bits) return (val & mask); } +struct real_mode_header; +enum stack_type; + /* Early IDT entry points for #VC handler */ extern void vc_no_ghcb(void); extern bool handle_vc_boot_ghcb(struct pt_regs *regs); @@ -91,9 +94,11 @@ static __always_inline void sev_es_ist_exit(void) if (static_branch_unlikely(&sev_es_enable_key)) __sev_es_ist_exit(); } +extern int sev_es_setup_ap_jump_table(struct real_mode_header *rmh); #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; } #endif #endif diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h index 8f36ae021a7f..a19ce9681ec2 100644 --- a/arch/x86/include/uapi/asm/svm.h +++ b/arch/x86/include/uapi/asm/svm.h @@ -84,6 +84,9 @@ /* SEV-ES software-defined VMGEXIT events */ #define SVM_VMGEXIT_MMIO_READ 0x80000001 #define SVM_VMGEXIT_MMIO_WRITE 0x80000002 +#define SVM_VMGEXIT_AP_JUMP_TABLE 0x80000005 +#define SVM_VMGEXIT_SET_AP_JUMP_TABLE 0 +#define SVM_VMGEXIT_GET_AP_JUMP_TABLE 1 #define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff #define SVM_EXIT_ERR -1 diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c index 28fe95ecd508..09a45ccd6c1d 100644 --- a/arch/x86/kernel/sev-es.c +++ b/arch/x86/kernel/sev-es.c @@ -21,6 +21,8 @@ #include <linux/mm.h> #include <asm/cpu_entry_area.h> +#include <asm/stacktrace.h> +#include <asm/realmode.h> #include <asm/sev-es.h> #include <asm/insn-eval.h> #include <asm/fpu/internal.h> @@ -219,6 +221,9 @@ static __always_inline void sev_es_put_ghcb(struct ghcb_state *state) } } +/* Needed in vc_early_vc_forward_exception */ +void do_early_exception(struct pt_regs *regs, int trapnr); + static inline u64 sev_es_rd_ghcb_msr(void) { return native_read_msr(MSR_AMD64_SEV_ES_GHCB); @@ -407,6 +412,69 @@ static bool vc_slow_virt_to_phys(struct ghcb *ghcb, struct es_em_ctxt *ctxt, /* Include code shared with pre-decompression boot stage */ #include "sev-es-shared.c" +static u64 sev_es_get_jump_table_addr(void) +{ + struct ghcb_state state; + unsigned long flags; + struct ghcb *ghcb; + u64 ret; + + local_irq_save(flags); + + ghcb = sev_es_get_ghcb(&state); + + vc_ghcb_invalidate(ghcb); + ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_AP_JUMP_TABLE); + ghcb_set_sw_exit_info_1(ghcb, SVM_VMGEXIT_GET_AP_JUMP_TABLE); + ghcb_set_sw_exit_info_2(ghcb, 0); + + sev_es_wr_ghcb_msr(__pa(ghcb)); + VMGEXIT(); + + if (!ghcb_sw_exit_info_1_is_valid(ghcb) || + !ghcb_sw_exit_info_2_is_valid(ghcb)) + ret = 0; + + ret = ghcb->save.sw_exit_info_2; + + sev_es_put_ghcb(&state); + + local_irq_restore(flags); + + return ret; +} + +int sev_es_setup_ap_jump_table(struct real_mode_header *rmh) +{ + u16 startup_cs, startup_ip; + phys_addr_t jump_table_pa; + u64 jump_table_addr; + u16 __iomem *jump_table; + + jump_table_addr = sev_es_get_jump_table_addr(); + + /* Check if AP Jump Table is non-zero and page-aligned */ + if (!jump_table_addr || jump_table_addr & ~PAGE_MASK) + return 0; + + jump_table_pa = jump_table_addr & PAGE_MASK; + + startup_cs = (u16)(rmh->trampoline_start >> 4); + startup_ip = (u16)(rmh->sev_es_trampoline_start - + rmh->trampoline_start); + + jump_table = ioremap_encrypted(jump_table_pa, PAGE_SIZE); + if (!jump_table) + return -EIO; + + writew(startup_ip, &jump_table[0]); + writew(startup_cs, &jump_table[1]); + + iounmap(jump_table); + + return 0; +} + static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) { struct pt_regs *regs = ctxt->regs; diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 1ed1208931e0..61a52b925d15 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -9,6 +9,7 @@ #include <asm/realmode.h> #include <asm/tlbflush.h> #include <asm/crash.h> +#include <asm/sev-es.h> struct real_mode_header *real_mode_header; u32 *trampoline_cr4_features; @@ -38,6 +39,19 @@ void __init reserve_real_mode(void) crash_reserve_low_1M(); } +static void sme_sev_setup_real_mode(struct trampoline_header *th) +{ +#ifdef CONFIG_AMD_MEM_ENCRYPT + if (sme_active()) + th->flags |= TH_FLAGS_SME_ACTIVE; + + if (sev_es_active()) { + if (sev_es_setup_ap_jump_table(real_mode_header)) + panic("Failed to update SEV-ES AP Jump Table"); + } +#endif +} + static void __init setup_real_mode(void) { u16 real_mode_seg; @@ -104,13 +118,13 @@ static void __init setup_real_mode(void) *trampoline_cr4_features = mmu_cr4_features; trampoline_header->flags = 0; - if (sme_active()) - trampoline_header->flags |= TH_FLAGS_SME_ACTIVE; trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); trampoline_pgd[0] = trampoline_pgd_entry.pgd; trampoline_pgd[511] = init_top_pgt[511].pgd; #endif + + sme_sev_setup_real_mode(trampoline_header); } /*