This series brings EFI support to a reduced subset of kvm-unit-tests on x86_64. I'm sending it out for early review since it covers enough ground to allow adding KVM testcases for EFI-only environments. EFI support works by changing the test entrypoint to a stub entry point for the EFI loader to jump to in long mode, where the test binary exits EFI boot services, performs the remaining CPU bootstrapping, and then calls the testcase main(). Since the EFI loader only understands PE objects, the first commit introduces a `configure --efi` mode which builds each test as a shared lib. This shared lib is repackaged into a PE via objdump. Commit 2-4 take a trip from the asm entrypoint to C to exit EFI and relocate ELF .dynamic contents. Commit 5 adds post-EFI long mode x86_64 setup and calls the testcase. Commit 6 patches out some broken tests for EFI. Testcases that refuse to build as shared libs are also left disabled, these need some massaging. git tree: https://github.com/varadgautam/kvm-unit-tests/commits/efi-stub Varad Gautam (6): x86: Build tests as PE objects for the EFI loader x86: Call efi_main from _efi_pe_entry x86: efi_main: Get EFI memory map and exit boot services x86: efi_main: Self-relocate ELF .dynamic addresses cstart64.S: x86_64 bootstrapping after exiting EFI x86: Disable some breaking tests for EFI and modify vmexit test .gitignore | 2 + Makefile | 16 ++- configure | 11 ++ lib/linux/uefi.h | 337 ++++++++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 45 ++++-- x86/Makefile.x86_64 | 43 +++--- x86/cstart64.S | 78 ++++++++++ x86/efi.lds | 67 +++++++++ x86/efi_main.c | 167 ++++++++++++++++++++++ x86/vmexit.c | 7 + 10 files changed, 741 insertions(+), 32 deletions(-) create mode 100644 lib/linux/uefi.h create mode 100644 x86/efi.lds create mode 100644 x86/efi_main.c -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 1/6] x86: Build tests as PE objects for the EFI loader
kvm-unit-tests produces tests as ELF binaries that can't be directly loaded with EFI. One way of doing so however, is to build the tests as shared libs (-pic, -shared), and then objcopy-ing out the relevant sections into a PE32+. This adds support to compile the tests as an intermediary .so lib, which is linked via x86/efi.lds to contain 4K aligned COFF-compatible sections. The linker script sets up _efi_pe_entry as the image entrypoint, and the .so sections get repackaged to an EFI binary via `objcopy --target efi-app-x86_64`. The 32-bit / long mode transition / multiboot / AP setup code within cstart64.S being incompatible with EFI builds is now hidden behind !CONFIG_EFI. It stays enabled without `configure --efi`. Some tests that don't support building with -fpic / -shared (and need some cleanups) are also moved to build on non-EFI only for now. This gets us dud EFI binaries that enter into _efi_pe_entry and die. No change to non- --efi builds. Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- .gitignore | 2 ++ Makefile | 16 +++++++++-- configure | 11 ++++++++ x86/Makefile.common | 44 +++++++++++++++++++---------- x86/Makefile.x86_64 | 43 ++++++++++++++++++----------- x86/cstart64.S | 27 +++++++++++++++++- x86/efi.lds | 67 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 177 insertions(+), 33 deletions(-) create mode 100644 x86/efi.lds diff --git a/.gitignore b/.gitignore index 8534fb7..81ee499 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,9 @@ tags *.a *.d *.o +*.so *.flat +*.efi *.elf .pc patches diff --git a/Makefile b/Makefile index f7b9f28..273b1df 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,11 @@ fomit_frame_pointer := $(call cc-option, $(frame-pointer-flag), "") fno_stack_protector := $(call cc-option, -fno-stack-protector, "") fno_stack_protector_all := $(call cc-option, -fno-stack-protector-all, "") wno_frame_address := $(call cc-option, -Wno-frame-address, "") -fno_pic := $(call cc-option, -fno-pic, "") +ifeq ($(CONFIG_EFI), y) +opt_pic := -fpic +else +opt_pic := $(call cc-option, -fno-pic, "") +endif no_pie := $(call cc-option, -no-pie, "") wclobbered := $(call cc-option, -Wclobbered, "") wunused_but_set_parameter := $(call cc-option, -Wunused-but-set-parameter, "") @@ -62,10 +66,15 @@ COMMON_CFLAGS += $(fno_stack_protector) COMMON_CFLAGS += $(fno_stack_protector_all) COMMON_CFLAGS += $(wno_frame_address) COMMON_CFLAGS += $(if $(U32_LONG_FMT),-D__U32_LONG_FMT__,) -COMMON_CFLAGS += $(fno_pic) $(no_pie) +COMMON_CFLAGS += $(opt_pic) $(no_pie) COMMON_CFLAGS += $(wclobbered) COMMON_CFLAGS += $(wunused_but_set_parameter) +ifeq ($(CONFIG_EFI),y) +COMMON_CFLAGS += -mno-red-zone -fshort-wchar -DCONFIG_EFI -ffreestanding \ + -fno-stack-check +endif + CFLAGS += $(COMMON_CFLAGS) CFLAGS += $(wmissing_parameter_type) CFLAGS += $(wold_style_declaration) @@ -74,6 +83,9 @@ CFLAGS += -Woverride-init -Wmissing-prototypes -Wstrict-prototypes autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d LDFLAGS += $(CFLAGS) +ifeq ($(CONFIG_EFI),y) +LDFLAGS += -nostdlib --warn-common --no-undefined --fatal-warnings +endif $(libcflat): $(cflatobjs) $(AR) rcs $@ $^ diff --git a/configure b/configure index 395c809..e14b9ec 100755 --- a/configure +++ b/configure @@ -28,6 +28,7 @@ erratatxt="$srcdir/errata.txt" host_key_document page_size earlycon+config_efi usage() { cat <<-EOF @@ -69,6 +70,7 @@ usage() { pl011,mmio32,ADDR Specify a PL011 compatible UART at address ADDR. Supported register stride is 32 bit only. + --efi Build with EFI support (x86_64 only). EOF exit 1 } @@ -133,6 +135,9 @@ while [[ "$1" = -* ]]; do --earlycon) earlycon="$arg" ;; + --efi) + config_efi=y + ;; --help) usage ;; @@ -192,6 +197,11 @@ elif [ "$processor" = "arm" ]; then processor="cortex-a15" fi +if [ "$config_efi" = y ] && [ "$arch" != "x86_64" ]; then + echo "--efi only supported on x86_64" + usage +fi + if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then testdir=x86 elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then @@ -337,6 +347,7 @@ U32_LONG_FMT=$u32_long WA_DIVIDE=$wa_divide GENPROTIMG=${GENPROTIMG-genprotimg} HOST_KEY_DOCUMENT=$host_key_document +CONFIG_EFI=$config_efi EOF if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then echo "TARGET=$target" >> config.mak diff --git a/x86/Makefile.common b/x86/Makefile.common index 52bb7aa..837a8a5 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -38,7 +38,7 @@ COMMON_CFLAGS += -O1 KEEP_FRAME_POINTER := y # We want to keep intermediate file: %.elf and %.o -.PRECIOUS: %.elf %.o +.PRECIOUS: %.elf %.o %.so FLATLIBS = lib/libcflat.a %.elf: %.o $(FLATLIBS) $(SRCDIR)/x86/flat.lds $(cstart.o) @@ -50,17 +50,33 @@ FLATLIBS = lib/libcflat.a $(OBJCOPY) -O elf32-i386 $^ $@ @chmod a-x $@ -tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ - $(TEST_DIR)/smptest.flat \ - $(TEST_DIR)/realmode.flat $(TEST_DIR)/msr.flat \ - $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \ - $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/eventinj.flat \ - $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat $(TEST_DIR)/setjmp.flat \ - $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ - $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ - $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ - $(TEST_DIR)/hyperv_connections.flat \ - $(TEST_DIR)/umip.flat $(TEST_DIR)/tsx-ctrl.flat +%.so: %.o $(FLATLIBS) $(cstart.o) + $(LD) -shared -nostdlib -znocombreloc -Bsymbolic -T $(SRCDIR)/x86/efi.lds $^ \ + -o $@ $(FLATLIBS) + @chmod a-x $@ + +%.efi: %.so + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \ + -j .reloc -j .init --target efi-app-x86_64 $*.so $@ + @chmod a-x $@ + +tests-flatonly = $(TEST_DIR)/realmode.$(out) $(TEST_DIR)/eventinj.$(out) \ + $(TEST_DIR)/smap.$(out) $(TEST_DIR)/umip.$(out) + +tests-common = $(TEST_DIR)/vmexit.$(out) $(TEST_DIR)/tsc.$(out) \ + $(TEST_DIR)/smptest.$(out) $(TEST_DIR)/msr.$(out) \ + $(TEST_DIR)/hypercall.$(out) $(TEST_DIR)/sieve.$(out) \ + $(TEST_DIR)/kvmclock_test.$(out) $(TEST_DIR)/s3.$(out) \ + $(TEST_DIR)/pmu.$(out) $(TEST_DIR)/setjmp.$(out) \ + $(TEST_DIR)/tsc_adjust.$(out) $(TEST_DIR)/asyncpf.$(out) \ + $(TEST_DIR)/init.$(out) $(TEST_DIR)/hyperv_synic.$(out) \ + $(TEST_DIR)/hyperv_stimer.$(out) $(TEST_DIR)/hyperv_connections.$(out) \ + $(TEST_DIR)/tsx-ctrl.$(out) + +ifneq ($(CONFIG_EFI),y) +tests-common += $(tests-flatonly) +endif test_cases: $(tests-common) $(tests) @@ -81,5 +97,5 @@ $(TEST_DIR)/hyperv_stimer.elf: $(TEST_DIR)/hyperv.o $(TEST_DIR)/hyperv_connections.elf: $(TEST_DIR)/hyperv.o arch_clean: - $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.flat $(TEST_DIR)/*.elf \ - $(TEST_DIR)/.*.d lib/x86/.*.d \ + $(RM) $(TEST_DIR)/*.o $(TEST_DIR)/*.$(out) $(TEST_DIR)/*.elf \ + $(TEST_DIR)/.*.d lib/x86/.*.d $(TEST_DIR)/*.so \ diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index 8134952..26970ab 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -5,28 +5,39 @@ ldarch = elf64-x86-64 fcf_protection_full := $(call cc-option, -fcf-protection=full,) COMMON_CFLAGS += -mno-red-zone -mno-sse -mno-sse2 $(fcf_protection_full) +ifeq ($(CONFIG_EFI),y) +out = efi +else +out = flat +endif + cflatobjs += lib/x86/setjmp64.o cflatobjs += lib/x86/intel-iommu.o cflatobjs += lib/x86/usermode.o -tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ - $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \ - $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \ - $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \ - $(TEST_DIR)/ioapic.flat $(TEST_DIR)/memory.flat \ - $(TEST_DIR)/pku.flat $(TEST_DIR)/hyperv_clock.flat -tests += $(TEST_DIR)/syscall.flat -tests += $(TEST_DIR)/svm.flat -tests += $(TEST_DIR)/vmx.flat -tests += $(TEST_DIR)/tscdeadline_latency.flat -tests += $(TEST_DIR)/intel-iommu.flat -tests += $(TEST_DIR)/vmware_backdoors.flat -tests += $(TEST_DIR)/rdpru.flat -tests += $(TEST_DIR)/pks.flat -tests += $(TEST_DIR)/pmu_lbr.flat +# Tests that have relocation / PIC problems and need more attention for EFI. +tests_flatonly = $(TEST_DIR)/access.$(out) $(TEST_DIR)/emulator.$(out) \ + $(TEST_DIR)/svm.$(out) $(TEST_DIR)/vmx.$(out) \ + $(TEST_DIR)/vmware_backdoors.$(out) + +tests = $(TEST_DIR)/apic.$(out) $(TEST_DIR)/idt_test.$(out) \ + $(TEST_DIR)/xsave.$(out) $(TEST_DIR)/rmap_chain.$(out) \ + $(TEST_DIR)/pcid.$(out) $(TEST_DIR)/debug.$(out) \ + $(TEST_DIR)/ioapic.$(out) $(TEST_DIR)/memory.$(out) \ + $(TEST_DIR)/pku.$(out) $(TEST_DIR)/hyperv_clock.$(out) +tests += $(TEST_DIR)/syscall.$(out) +tests += $(TEST_DIR)/tscdeadline_latency.$(out) +tests += $(TEST_DIR)/intel-iommu.$(out) +tests += $(TEST_DIR)/rdpru.$(out) +tests += $(TEST_DIR)/pks.$(out) +tests += $(TEST_DIR)/pmu_lbr.$(out) ifneq ($(fcf_protection_full),) -tests += $(TEST_DIR)/cet.flat +tests_flatonly += $(TEST_DIR)/cet.$(out) +endif + +ifneq ($(CONFIG_EFI),y) +tests += $(tests_flatonly) endif include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/x86/cstart64.S b/x86/cstart64.S index 5c6ad38..404fcac 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -101,20 +101,26 @@ i = i + 1 .endr tss_end: +#ifndef CONFIG_EFI mb_boot_info: .quad 0 +#endif pt_root: .quad ptl4 +#ifndef CONFIG_EFI .section .init +#endif .code32 +#ifndef CONFIG_EFI mb_magic = 0x1BADB002 mb_flags = 0x0 # multiboot header .long mb_magic, mb_flags, 0 - (mb_magic + mb_flags) mb_cmdline = 16 +#endif MSR_GS_BASE = 0xc0000101 @@ -140,6 +146,7 @@ MSR_GS_BASE = 0xc0000101 wrmsr .endm +#ifndef CONFIG_EFI .globl start start: mov %ebx, mb_boot_info @@ -231,16 +238,20 @@ ap_start32: setup_percpu_area call prepare_64 ljmpl $8, $ap_start64 +#endif /* CONFIG_EFI */ .code64 save_id: +#ifndef CONFIG_EFI movl $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax movl (%rax), %eax shrl $24, %eax lock btsl %eax, online_cpus +#endif retq ap_start64: +#ifndef CONFIG_EFI call reset_apic call load_tss call enable_apic @@ -249,11 +260,18 @@ ap_start64: sti nop lock incw cpu_online_count - +#endif 1: hlt jmp 1b +#ifdef CONFIG_EFI +.globl _efi_pe_entry +_efi_pe_entry: + ret +#endif + start64: +#ifndef CONFIG_EFI call reset_apic call load_tss call mask_pic_interrupts @@ -277,9 +295,11 @@ start64: call main mov %eax, %edi call exit +#endif .globl setup_5level_page_table setup_5level_page_table: +#ifndef CONFIG_EFI /* Check if 5-level paging has already enabled */ mov %cr4, %rax test $0x1000, %eax @@ -287,6 +307,7 @@ setup_5level_page_table: pushq $32 pushq $switch_to_5level +#endif lretq lvl5: retq @@ -299,6 +320,7 @@ online_cpus: .fill (max_cpus + 7) / 8, 1, 0 load_tss: +#ifndef CONFIG_EFI lidtq idt_descr mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax mov (%rax), %eax @@ -317,9 +339,11 @@ load_tss: mov %eax, tss_descr+8(%rbx) lea tss_descr-gdt64(%rbx), %rax ltr %ax +#endif ret ap_init: +#ifndef CONFIG_EFI cld lea sipi_entry, %rsi xor %rdi, %rdi @@ -332,6 +356,7 @@ ap_init: 1: pause cmpw %ax, cpu_online_count jne 1b +#endif ret cpu_online_count: .word 1 diff --git a/x86/efi.lds b/x86/efi.lds new file mode 100644 index 0000000..9ed1272 --- /dev/null +++ b/x86/efi.lds @@ -0,0 +1,67 @@ +/* Same as gnu-efi's elf_x86_64_fbsd_efi.lds. */ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_efi_pe_entry) +SECTIONS +{ + . = 0; + ImageBase = .; + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + . = ALIGN(4096); + .text : + { + _text = .; + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + . = ALIGN(16); + } + _etext = .; + _text_size = . - _text; + . = ALIGN(4096); + .reloc : + { + LONG(_data); + LONG(10); + SHORT(0); + *(.reloc) + } + . = ALIGN(4096); + .data : + { + _data = .; + exception_table_start = .; + *(.data.ex) + exception_table_end = .; + *(.rodata*) + *(.got.plt) + *(.got) + *(.data*) + *(.sdata) + *(.sbss) + *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + *(.rel.local) + } + .note.gnu.build-id : { *(.note.gnu.build-id) } + edata = .; + _data_size = . - _etext; + . = ALIGN(4096); + .dynamic : { *(.dynamic) } + . = ALIGN(4096); + .rela : + { + *(.rela.data*) + *(.rela.got) + *(.rela.stab) + } + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .comment 0 : { *(.comment) } +} -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 2/6] x86: Call efi_main from _efi_pe_entry
EFI calls _efi_pe_entry in long mode with the location of EFI handle/system table. Add an efi_main() C handler to make it easier to communicate with EFI for initial setup. efi_main will later, 1. Acquire the efi memmap 2. Call ExitBootServices 3. Perform remaining bootstrapping before calling the testcase main() Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- lib/linux/uefi.h | 337 ++++++++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 2 +- x86/cstart64.S | 10 +- x86/efi_main.c | 11 ++ 4 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 lib/linux/uefi.h create mode 100644 x86/efi_main.c diff --git a/lib/linux/uefi.h b/lib/linux/uefi.h new file mode 100644 index 0000000..eb142a5 --- /dev/null +++ b/lib/linux/uefi.h @@ -0,0 +1,337 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Relevant definitions from linux/efi.h. */ + +#ifndef __LINUX_UEFI_H +#define __LINUX_UEFI_H + +#include "libcflat.h" + +#define BITS_PER_LONG 64 + +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR ( 1 | (1UL << (BITS_PER_LONG-1))) +#define EFI_INVALID_PARAMETER ( 2 | (1UL << (BITS_PER_LONG-1))) +#define EFI_UNSUPPORTED ( 3 | (1UL << (BITS_PER_LONG-1))) +#define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << (BITS_PER_LONG-1))) +#define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << (BITS_PER_LONG-1))) +#define EFI_NOT_READY ( 6 | (1UL << (BITS_PER_LONG-1))) +#define EFI_DEVICE_ERROR ( 7 | (1UL << (BITS_PER_LONG-1))) +#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) +#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) +#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) +#define EFI_TIMEOUT (18 | (1UL << (BITS_PER_LONG-1))) +#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1))) +#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) + +typedef unsigned long efi_status_t; +typedef u8 efi_bool_t; +typedef u16 efi_char16_t; /* UNICODE character */ +typedef u64 efi_physical_addr_t; +typedef void *efi_handle_t; +#define __efiapi __attribute__((ms_abi)) + +/* + * Generic EFI table header + */ +typedef struct { + u64 signature; + u32 revision; + u32 headersize; + u32 crc32; + u32 reserved; +} efi_table_hdr_t; + +typedef struct { + u16 scan_code; + efi_char16_t unicode_char; +} efi_input_key_t; + +typedef void *efi_event_t; +/* Note that notifications won't work in mixed mode */ +typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *); + +typedef union efi_simple_text_input_protocol efi_simple_text_input_protocol_t; +typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t; + +union efi_simple_text_input_protocol { + struct { + void *reset; + efi_status_t (__efiapi *read_keystroke)(efi_simple_text_input_protocol_t *, + efi_input_key_t *); + efi_event_t wait_for_key; + }; + struct { + u32 reset; + u32 read_keystroke; + u32 wait_for_key; + } mixed_mode; +}; + +union efi_simple_text_output_protocol { + struct { + void *reset; + efi_status_t (__efiapi *output_string)(efi_simple_text_output_protocol_t *, + efi_char16_t *); + void *test_string; + }; + struct { + u32 reset; + u32 output_string; + u32 test_string; + } mixed_mode; +}; + +typedef enum { + EfiTimerCancel, + EfiTimerPeriodic, + EfiTimerRelative +} EFI_TIMER_DELAY; + +struct efi_generic_dev_path { + u8 type; + u8 sub_type; + u16 length; +} __packed; +typedef struct efi_generic_dev_path efi_device_path_protocol_t; + +union efi_boot_services { + struct { + efi_table_hdr_t hdr; + void *raise_tpl; + void *restore_tpl; + efi_status_t (__efiapi *allocate_pages)(int, int, unsigned long, + efi_physical_addr_t *); + efi_status_t (__efiapi *free_pages)(efi_physical_addr_t, + unsigned long); + efi_status_t (__efiapi *get_memory_map)(unsigned long *, void *, + unsigned long *, + unsigned long *, u32 *); + efi_status_t (__efiapi *allocate_pool)(int, unsigned long, + void **); + efi_status_t (__efiapi *free_pool)(void *); + efi_status_t (__efiapi *create_event)(u32, unsigned long, + efi_event_notify_t, void *, + void *); + efi_status_t (__efiapi *set_timer)(efi_event_t, + EFI_TIMER_DELAY, u64); + efi_status_t (__efiapi *wait_for_event)(unsigned long, + void *, + unsigned long *); + void *signal_event; + efi_status_t (__efiapi *close_event)(void); + void *check_event; + void *install_protocol_interface; + void *reinstall_protocol_interface; + void *uninstall_protocol_interface; + efi_status_t (__efiapi *handle_protocol)(efi_handle_t, + void *, void **); + void *__reserved; + void *register_protocol_notify; + efi_status_t (__efiapi *locate_handle)(int, void *, + void *, unsigned long *, + efi_handle_t *); + efi_status_t (__efiapi *locate_device_path)(void *, + efi_device_path_protocol_t **, + efi_handle_t *); + efi_status_t (__efiapi *install_configuration_table)(void *, + void *); + void *load_image; + void *start_image; + efi_status_t (__efiapi *exit)(efi_handle_t, + efi_status_t, + unsigned long, + efi_char16_t *); + void *unload_image; + efi_status_t (__efiapi *exit_boot_services)(efi_handle_t, + unsigned long); + void *get_next_monotonic_count; + efi_status_t (__efiapi *stall)(unsigned long); + void *set_watchdog_timer; + void *connect_controller; + efi_status_t (__efiapi *disconnect_controller)(efi_handle_t, + efi_handle_t, + efi_handle_t); + void *open_protocol; + void *close_protocol; + void *open_protocol_information; + void *protocols_per_handle; + void *locate_handle_buffer; + efi_status_t (__efiapi *locate_protocol)(void *, void *, + void **); + void *install_multiple_protocol_interfaces; + void *uninstall_multiple_protocol_interfaces; + void *calculate_crc32; + void *copy_mem; + void *set_mem; + void *create_event_ex; + }; + struct { + efi_table_hdr_t hdr; + u32 raise_tpl; + u32 restore_tpl; + u32 allocate_pages; + u32 free_pages; + u32 get_memory_map; + u32 allocate_pool; + u32 free_pool; + u32 create_event; + u32 set_timer; + u32 wait_for_event; + u32 signal_event; + u32 close_event; + u32 check_event; + u32 install_protocol_interface; + u32 reinstall_protocol_interface; + u32 uninstall_protocol_interface; + u32 handle_protocol; + u32 __reserved; + u32 register_protocol_notify; + u32 locate_handle; + u32 locate_device_path; + u32 install_configuration_table; + u32 load_image; + u32 start_image; + u32 exit; + u32 unload_image; + u32 exit_boot_services; + u32 get_next_monotonic_count; + u32 stall; + u32 set_watchdog_timer; + u32 connect_controller; + u32 disconnect_controller; + u32 open_protocol; + u32 close_protocol; + u32 open_protocol_information; + u32 protocols_per_handle; + u32 locate_handle_buffer; + u32 locate_protocol; + u32 install_multiple_protocol_interfaces; + u32 uninstall_multiple_protocol_interfaces; + u32 calculate_crc32; + u32 copy_mem; + u32 set_mem; + u32 create_event_ex; + } mixed_mode; +}; + +typedef union efi_boot_services efi_boot_services_t; + +typedef struct { + efi_table_hdr_t hdr; + u64 fw_vendor; /* physical addr of CHAR16 vendor string */ + u32 fw_revision; + u32 __pad1; + u64 con_in_handle; + u64 con_in; + u64 con_out_handle; + u64 con_out; + u64 stderr_handle; + u64 stderr; + u64 runtime; + u64 boottime; + u32 nr_tables; + u32 __pad2; + u64 tables; +} efi_system_table_64_t; + +typedef struct { + efi_table_hdr_t hdr; + u32 fw_vendor; /* physical addr of CHAR16 vendor string */ + u32 fw_revision; + u32 con_in_handle; + u32 con_in; + u32 con_out_handle; + u32 con_out; + u32 stderr_handle; + u32 stderr; + u32 runtime; + u32 boottime; + u32 nr_tables; + u32 tables; +} efi_system_table_32_t; + +typedef union { + struct { + efi_table_hdr_t hdr; + unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */ + u32 fw_revision; + unsigned long con_in_handle; + efi_simple_text_input_protocol_t *con_in; + unsigned long con_out_handle; + efi_simple_text_output_protocol_t *con_out; + unsigned long stderr_handle; + unsigned long stderr; + void *runtime; + efi_boot_services_t *boottime; + unsigned long nr_tables; + unsigned long tables; + }; + efi_system_table_32_t mixed_mode; +} efi_system_table_t; + +/* + * Memory map descriptor: + */ + +/* Memory types: */ +#define EFI_RESERVED_TYPE 0 +#define EFI_LOADER_CODE 1 +#define EFI_LOADER_DATA 2 +#define EFI_BOOT_SERVICES_CODE 3 +#define EFI_BOOT_SERVICES_DATA 4 +#define EFI_RUNTIME_SERVICES_CODE 5 +#define EFI_RUNTIME_SERVICES_DATA 6 +#define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNUSABLE_MEMORY 8 +#define EFI_ACPI_RECLAIM_MEMORY 9 +#define EFI_ACPI_MEMORY_NVS 10 +#define EFI_MEMORY_MAPPED_IO 11 +#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 +#define EFI_PAL_CODE 13 +#define EFI_PERSISTENT_MEMORY 14 +#define EFI_MAX_MEMORY_TYPE 15 + +/* Attribute values: */ +#define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */ +#define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ +#define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ +#define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ +#define EFI_MEMORY_UCE ((u64)0x0000000000000010ULL) /* uncached, exported */ +#define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ +#define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ +#define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ +#define EFI_MEMORY_NV ((u64)0x0000000000008000ULL) /* non-volatile */ +#define EFI_MEMORY_MORE_RELIABLE \ + ((u64)0x0000000000010000ULL) /* higher reliability */ +#define EFI_MEMORY_RO ((u64)0x0000000000020000ULL) /* read-only */ +#define EFI_MEMORY_SP ((u64)0x0000000000040000ULL) /* soft reserved */ +#define EFI_MEMORY_CPU_CRYPTO ((u64)0x0000000000080000ULL) /* supports encryption */ +#define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */ +#define EFI_MEMORY_DESCRIPTOR_VERSION 1 + +#define EFI_PAGE_SHIFT 12 +#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) +#define EFI_PAGES_MAX (U64_MAX >> EFI_PAGE_SHIFT) + +typedef struct { + u32 type; + u32 pad; + u64 phys_addr; + u64 virt_addr; + u64 num_pages; + u64 attribute; +} efi_memory_desc_t; + +struct efi_boot_memmap { + efi_memory_desc_t **map; + unsigned long *map_size; + unsigned long *desc_size; + u32 *desc_ver; + unsigned long *key_ptr; + unsigned long *buff_size; +}; + +#define efi_bs_call(func, ...) \ + efi_system_table->boottime->func(__VA_ARGS__) + +#endif /* __LINUX_UEFI_H */ diff --git a/x86/Makefile.common b/x86/Makefile.common index 837a8a5..98d8de9 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -50,7 +50,7 @@ FLATLIBS = lib/libcflat.a $(OBJCOPY) -O elf32-i386 $^ $@ @chmod a-x $@ -%.so: %.o $(FLATLIBS) $(cstart.o) +%.so: %.o $(FLATLIBS) $(TEST_DIR)/efi_main.o $(cstart.o) $(LD) -shared -nostdlib -znocombreloc -Bsymbolic -T $(SRCDIR)/x86/efi.lds $^ \ -o $@ $(FLATLIBS) @chmod a-x $@ diff --git a/x86/cstart64.S b/x86/cstart64.S index 404fcac..98e7848 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -267,7 +267,15 @@ ap_start64: #ifdef CONFIG_EFI .globl _efi_pe_entry _efi_pe_entry: - ret + # EFI image loader calls this with rcx=efi_handle, + # rdx=efi_system_table. Pass these to efi_main. + mov %rcx, %rdi + mov %rdx, %rsi + + pushq %rdi + pushq %rsi + + call efi_main #endif start64: diff --git a/x86/efi_main.c b/x86/efi_main.c new file mode 100644 index 0000000..00e7086 --- /dev/null +++ b/x86/efi_main.c @@ -0,0 +1,11 @@ +#include <linux/uefi.h> + +unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab); +efi_system_table_t *efi_system_table = NULL; + +unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) +{ + efi_system_table = sys_tab; + + return 0; +} -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 3/6] x86: efi_main: Get EFI memory map and exit boot services
The largest EFI_CONVENTIONAL_MEMORY chunk is passed over to alloc_phys for the testcase. Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- x86/efi_main.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/x86/efi_main.c b/x86/efi_main.c index 00e7086..237d4e7 100644 --- a/x86/efi_main.c +++ b/x86/efi_main.c @@ -1,11 +1,103 @@ +#include <alloc_phys.h> #include <linux/uefi.h> unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab); efi_system_table_t *efi_system_table = NULL; +static void efi_free_pool(void *ptr) +{ + efi_bs_call(free_pool, ptr); +} + +static efi_status_t efi_get_memory_map(struct efi_boot_memmap *map) +{ + efi_memory_desc_t *m = NULL; + efi_status_t status; + unsigned long key = 0, map_size = 0, desc_size = 0; + + status = efi_bs_call(get_memory_map, &map_size, + NULL, &key, &desc_size, NULL); + if (status != EFI_BUFFER_TOO_SMALL || map_size == 0) + goto out; + + /* Pad map_size with additional descriptors so we don't need to + * retry. */ + map_size += 4 * desc_size; + *map->buff_size = map_size; + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, + map_size, (void **)&m); + if (status != EFI_SUCCESS) + goto out; + + /* Get the map. */ + status = efi_bs_call(get_memory_map, &map_size, + m, &key, &desc_size, NULL); + if (status != EFI_SUCCESS) { + efi_free_pool(m); + goto out; + } + + *map->desc_size = desc_size; + *map->map_size = map_size; + *map->key_ptr = key; +out: + *map->map = m; + return status; +} + +static efi_status_t efi_exit_boot_services(void *handle, + struct efi_boot_memmap *map) +{ + return efi_bs_call(exit_boot_services, handle, *map->key_ptr); +} + +static efi_status_t exit_efi(void *handle) +{ + unsigned long map_size = 0, key = 0, desc_size = 0, buff_size; + efi_memory_desc_t *mem_map, *md, *conventional = NULL; + efi_status_t status; + unsigned num_ents, i; + unsigned long pages = 0; + struct efi_boot_memmap map; + + map.map = &mem_map; + map.map_size = &map_size; + map.desc_size = &desc_size; + map.desc_ver = NULL; + map.key_ptr = &key; + map.buff_size = &buff_size; + + status = efi_get_memory_map(&map); + if (status != EFI_SUCCESS) + return status; + + status = efi_exit_boot_services(handle, &map); + if (status != EFI_SUCCESS) { + efi_free_pool(mem_map); + return status; + } + + /* Use the largest EFI_CONVENTIONAL_MEMORY range for phys_alloc_init. */ + num_ents = map_size / desc_size; + for (i = 0; i < num_ents; i++) { + md = (efi_memory_desc_t *) (((u8 *) mem_map) + i * (desc_size)); + + if (md->type == EFI_CONVENTIONAL_MEMORY && md->num_pages > pages) { + conventional = md; + pages = md->num_pages; + } + } + phys_alloc_init(conventional->phys_addr, + conventional->num_pages << EFI_PAGE_SHIFT); + + return EFI_SUCCESS; +} + unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) { efi_system_table = sys_tab; + exit_efi(handle); + return 0; } -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 4/6] x86: efi_main: Self-relocate ELF .dynamic addresses
EFI expects a relocatable PE, and the loader will patch in the relocations from the COFF. Since we are wrapping an ELF into a PE here, the EFI loader will not handle ELF relocations, and we need to patch the ELF .dynamic section manually on early boot. Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- x86/efi_main.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/x86/efi_main.c b/x86/efi_main.c index 237d4e7..be3f9ab 100644 --- a/x86/efi_main.c +++ b/x86/efi_main.c @@ -1,9 +1,13 @@ #include <alloc_phys.h> #include <linux/uefi.h> +#include <elf.h> unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab); efi_system_table_t *efi_system_table = NULL; +extern char ImageBase; +extern char _DYNAMIC; + static void efi_free_pool(void *ptr) { efi_bs_call(free_pool, ptr); @@ -93,11 +97,70 @@ static efi_status_t exit_efi(void *handle) return EFI_SUCCESS; } +static efi_status_t elf_reloc(unsigned long image_base, unsigned long dynamic) +{ + long relsz = 0, relent = 0; + Elf64_Rel *rel = 0; + Elf64_Dyn *dyn = (Elf64_Dyn *) dynamic; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; i++) { + switch (dyn[i].d_tag) { + case DT_RELA: + rel = (Elf64_Rel *) + ((unsigned long) dyn[i].d_un.d_ptr + image_base); + break; + case DT_RELASZ: + relsz = dyn[i].d_un.d_val; + break; + case DT_RELAENT: + relent = dyn[i].d_un.d_val; + break; + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF64_R_TYPE (rel->r_info)) { + case R_X86_64_NONE: + break; + case R_X86_64_RELATIVE: + addr = (unsigned long *) (image_base + rel->r_offset); + *addr += image_base; + break; + default: + break; + } + rel = (Elf64_Rel *) ((char *) rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +} + unsigned long __efiapi efi_main(efi_handle_t handle, efi_system_table_t *sys_tab) { + unsigned long image_base, dyn; efi_system_table = sys_tab; exit_efi(handle); + image_base = (unsigned long) &ImageBase; + dyn = image_base + (unsigned long) &_DYNAMIC; + + /* The EFI loader does not handle ELF relocations, so fixup + * .dynamic addresses before proceeding any further. */ + elf_reloc(image_base, dyn); + + start64(); + return 0; } -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 5/6] cstart64.S: x86_64 bootstrapping after exiting EFI
EFI sets up long mode with arbitrary state before calling the image entrypoint. To run the testcases at hand, it is necessary to redo some of the bootstrapping to not rely on what EFI provided. Adapt start64() for EFI testcases to fixup %rsp/GDT/IDT/TSS and friends, and jump here after relocation from efi_main. Switch to RIP-relative addressing where necessary. Initially leave out: - AP init - leave EFI to single CPU - Testcase arg passing Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- x86/cstart64.S | 57 ++++++++++++++++++++++++++++++++++++++++++++------ x86/efi_main.c | 1 + 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/x86/cstart64.S b/x86/cstart64.S index 98e7848..d4448c2 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -242,16 +242,17 @@ ap_start32: .code64 save_id: -#ifndef CONFIG_EFI movl $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax movl (%rax), %eax shrl $24, %eax +#ifdef CONFIG_EFI + lock btsl %eax, online_cpus(%rip) +#else lock btsl %eax, online_cpus #endif retq ap_start64: -#ifndef CONFIG_EFI call reset_apic call load_tss call enable_apic @@ -259,12 +260,37 @@ ap_start64: call enable_x2apic sti nop +#ifdef CONFIG_EFI + lock incw cpu_online_count(%rip) +#else lock incw cpu_online_count #endif + 1: hlt jmp 1b #ifdef CONFIG_EFI +setup_gdt64: + lgdt gdt64_desc(%rip) + + setup_segments + + movabsq $flush_cs, %rax + pushq $0x8 + pushq %rax + retfq +flush_cs: + ret + +setup_idt64: + lidtq idt_descr(%rip) + ret + +setup_cr3: + movabsq $ptl4, %rax + mov %rax, %cr3 + ret + .globl _efi_pe_entry _efi_pe_entry: # EFI image loader calls this with rcx=efi_handle, @@ -276,15 +302,25 @@ _efi_pe_entry: pushq %rsi call efi_main -#endif +.globl start64 start64: -#ifndef CONFIG_EFI + cli + lea stacktop(%rip), %rsp + + setup_percpu_area + call setup_gdt64 + call setup_idt64 + call setup_cr3 +#else +start64: +#endif call reset_apic call load_tss call mask_pic_interrupts call enable_apic call save_id +#ifndef CONFIG_EFI mov mb_boot_info(%rip), %rbx mov %rbx, %rdi call setup_multiboot @@ -292,18 +328,24 @@ start64: mov mb_cmdline(%rbx), %eax mov %rax, __args(%rip) call __setup_args +#endif call ap_init call enable_x2apic call smp_init +#ifdef CONFIG_EFI + mov $0, %edi + mov $0, %rsi + mov $0, %rdx +#else mov __argc(%rip), %edi lea __argv(%rip), %rsi lea __environ(%rip), %rdx +#endif call main mov %eax, %edi call exit -#endif .globl setup_5level_page_table setup_5level_page_table: @@ -328,7 +370,10 @@ online_cpus: .fill (max_cpus + 7) / 8, 1, 0 load_tss: -#ifndef CONFIG_EFI +#ifdef CONFIG_EFI + mov $(tss_descr - gdt64), %rax + ltr %ax +#else lidtq idt_descr mov $(APIC_DEFAULT_PHYS_BASE + APIC_ID), %eax mov (%rax), %eax diff --git a/x86/efi_main.c b/x86/efi_main.c index be3f9ab..c542fb9 100644 --- a/x86/efi_main.c +++ b/x86/efi_main.c @@ -7,6 +7,7 @@ efi_system_table_t *efi_system_table = NULL; extern char ImageBase; extern char _DYNAMIC; +extern void start64(void); static void efi_free_pool(void *ptr) { -- 2.30.2
Varad Gautam
2021-Jul-02 11:48 UTC
[kvm-unit-tests PATCH 6/6] x86: Disable some breaking tests for EFI and modify vmexit test
Disable some tests from building on EFI. These fail early, and need some adaptation (eg. inline asm changes / AP initialization / memory reclamation from EFI). Eg, asyncpf: runs out of memory since the allocator only uses the largest EFI_CONVENTIONAL_MEMORY block. hyperv_*: untested with EFI. vmexit: breaks since test arg passing isn't enabled - enable it except for pci-* cases since iomem needs more fixups. Signed-off-by: Varad Gautam <varad.gautam at suse.com> --- x86/Makefile.common | 21 +++++++++++---------- x86/vmexit.c | 7 +++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/x86/Makefile.common b/x86/Makefile.common index 98d8de9..b995a67 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -62,17 +62,18 @@ FLATLIBS = lib/libcflat.a @chmod a-x $@ tests-flatonly = $(TEST_DIR)/realmode.$(out) $(TEST_DIR)/eventinj.$(out) \ - $(TEST_DIR)/smap.$(out) $(TEST_DIR)/umip.$(out) - -tests-common = $(TEST_DIR)/vmexit.$(out) $(TEST_DIR)/tsc.$(out) \ - $(TEST_DIR)/smptest.$(out) $(TEST_DIR)/msr.$(out) \ - $(TEST_DIR)/hypercall.$(out) $(TEST_DIR)/sieve.$(out) \ - $(TEST_DIR)/kvmclock_test.$(out) $(TEST_DIR)/s3.$(out) \ + $(TEST_DIR)/smap.$(out) $(TEST_DIR)/umip.$(out) \ + $(TEST_DIR)/kvmclock_test.$(out) $(TEST_DIR)/hypercall.$(out) \ + $(TEST_DIR)/init.$(out) \ + $(TEST_DIR)/asyncpf.$(out) $(TEST_DIR)/hyperv_synic.$(out) \ + $(TEST_DIR)/hyperv_stimer.$(out) $(TEST_DIR)/hyperv_connections.$(out) + +tests-common = $(TEST_DIR)/tsc.$(out) $(TEST_DIR)/smptest.$(out) \ + $(TEST_DIR)/msr.$(out) $(TEST_DIR)/sieve.$(out) \ + $(TEST_DIR)/sieve.$(out) $(TEST_DIR)/s3.$(out) \ $(TEST_DIR)/pmu.$(out) $(TEST_DIR)/setjmp.$(out) \ - $(TEST_DIR)/tsc_adjust.$(out) $(TEST_DIR)/asyncpf.$(out) \ - $(TEST_DIR)/init.$(out) $(TEST_DIR)/hyperv_synic.$(out) \ - $(TEST_DIR)/hyperv_stimer.$(out) $(TEST_DIR)/hyperv_connections.$(out) \ - $(TEST_DIR)/tsx-ctrl.$(out) + $(TEST_DIR)/tsc_adjust.$(out) $(TEST_DIR)/tsx-ctrl.$(out) \ + $(TEST_DIR)/vmexit.$(out) ifneq ($(CONFIG_EFI),y) tests-common += $(tests-flatonly) diff --git a/x86/vmexit.c b/x86/vmexit.c index 999babf..4062f7a 100644 --- a/x86/vmexit.c +++ b/x86/vmexit.c @@ -560,6 +560,12 @@ static void enable_nx(void *junk) static bool test_wanted(struct test *test, char *wanted[], int nwanted) { +#ifdef CONFIG_EFI + if (strcmp(test->name, "pci-io") == 0 || strcmp(test->name, "pci-mem") == 0 ) + return false; + + return true; +#else int i; if (!nwanted) @@ -570,6 +576,7 @@ static bool test_wanted(struct test *test, char *wanted[], int nwanted) return true; return false; +#endif } int main(int ac, char **av) -- 2.30.2
On Fri, Jul 02, 2021 at 01:48:14PM +0200, Varad Gautam wrote:> This series brings EFI support to a reduced subset of kvm-unit-tests > on x86_64. I'm sending it out for early review since it covers enough > ground to allow adding KVM testcases for EFI-only environments. > > EFI support works by changing the test entrypoint to a stub entry > point for the EFI loader to jump to in long mode, where the test binary > exits EFI boot services, performs the remaining CPU bootstrapping, > and then calls the testcase main(). > > Since the EFI loader only understands PE objects, the first commit > introduces a `configure --efi` mode which builds each test as a shared > lib. This shared lib is repackaged into a PE via objdump. > > Commit 2-4 take a trip from the asm entrypoint to C to exit EFI and > relocate ELF .dynamic contents. > > Commit 5 adds post-EFI long mode x86_64 setup and calls the testcase. > > Commit 6 patches out some broken tests for EFI. Testcases that refuse > to build as shared libs are also left disabled, these need some massaging. > > git tree: https://github.com/varadgautam/kvm-unit-tests/commits/efi-stubHi Varad, Thanks for this. I haven't reviewed it in detail yet (I just got back from vacation), but this looks like the right approach. In fact, I had started going down the efi stub approach for AArch64 a while back as well, but the effort got preempted by other work [again]. I'll try to allocate time to play with this for x86 and to build on it for AArch64 in the coming weeks. drew> > Varad Gautam (6): > x86: Build tests as PE objects for the EFI loader > x86: Call efi_main from _efi_pe_entry > x86: efi_main: Get EFI memory map and exit boot services > x86: efi_main: Self-relocate ELF .dynamic addresses > cstart64.S: x86_64 bootstrapping after exiting EFI > x86: Disable some breaking tests for EFI and modify vmexit test > > .gitignore | 2 + > Makefile | 16 ++- > configure | 11 ++ > lib/linux/uefi.h | 337 ++++++++++++++++++++++++++++++++++++++++++++ > x86/Makefile.common | 45 ++++-- > x86/Makefile.x86_64 | 43 +++--- > x86/cstart64.S | 78 ++++++++++ > x86/efi.lds | 67 +++++++++ > x86/efi_main.c | 167 ++++++++++++++++++++++ > x86/vmexit.c | 7 + > 10 files changed, 741 insertions(+), 32 deletions(-) > create mode 100644 lib/linux/uefi.h > create mode 100644 x86/efi.lds > create mode 100644 x86/efi_main.c > > -- > 2.30.2 >