From: Joerg Roedel
Install an exception handler for #VC exception that uses a GHCB. Also
add the infrastructure for handling different exit-codes by decoding
the instruction that caused the exception and error handling.
Signed-off-by: Joerg Roedel
---
arch/x86/Kconfig | 1 +
arch/x86/boot/compressed/idt_64.c | 4 +
arch/x86/boot/compressed/idt_handlers_64.S | 1 +
arch/x86/boot/compressed/misc.h| 1 +
arch/x86/boot/compressed/sev-es.c | 91 +++
arch/x86/include/asm/sev-es.h | 33
arch/x86/include/uapi/asm/svm.h| 1 +
arch/x86/kernel/sev-es-shared.c| 171 +
8 files changed, 303 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index beea77046f9b..c12347492589 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1526,6 +1526,7 @@ config AMD_MEM_ENCRYPT
select DYNAMIC_PHYSICAL_MASK
select ARCH_USE_MEMREMAP_PROT
select ARCH_HAS_FORCE_DMA_UNENCRYPTED
+ select INSTRUCTION_DECODER
---help---
Say yes to enable support for the encryption of system memory.
This requires an AMD processor that supports Secure Memory
diff --git a/arch/x86/boot/compressed/idt_64.c
b/arch/x86/boot/compressed/idt_64.c
index bdd20dfd1fd0..eebb2f857dac 100644
--- a/arch/x86/boot/compressed/idt_64.c
+++ b/arch/x86/boot/compressed/idt_64.c
@@ -45,5 +45,9 @@ void load_stage2_idt(void)
set_idt_entry(X86_TRAP_PF, boot_pf_handler);
+#ifdef CONFIG_AMD_MEM_ENCRYPT
+ set_idt_entry(X86_TRAP_VC, boot_stage2_vc_handler);
+#endif
+
load_boot_idt(_idt_desc);
}
diff --git a/arch/x86/boot/compressed/idt_handlers_64.S
b/arch/x86/boot/compressed/idt_handlers_64.S
index 330eb4e5c8b3..3c71a11beee0 100644
--- a/arch/x86/boot/compressed/idt_handlers_64.S
+++ b/arch/x86/boot/compressed/idt_handlers_64.S
@@ -74,4 +74,5 @@ EXCEPTION_HANDLER boot_pf_handler do_boot_page_fault
error_code=1
#ifdef CONFIG_AMD_MEM_ENCRYPT
EXCEPTION_HANDLER boot_stage1_vc_handler no_ghcb_vc_handler error_code=1
+EXCEPTION_HANDLER boot_stage2_vc_handler boot_vc_handler error_code=1
#endif
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 42f68a858a35..567d71ab5ed9 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -143,5 +143,6 @@ extern struct desc_ptr boot_idt_desc;
/* IDT Entry Points */
void boot_pf_handler(void);
void boot_stage1_vc_handler(void);
+void boot_stage2_vc_handler(void);
#endif /* BOOT_COMPRESSED_MISC_H */
diff --git a/arch/x86/boot/compressed/sev-es.c
b/arch/x86/boot/compressed/sev-es.c
index 8d13121a8cf2..02fb6f57128b 100644
--- a/arch/x86/boot/compressed/sev-es.c
+++ b/arch/x86/boot/compressed/sev-es.c
@@ -8,12 +8,16 @@
#include
#include
+#include
#include
#include
#include
#include "misc.h"
+struct ghcb boot_ghcb_page __aligned(PAGE_SIZE);
+struct ghcb *boot_ghcb;
+
static inline u64 read_ghcb_msr(void)
{
unsigned long low, high;
@@ -35,8 +39,95 @@ static inline void write_ghcb_msr(u64 val)
"a"(low), "d" (high) : "memory");
}
+static enum es_result es_fetch_insn_byte(struct es_em_ctxt *ctxt,
+unsigned int offset,
+char *buffer)
+{
+ char *rip = (char *)ctxt->regs->ip;
+
+ buffer[offset] = rip[offset];
+
+ return ES_OK;
+}
+
+static enum es_result es_write_mem(struct es_em_ctxt *ctxt,
+ void *dst, char *buf, size_t size)
+{
+ memcpy(dst, buf, size);
+
+ return ES_OK;
+}
+
+static enum es_result es_read_mem(struct es_em_ctxt *ctxt,
+ void *src, char *buf, size_t size)
+{
+ memcpy(buf, src, size);
+
+ return ES_OK;
+}
+
#undef __init
+#undef __pa
#define __init
+#define __pa(x)((unsigned long)(x))
+
+#define __BOOT_COMPRESSED
+
+/* Basic instruction decoding support needed */
+#include "../../lib/inat.c"
+#include "../../lib/insn.c"
/* Include code for early handlers */
#include "../../kernel/sev-es-shared.c"
+
+static bool setup_ghcb(void)
+{
+ if (!sev_es_negotiate_protocol())
+ terminate(GHCB_SEV_ES_REASON_PROTOCOL_UNSUPPORTED);
+
+ if (set_page_decrypted((unsigned long)_ghcb_page))
+ return false;
+
+ /* Page is now mapped decrypted, clear it */
+ memset(_ghcb_page, 0, sizeof(boot_ghcb_page));
+
+ boot_ghcb = _ghcb_page;
+
+ /* Initialize lookup tables for the instruction decoder */
+ inat_init_tables();
+
+ return true;
+}
+
+void boot_vc_handler(struct pt_regs *regs)
+{
+ unsigned long exit_code = regs->orig_ax;
+ struct es_em_ctxt ctxt;
+ enum es_result result;
+
+ if (!boot_ghcb && !setup_ghcb())
+ terminate(GHCB_SEV_ES_REASON_GENERAL_REQUEST);
+
+