@@ -41,6 +41,9 @@ OBJDIRS += $(LIBFDT_objdir)
# EFI App
ifeq ($(CONFIG_EFI),y)
EFI_CFLAGS := -DCONFIG_EFI -DCONFIG_RELOC
+ifeq ($(AMDSEV_EFI_VC),y)
+EFI_CFLAGS += -DAMDSEV_EFI_VC
+endif
# The following CFLAGS and LDFLAGS come from:
# - GNU-EFI/Makefile.defaults
# - GNU-EFI/apps/Makefile
@@ -32,6 +32,12 @@ enable_dump=no
page_size=
earlycon=
efi=
+# For AMD SEV-ES, the tests build to use their own #VC exception handler
+# by default, instead of using the one installed by UEFI. This ensures
+# that the tests do not depend on UEFI state after ExitBootServices.
+# To continue using the UEFI #VC handler, ./configure can be run with
+# --amdsev-efi-vc.
+amdsev_efi_vc=
# Enable -Werror by default for git repositories only (i.e. developer builds)
if [ -e "$srcdir"/.git ]; then
@@ -89,6 +95,8 @@ usage() {
--[enable|disable]-efi Boot and run from UEFI (disabled by default, x86_64 and arm64 only)
--[enable|disable]-werror
Select whether to compile with the -Werror compiler flag
+ --amdsev-efi-vc Use UEFI-provided #VC handlers on AMD SEV/ES. Requires
+ --enable-efi.
EOF
exit 1
}
@@ -174,6 +182,9 @@ while [[ "$1" = -* ]]; do
--disable-werror)
werror=
;;
+ --amdsev-efi-vc)
+ amdsev_efi_vc=y
+ ;;
--help)
usage
;;
@@ -249,8 +260,17 @@ elif [ "$processor" = "arm" ]; then
processor="cortex-a15"
fi
+if [ "$amdsev_efi_vc" ] && [ "$arch" != "x86_64" ]; then
+ echo "--amdsev-efi-vc requires arch x86_64."
+ usage
+fi
+
if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
testdir=x86
+ if [ "$amdsev_efi_vc" ] && [ -z "$efi" ]; then
+ echo "--amdsev-efi-vc requires --enable-efi."
+ usage
+ fi
elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
testdir=arm
if [ "$target" = "qemu" ]; then
@@ -413,6 +433,7 @@ GENPROTIMG=${GENPROTIMG-genprotimg}
HOST_KEY_DOCUMENT=$host_key_document
CONFIG_DUMP=$enable_dump
CONFIG_EFI=$efi
+AMDSEV_EFI_VC=$amdsev_efi_vc
CONFIG_WERROR=$werror
GEN_SE_HEADER=$gen_se_header
EOF
@@ -14,6 +14,7 @@
#include "x86/vm.h"
static unsigned short amd_sev_c_bit_pos;
+phys_addr_t ghcb_addr;
bool amd_sev_enabled(void)
{
@@ -100,14 +101,10 @@ efi_status_t setup_amd_sev_es(void)
/*
* Copy UEFI's #VC IDT entry, so KVM-Unit-Tests can reuse it and does
- * not have to re-implement a #VC handler. Also update the #VC IDT code
- * segment to use KVM-Unit-Tests segments, KERNEL_CS, so that we do not
+ * not have to re-implement a #VC handler for #VC exceptions before
+ * GHCB is mapped. Also update the #VC IDT code segment to use
+ * KVM-Unit-Tests segments, KERNEL_CS, so that we do not
* have to copy the UEFI GDT entries into KVM-Unit-Tests GDT.
- *
- * TODO: Reusing UEFI #VC handler is a temporary workaround to simplify
- * the boot up process, the long-term solution is to implement a #VC
- * handler in kvm-unit-tests and load it, so that kvm-unit-tests does
- * not depend on specific UEFI #VC handler implementation.
*/
sidt(&idtr);
idt = (idt_entry_t *)idtr.base;
@@ -126,7 +123,7 @@ void setup_ghcb_pte(pgd_t *page_table)
* function searches GHCB's L1 pte, creates corresponding L1 ptes if not
* found, and unsets the c-bit of GHCB's L1 pte.
*/
- phys_addr_t ghcb_addr, ghcb_base_addr;
+ phys_addr_t ghcb_base_addr;
pteval_t *pte;
/* Read the current GHCB page addr */
@@ -54,6 +54,7 @@ efi_status_t setup_amd_sev(void);
bool amd_sev_es_enabled(void);
efi_status_t setup_amd_sev_es(void);
void setup_ghcb_pte(pgd_t *page_table);
+void handle_sev_es_vc(struct ex_regs *regs);
unsigned long long get_amd_sev_c_bit_mask(void);
unsigned long long get_amd_sev_addr_upperbound(void);
new file mode 100644
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "amd_sev.h"
+
+extern phys_addr_t ghcb_addr;
+
+void handle_sev_es_vc(struct ex_regs *regs)
+{
+ struct ghcb *ghcb = (struct ghcb *) ghcb_addr;
+
+ if (!ghcb) {
+ /* TODO: kill guest */
+ return;
+ }
+}
@@ -4,6 +4,9 @@
#include "smp.h"
#include <setjmp.h>
#include "apic-defs.h"
+#ifdef CONFIG_EFI
+#include "amd_sev.h"
+#endif
/* Boot-related data structures */
@@ -243,6 +246,9 @@ EX_E(ac, 17);
EX(mc, 18);
EX(xm, 19);
EX_E(cp, 21);
+#ifdef CONFIG_EFI
+EX_E(vc, 29);
+#endif
asm (".pushsection .text \n\t"
"__handle_exception: \n\t"
@@ -309,6 +315,17 @@ void setup_idt(void)
}
}
+#ifdef CONFIG_EFI
+void setup_amd_sev_es_vc(void)
+{
+ if (!amd_sev_es_enabled())
+ return;
+
+ set_idt_entry(29, &vc_fault, 0);
+ handle_exception(29, handle_sev_es_vc);
+}
+#endif
+
void load_idt(void)
{
lidt(&idt_descr);
@@ -252,6 +252,7 @@ void print_current_tss_info(void);
handler handle_exception(u8 v, handler fn);
void unhandled_exception(struct ex_regs *regs, bool cpu);
const char* exception_mnemonic(int vector);
+void setup_amd_sev_es_vc(void);
bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
void *data);
@@ -363,6 +363,14 @@ efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
save_id();
bsp_rest_init();
+#ifndef AMDSEV_EFI_VC
+ /*
+ * Switch away from the UEFI-installed #VC handler.
+ * GHCB has already been mapped at this point.
+ */
+ setup_amd_sev_es_vc();
+#endif /* AMDSEV_EFI_VC */
+
return EFI_SUCCESS;
}
@@ -25,6 +25,7 @@ cflatobjs += lib/x86/delay.o
cflatobjs += lib/x86/pmu.o
ifeq ($(CONFIG_EFI),y)
cflatobjs += lib/x86/amd_sev.o
+cflatobjs += lib/x86/amd_sev_vc.o
cflatobjs += lib/efi.o
cflatobjs += x86/efi/reloc_x86_64.o
endif