diff --git a/misc/efi-stub/Makefile b/misc/efi-stub/Makefile new file mode 100644 index 000000000..a8f94d90a --- /dev/null +++ b/misc/efi-stub/Makefile @@ -0,0 +1,94 @@ +# +# Copyright (c) 2011 - 2021, Intel Corporation +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +HV_OBJDIR:=build +HV_SRC:=../../hypervisor +C_SRCS = boot.c pe.c malloc.c +ACRN_OBJS := $(patsubst %.c,$(EFI_OBJDIR)/%.o,$(C_SRCS)) +INCLUDE_PATH += $(INCDIR)/efi +INCLUDE_PATH += $(HV_SRC)/include/public +INCLUDE_PATH += $(HV_SRC)/include/lib + +BOARD ?= tgl-rvp +SCENARIO ?= hybrid_rt + +OBJCOPY=objcopy + +ARCH := x86_64 +FORMAT := efi-app-x86-64 + +# Different Linux distributions have the 'gnu-efi' package install +# its tools and libraries in different folders. The next couple of +# variables will determine and set the right path for both the +# tools $(GNUEFI_DIR) and libraries $(LIBDIR) +GNUEFI_DIR := $(shell find $(SYSROOT)/usr/lib* -name elf_$(ARCH)_efi.lds -type f | xargs dirname) +LIBDIR := $(subst gnuefi,,$(GNUEFI_DIR)) +CRT0 := $(GNUEFI_DIR)/crt0-efi-$(ARCH).o +LDSCRIPT := $(GNUEFI_DIR)/elf_$(ARCH)_efi.lds + +INCDIR := $(SYSROOT)/usr/include + +CFLAGS=-I. -I.. -I$(INCDIR)/efi -I$(INCDIR)/efi/$(ARCH) \ + -DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \ + -Wall -I../fs/ -D$(ARCH) -O2 \ + +CFLAGS += -mno-mmx -mno-sse -mno-sse2 -mno-80387 -mno-fp-ret-in-387 + +CFLAGS += -fno-delete-null-pointer-checks -fwrapv -mno-red-zone + +LDFLAGS=-T $(LDSCRIPT) -Bsymbolic -shared -nostdlib -znocombreloc \ + -L$(LIBDIR) $(CRT0) +BOOT=$(EFI_OBJDIR)/boot.efi + +all: $(BOOT) + +$(BOOT): $(EFI_OBJDIR)/boot.so + +$(EFI_OBJDIR)/boot.so: $(ACRN_OBJS) + $(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +clean: + rm -f $(BOOT) $(EFI_OBJDIR)/boot.so $(ACRN_OBJS) + +-include $(ACRN_OBJS:.o=.d) + +$(EFI_OBJDIR)/%.o:%.S + [ ! -e $@ ] && mkdir -p $(dir $@); \ + $(CC) $(CFLAGS) -c -o $@ $< -MMD -MT $@ + +$(EFI_OBJDIR)/%.o: %.c + [ ! -e $@ ] && mkdir -p $(dir $@); \ + $(CC) $(patsubst %, -I%, $(INCLUDE_PATH)) -I. -c $(CFLAGS) $(ARCH_CFLAGS) $< -o $@ -MMD -MT $@ + +%.efi: %.so + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ + -j .rela -j .reloc --target=$(FORMAT) $*.so $@ diff --git a/misc/efi-stub/boot.c b/misc/efi-stub/boot.c new file mode 100644 index 000000000..5e986d390 --- /dev/null +++ b/misc/efi-stub/boot.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "efilinux.h" +#include "stdlib.h" +#include "boot.h" +#include "container.h" + +EFI_SYSTEM_TABLE *sys_table; +EFI_BOOT_SERVICES *boot; +EFI_RUNTIME_SERVICES *runtime; +HV_LOADER hvld; + +EFI_STATUS +get_efi_memmap(struct efi_memmap_info *mi, int size_only) +{ + UINTN map_size, map_key; + UINT32 desc_version; + UINTN desc_size; + EFI_MEMORY_DESCRIPTOR *map_buf; + EFI_STATUS err = EFI_SUCCESS; + + /* We're just interested in the map's size for now */ + map_size = 0; + err = get_memory_map(&map_size, NULL, NULL, &desc_size, NULL); + if (err != EFI_SUCCESS && err != EFI_BUFFER_TOO_SMALL) + goto out; + + if (size_only) { + mi->map_size = map_size; + mi->desc_size = desc_size; + return err; + } + +again: + err = allocate_pool(EfiLoaderData, map_size, (void **) &map_buf); + if (err != EFI_SUCCESS) + goto out; + + /* + * Remember! We've already allocated map_buf with emalloc (and + * 'map_size' contains its size) which means that it should be + * positioned below our allocation for the kernel. Use that + * space for the memory map. + */ + err = get_memory_map(&map_size, map_buf, &map_key, + &desc_size, &desc_version); + if (err != EFI_SUCCESS) { + if (err == EFI_BUFFER_TOO_SMALL) { + /* + * Argh! The buffer that we allocated further + * up wasn't large enough which means we need + * to allocate them again, but this time + * larger. 'map_size' has been updated by the + * call to memory_map(). + */ + free_pool(map_buf); + goto again; + } + goto out; + } + + mi->map_size = map_size; + mi->map_key = map_key; + mi->desc_version = desc_version; + mi->desc_size = desc_size; + mi->mmap = map_buf; + +out: + return err; +} + +static EFI_STATUS +terminate_boot_services(EFI_HANDLE image, struct efi_memmap_info *mmap_info) +{ + EFI_STATUS err = EFI_SUCCESS; + + err = exit_boot_services(image, mmap_info->map_key); + if (err != EFI_SUCCESS) { + if (err == EFI_INVALID_PARAMETER) { + /* + * Incorrect map key: memory map changed during the call of get_memory_map + * and exit_boot_services. + * We must call get_memory_map and exit_boot_services one more time. + * We can't allocate nor free pool since exit_boot_services has already been called. + * Original memory pool should be sufficient and this call is expected to succeed. + */ + err = get_memory_map(&mmap_info->map_size, mmap_info->mmap, + &mmap_info->map_key, &mmap_info->desc_size, &mmap_info->desc_version); + if (err != EFI_SUCCESS) + goto out; + + err = exit_boot_services(image, mmap_info->map_key); + if (err != EFI_SUCCESS) + goto out; + } + } + +out: + return err; +} + +static inline void hv_jump(EFI_PHYSICAL_ADDRESS hv_entry, uint32_t mbi, int32_t magic) +{ + asm volatile ( + "cli\n\t" + "jmp *%2\n\t" + : + : "a"(magic), "b"(mbi), "r"(hv_entry) + ); +} + +EFI_STATUS construct_mbi(HV_LOADER hvld, struct multiboot_info **mbinfo, struct efi_memmap_info *mmap_info) +{ + EFI_STATUS err = EFI_SUCCESS; + return err; +} + +EFI_STATUS +construct_mbi2(struct hv_loader *hvld, void **mbi_addr, struct efi_memmap_info *mmap_info) +{ + return EFI_SUCCESS; +} + +static EFI_STATUS +run_acrn(EFI_HANDLE image, HV_LOADER hvld) +{ + EFI_STATUS err; + struct efi_memmap_info memmapinfo; + void *mbi; + int32_t mb_version = hvld->get_multiboot_version(hvld); + + if (mb_version == 2) { + err = construct_mbi2(hvld, &mbi, &memmapinfo); + } + else { + err = construct_mbi(hvld, (struct multiboot_info **)&mbi, &memmapinfo); + } + + if (err != EFI_SUCCESS) + goto out; + + err = terminate_boot_services(image, &memmapinfo); + if (err != EFI_SUCCESS) + goto out; + + hv_jump(hvld->get_hv_entry(hvld), (uint32_t)(uint64_t)mbi, + mb_version == 2 ? MULTIBOOT2_INFO_MAGIC : MULTIBOOT_INFO_MAGIC); + + /* Not reached on success */ +out: + return err; +} + +/** + * efi_main - The entry point for the OS loader image. + * @image: firmware-allocated handle that identifies the image + * @sys_table: EFI system table + */ +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table) +{ + WCHAR *error_buf; + EFI_STATUS err; + EFI_LOADED_IMAGE *info; + EFI_STATUS (*hvld_init)(EFI_LOADED_IMAGE *, HV_LOADER *); + + INTN index; + + InitializeLib(image, _table); + sys_table = _table; + boot = sys_table->BootServices; + runtime = sys_table->RuntimeServices; + + if (CheckCrc(sys_table->Hdr.HeaderSize, &sys_table->Hdr) != TRUE) + return EFI_LOAD_ERROR; + + err = handle_protocol(image, &LoadedImageProtocol, (void **)&info); + if (err != EFI_SUCCESS) + goto failed; + + /* We may support other containers in the future */ + hvld_init = container_init; + + /* + * Load hypervisor boot image handler. Currently Slim Bootloader + * compatible embedded container format is supported. File system + * mode to come future. + */ + err = hvld_init(info, &hvld); + if (err != EFI_SUCCESS) { + Print(L"Unable to init container library %r ", err); + goto failed; + } + + err = hvld->load_boot_image(hvld); + if (err != EFI_SUCCESS) { + Print(L"Unable to load ACRNHV Image %r ", err); + goto failed; + } + + err = hvld->load_modules(hvld); + if (err != EFI_SUCCESS) { + Print(L"Unable to load VM modules %r ", err); + goto failed; + } + + err = run_acrn(image, hvld); + if (err != EFI_SUCCESS) + goto failed; + + return EFI_SUCCESS; + +failed: + if (hvld) { + hvld->deinit(hvld); + } + + /* + * We need to be careful not to trash 'err' here. If we fail + * to allocate enough memory to hold the error string fallback + * to returning 'err'. + */ + if (allocate_pool(EfiLoaderData, ERROR_STRING_LENGTH, + (void **)&error_buf) != EFI_SUCCESS) { + Print(L"Couldn't allocate pages for error string\n"); + return err; + } + + StatusToString(error_buf, err); + Print(L": %s\n", error_buf); + + /* If we don't wait for user input, (s)he will not see the error message */ + uefi_call_wrapper(sys_table->ConOut->OutputString, 2, sys_table->ConOut, \ + L"\r\n\r\n\r\nHit any key to exit\r\n"); + uefi_call_wrapper(sys_table->BootServices->WaitForEvent, 3, 1, \ + &sys_table->ConIn->WaitForKey, &index); + + return exit(image, err, ERROR_STRING_LENGTH, error_buf); +} diff --git a/misc/efi-stub/boot.h b/misc/efi-stub/boot.h new file mode 100644 index 000000000..b16b193f1 --- /dev/null +++ b/misc/efi-stub/boot.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ACRNBOOT_H__ +#define __ACRNBOOT_H__ + +#include "multiboot.h" + +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +#define ERROR_STRING_LENGTH 32 +#define EFI_LOADER_SIGNATURE "EL64" + +#define ACPI_XSDT_ENTRY_SIZE (sizeof(UINT64)) +#define ACPI_NAME_SIZE 4 +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + +#define MSR_IA32_PAT 0x00000277 /* PAT */ +#define MSR_IA32_EFER 0xC0000080 +#define MSR_IA32_FS_BASE 0xC0000100U +#define MSR_IA32_GS_BASE 0xC0000101 +#define MSR_IA32_SYSENTER_ESP 0x00000175 /* ESP for sysenter */ +#define MSR_IA32_SYSENTER_EIP 0x00000176 /* EIP for sysenter */ + +#define UEFI_BOOT_LOADER_NAME "ACRN UEFI loader" + +#define ALIGN_UP(addr, align) \ + (((addr) + (typeof (addr)) (align) - 1) & ~((typeof (addr)) (align) - 1)) + +/* Read MSR */ +#define CPU_MSR_READ(reg, msr_val_ptr) \ +{ \ + uint32_t msrl, msrh; \ + asm volatile ("rdmsr" : "=a"(msrl), \ + "=d"(msrh) : "c" (reg)); \ + *msr_val_ptr = ((uint64_t)msrh << 32U) | msrl; \ +} + +EFI_STATUS get_pe_section(CHAR8 *base, char *section_name, UINTN section_name_len, UINTN *vaddr, UINTN *size); +typedef void(*hv_func)(int32_t, struct multiboot_info*); + +/* + * We allocate memory for the following struct together with hyperivosr itself + * memory allocation during boot. + */ +#define MBOOT_MMAP_NUMS 256 +#define MBOOT_MMAP_SIZE (sizeof(struct multiboot_mmap) * MBOOT_MMAP_NUMS) +#define MBOOT_INFO_SIZE (sizeof(struct multiboot_info)) +#define MBOOT_MODS_NUMS 4 +#define MBOOT_MODS_SIZE (sizeof(struct multiboot_module) * MBOOT_MODS_NUMS) +#define BOOT_LOADER_NAME_SIZE 17U +#define EFI_BOOT_MEM_SIZE \ + (MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE + MBOOT_MODS_SIZE + BOOT_LOADER_NAME_SIZE) +#define MBOOT_MMAP_PTR(addr) \ + ((struct multiboot_mmap *)((VOID *)(addr))) +#define MBOOT_INFO_PTR(addr) \ + ((struct multiboot_info *)((VOID *)(addr) + MBOOT_MMAP_SIZE)) +#define MBOOT_MODS_PTR(addr) \ + ((struct multiboot_module *)((VOID *)(addr) + MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE)) +#define BOOT_LOADER_NAME_PTR(addr) \ + ((char *)((VOID *)(addr) + MBOOT_MMAP_SIZE + MBOOT_INFO_SIZE + MBOOT_MODS_SIZE)) + +struct efi_memmap_info { + UINTN map_size; + UINTN map_key; + UINT32 desc_version; + UINTN desc_size; + EFI_MEMORY_DESCRIPTOR *mmap; +}; + +typedef struct mb_module_info { + UINTN mod_start; + UINTN mod_end; + const char *cmd; + UINTN cmdsize; +} MB_MODULE_INFO; + +struct efi_info { + UINT32 efi_loader_signature; + UINT32 efi_systab; + UINT32 efi_memdesc_size; + UINT32 efi_memdesc_version; + UINT32 efi_memmap; + UINT32 efi_memmap_size; + UINT32 efi_systab_hi; + UINT32 efi_memmap_hi; +}; + +struct e820_entry { + UINT64 addr; /* start of memory segment */ + UINT64 size; /* size of memory segment */ + UINT32 type; /* type of memory segment */ +} __attribute__((packed)); + +struct acpi_table_rsdp { + /* ACPI signature, contains "RSD PTR " */ + char signature[8]; + /* ACPI 1.0 checksum */ + UINT8 checksum; + /* OEM identification */ + char oem_id[ACPI_OEM_ID_SIZE]; + /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ + UINT8 revision; + /* 32-bit physical address of the RSDT */ + UINT32 rsdt_physical_address; + /* Table length in bytes, including header (ACPI 2.0+) */ + UINT32 length; + /* 64-bit physical address of the XSDT (ACPI 2.0+) */ + UINT64 xsdt_physical_address; + /* Checksum of entire table (ACPI 2.0+) */ + UINT8 extended_checksum; + /* Reserved, must be zero */ + UINT8 reserved[3]; +}; + +struct acpi_table_header { + /* ASCII table signature */ + char signature[ACPI_NAME_SIZE]; + /* Length of table in bytes, including this header */ + UINT32 length; + /* ACPI Specification minor version number */ + UINT8 revision; + /* To make sum of entire table == 0 */ + UINT8 checksum; + /* ASCII OEM identification */ + char oem_id[ACPI_OEM_ID_SIZE]; + /* ASCII OEM table identification */ + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; + /* OEM revision number */ + UINT32 oem_revision; + /* ASCII ASL compiler vendor ID */ + char asl_compiler_id[ACPI_NAME_SIZE]; + /* ASL compiler version */ + UINT32 asl_compiler_revision; +}; + +/* hypervisor loader operation table */ +typedef struct hv_loader *HV_LOADER; +struct hv_loader { + /* Load ACRN hypervisor image into memory */ + EFI_STATUS (*load_boot_image)(IN HV_LOADER hvld); + /* Load VM Kernels and ACPI Tables into memory */ + EFI_STATUS (*load_modules)(IN HV_LOADER hvld); + + const char *(*get_boot_cmd)(IN HV_LOADER hvld); + /* Get hypervisor boot command length */ + UINTN (*get_boot_cmdsize)(IN HV_LOADER hvld); + + MB_MODULE_INFO *(*get_mods_info)(IN HV_LOADER hvld, UINTN index); + /* Get the number of multiboot2 modules */ + UINTN (*get_mod_count)(IN HV_LOADER hvld); + /* Get the total memory size allocated to load module files */ + UINTN (*get_total_modsize)(IN HV_LOADER hvld); + /* Get the total lengths of the module commands */ + UINTN (*get_total_modcmdsize)(IN HV_LOADER hvld); + + /* Get the total memory size of hv image */ + UINTN (*get_hv_ram_size)(IN HV_LOADER hvld); + + /* Get the start address of the memory region stored ACRN hypervisor image */ + EFI_PHYSICAL_ADDRESS (*get_hv_hpa)(IN HV_LOADER hvld); + /* Get the start address of the memory region stored module files */ + EFI_PHYSICAL_ADDRESS (*get_mod_hpa)(IN HV_LOADER hvld); + /* Get the entry point of ACRN hypervisor */ + EFI_PHYSICAL_ADDRESS (*get_hv_entry)(IN HV_LOADER hvld); + + /* Get the supported multiboot version of ACRN hypervisor image */ + int (*get_multiboot_version)(IN HV_LOADER hvld); + + /* free up memory allocated by hypervisor loader */ + void (*deinit)(IN HV_LOADER hvld); +}; + +EFI_STATUS get_efi_memmap(struct efi_memmap_info *mmap_info, int size_only); + +static inline uint64_t +msr_read(uint32_t reg_num) +{ + uint64_t msr_val; + + CPU_MSR_READ(reg_num, &msr_val); + return msr_val; +} + +#endif diff --git a/misc/efi-stub/container.h b/misc/efi-stub/container.h new file mode 100644 index 000000000..26edc9580 --- /dev/null +++ b/misc/efi-stub/container.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __ACRNCONTAINER_H__ +#define __ACRNCONTAINER_H__ + +/** + * container_init - Initialize Container Library and returned the loader operation table. + * @info: Firmware-allocated handle that identifies the EFI application image (i.e. acrn.efi) + * @hvld: Loader operation table + */ +EFI_STATUS container_init(EFI_LOADED_IMAGE *info, HV_LOADER *hvld); + +#endif /* __ACRNCONTAINER_H__ */ diff --git a/misc/efi-stub/efilinux.h b/misc/efi-stub/efilinux.h new file mode 100644 index 000000000..14b13fd97 --- /dev/null +++ b/misc/efi-stub/efilinux.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file contains some wrappers around the gnu-efi functions. As + * we're not going through uefi_call_wrapper() directly, this allows + * us to get some type-safety for function call arguments and for the + * compiler to check that the number of function call arguments is + * correct. + * + * It's also a good place to document the EFI interface. + */ + +#ifndef __EFILINUX_H__ +#define __EFILINUX_H__ + +#define EFILINUX_VERSION_MAJOR 1 +#define EFILINUX_VERSION_MINOR 0 + +#define MEM_ADDR_1MB (1U << 20U) +#define MEM_ADDR_4GB (0xFFFFFFFFU) + + +extern EFI_SYSTEM_TABLE *sys_table; +extern EFI_BOOT_SERVICES *boot; +extern EFI_RUNTIME_SERVICES *runtime; + +extern EFI_STATUS +emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align, + EFI_PHYSICAL_ADDRESS minaddr, EFI_PHYSICAL_ADDRESS maxaddr); + +/** + * allocate_pages - Allocate memory pages from the system + * @atype: type of allocation to perform + * @mtype: type of memory to allocate + * @num_pages: number of contiguous 4KB pages to allocate + * @memory: used to return the address of allocated pages + * + * Allocate @num_pages physically contiguous pages from the system + * memory and return a pointer to the base of the allocation in + * @memory if the allocation succeeds. On success, the firmware memory + * map is updated accordingly. + * + * If @atype is AllocateAddress then, on input, @memory specifies the + * address at which to attempt to allocate the memory pages. + */ +static inline EFI_STATUS +allocate_pages(EFI_ALLOCATE_TYPE atype, EFI_MEMORY_TYPE mtype, + UINTN num_pages, EFI_PHYSICAL_ADDRESS *memory) +{ + return uefi_call_wrapper(boot->AllocatePages, 4, atype, + mtype, num_pages, memory); +} + +/** + * free_pages - Return memory allocated by allocate_pages() to the firmware + * @memory: physical base address of the page range to be freed + * @num_pages: number of contiguous 4KB pages to free + * + * On success, the firmware memory map is updated accordingly. + */ +static inline EFI_STATUS +free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN num_pages) +{ + return uefi_call_wrapper(boot->FreePages, 2, memory, num_pages); +} + +/** + * allocate_pool - Allocate pool memory + * @type: the type of pool to allocate + * @size: number of bytes to allocate from pool of @type + * @buffer: used to return the address of allocated memory + * + * Allocate memory from pool of @type. If the pool needs more memory + * pages are allocated from EfiConventionalMemory in order to grow the + * pool. + * + * All allocations are eight-byte aligned. + */ +static inline EFI_STATUS +allocate_pool(EFI_MEMORY_TYPE type, UINTN size, void **buffer) +{ + return uefi_call_wrapper(boot->AllocatePool, 3, type, size, buffer); +} + +/** + * free_pool - Return pool memory to the system + * @buffer: the buffer to free + * + * Return @buffer to the system. The returned memory is marked as + * EfiConventionalMemory. + */ +static inline EFI_STATUS free_pool(void *buffer) +{ + return uefi_call_wrapper(boot->FreePool, 1, buffer); +} + +/** + * get_memory_map - Return the current memory map + * @size: the size in bytes of @map + * @map: buffer to hold the current memory map + * @key: used to return the key for the current memory map + * @descr_size: used to return the size in bytes of EFI_MEMORY_DESCRIPTOR + * @descr_version: used to return the version of EFI_MEMORY_DESCRIPTOR + * + * Get a copy of the current memory map. The memory map is an array of + * EFI_MEMORY_DESCRIPTORs. An EFI_MEMORY_DESCRIPTOR describes a + * contiguous block of memory. + * + * On success, @key is updated to contain an identifer for the current + * memory map. The firmware's key is changed every time something in + * the memory map changes. @size is updated to indicate the size of + * the memory map pointed to by @map. + * + * @descr_size and @descr_version are used to ensure backwards + * compatibility with future changes made to the EFI_MEMORY_DESCRIPTOR + * structure. @descr_size MUST be used when the size of an + * EFI_MEMORY_DESCRIPTOR is used in a calculation, e.g when iterating + * over an array of EFI_MEMORY_DESCRIPTORs. + * + * On failure, and if the buffer pointed to by @map is too small to + * hold the memory map, EFI_BUFFER_TOO_SMALL is returned and @size is + * updated to reflect the size of a buffer required to hold the memory + * map. + */ +static inline EFI_STATUS +get_memory_map(UINTN *size, EFI_MEMORY_DESCRIPTOR *map, UINTN *key, + UINTN *descr_size, UINT32 *descr_version) +{ + return uefi_call_wrapper(boot->GetMemoryMap, 5, size, map, + key, descr_size, descr_version); +} + +/** + * exit_boot_serivces - Terminate all boot services + * @image: firmware-allocated handle that identifies the image + * @key: key to the latest memory map + * + * This function is called when efilinux wants to take complete + * control of the system. efilinux should not make calls to boot time + * services after this function is called. + */ +static inline EFI_STATUS +exit_boot_services(EFI_HANDLE image, UINTN key) +{ + return uefi_call_wrapper(boot->ExitBootServices, 2, image, key); +} + + +/** + * handle_protocol - Query @handle to see if it supports @protocol + * @handle: the handle being queried + * @protocol: the GUID of the protocol + * @interface: used to return the protocol interface + * + * Query @handle to see if @protocol is supported. If it is supported, + * @interface contains the protocol interface. + */ +static inline EFI_STATUS +handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface) +{ + return uefi_call_wrapper(boot->HandleProtocol, 3, + handle, protocol, interface); +} + + +/* + * emalloc_reserved_mem - it is called to allocate memory hypervisor itself + * and trampoline code, and mark the allocate memory as EfiReserved memory + * type so that SOS won't touch it during boot. + * @addr: a pointer to the allocated address on success + * @size: size in bytes of the requested allocation + * @max_addr: the allocated memory must be no more than this threshold + */ +static inline EFI_STATUS emalloc_reserved_mem(EFI_PHYSICAL_ADDRESS *addr, + UINTN size, EFI_PHYSICAL_ADDRESS max_addr) +{ + *addr = max_addr; + return allocate_pages(AllocateMaxAddress, EfiReservedMemoryType, + EFI_SIZE_TO_PAGES(size), addr); +} + + +/* + * emalloc_fixed_addr - it is called to allocate memory hypervisor itself + * when CONFIG_RELOC config is NOT enable.And mark the allocated memory as + * EfiReserved memory type so that SOS won't touch it during boot. + * @addr: a pointer to the allocated address on success + * @size: size in bytes of the requested allocation + */ +static inline EFI_STATUS emalloc_fixed_addr(EFI_PHYSICAL_ADDRESS *addr, + UINTN size, EFI_PHYSICAL_ADDRESS fixed_addr) +{ + *addr = fixed_addr; + return allocate_pages(AllocateAddress, EfiReservedMemoryType, + EFI_SIZE_TO_PAGES(size), addr); +} + +static inline EFI_STATUS get_variable(const CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, UINTN *size, void *data) +{ + return uefi_call_wrapper(runtime->GetVariable, 5, name, guid, attrs, size, data); +} + +static inline EFI_STATUS set_variable(const CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN size, void *data) +{ + return uefi_call_wrapper(runtime->SetVariable, 5, name, guid, attrs, size, data); +} + +/** + * exit - Terminate a loaded EFI image + * @image: firmware-allocated handle that identifies the image + * @status: the image's exit code + * @size: size in bytes of @reason. Ignored if @status is EFI_SUCCESS + * @reason: a NUL-terminated status string, optionally followed by binary data + * + * This function terminates @image and returns control to the boot + * services. This function MUST NOT be called until all loaded child + * images have exited. All memory allocated by the image must be freed + * before calling this function, apart from the buffer @reason, which + * will be freed by the firmware. + */ +static inline EFI_STATUS +exit(EFI_HANDLE image, EFI_STATUS status, UINTN size, CHAR16 *reason) +{ + return uefi_call_wrapper(boot->Exit, 4, image, status, size, reason); +} + +#define PAGE_SIZE 4096 + +static const CHAR16 *memory_types[] = { + L"EfiReservedMemoryType", + L"EfiLoaderCode", + L"EfiLoaderData", + L"EfiBootServicesCode", + L"EfiBootServicesData", + L"EfiRuntimeServicesCode", + L"EfiRuntimeServicesData", + L"EfiConventionalMemory", + L"EfiUnusableMemory", + L"EfiACPIReclaimMemory", + L"EfiACPIMemoryNVS", + L"EfiMemoryMappedIO", + L"EfiMemoryMappedIOPortSpace", + L"EfiPalCode", +}; + +static inline const CHAR16 *memory_type_to_str(UINT32 type) +{ + if (type > sizeof(memory_types)/sizeof(CHAR16 *)) + return L"Unknown"; + + return memory_types[type]; +} + +extern EFI_STATUS memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, + UINTN *map_size, UINTN *map_key, + UINTN *desc_size, UINT32 *desc_version); + +#endif /* __EFILINUX_H__ */ diff --git a/misc/efi-stub/malloc.c b/misc/efi-stub/malloc.c new file mode 100644 index 000000000..22ede6c61 --- /dev/null +++ b/misc/efi-stub/malloc.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "efilinux.h" +#include "stdlib.h" +#include "boot.h" + +EFI_STATUS +emalloc_reserved_aligned(EFI_PHYSICAL_ADDRESS *addr, UINTN size, UINTN align, + EFI_PHYSICAL_ADDRESS minaddr, EFI_PHYSICAL_ADDRESS maxaddr) +{ + struct efi_memmap_info mmap_info; + UINTN msize, desc_sz, desc_addr, pages; + EFI_MEMORY_DESCRIPTOR *mbuf; + EFI_STATUS err; + + pages = EFI_SIZE_TO_PAGES(size); + + /* Memory map may change so we request it again */ + err = get_efi_memmap(&mmap_info, 0); + if (err != EFI_SUCCESS) + goto fail; + + msize = mmap_info.map_size; + desc_sz = mmap_info.desc_size; + mbuf = mmap_info.mmap; + + /* ACRN requests for lowest possible address that's greater than minaddr */ + /* TODO: in the future we may want to support both preferences */ + for (desc_addr = (UINTN)mbuf; desc_addr <= (UINTN)mbuf + msize - desc_sz; desc_addr += desc_sz) { + EFI_MEMORY_DESCRIPTOR *desc; + EFI_PHYSICAL_ADDRESS start, end; + + desc = (EFI_MEMORY_DESCRIPTOR*)desc_addr; + if (desc->Type != EfiConventionalMemory) + continue; + + start = desc->PhysicalStart; + end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT); + + /* 1MB low memory is allocated only if required/requested */ + if ((end <= MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB)) + continue; + + /* starting allocation from 1M above unless requested */ + if ((start < MEM_ADDR_1MB) && (maxaddr > MEM_ADDR_1MB)) { + start = MEM_ADDR_1MB; + } + + /* zero page won't be allocated */ + if (start < 4096) { + start = 4096; + } + + if (start < minaddr) { + start = minaddr; + } + start = (start + align - 1) & ~(align - 1); + + /* Since this routine is called during booting, memory block is large + * enought, the reduction of memory size for memory alignment won't + * impact allocation. It is true in most cases. if it is not true, loop + * again + */ + if ((start + size <= end) && (start + size <= maxaddr)) { + err = allocate_pages(AllocateAddress, EfiReservedMemoryType, pages, &start); + if (err == EFI_SUCCESS) { + *addr = start; + break; + } + } + } + if (desc_addr > (UINTN)mbuf + msize - desc_sz) { + err = EFI_OUT_OF_RESOURCES; + } + + free_pool(mbuf); + +fail: + return err; +} + +EFI_STATUS dump_e820(void) +{ + UINTN map_size, map_key, desc_size; + EFI_MEMORY_DESCRIPTOR *map_buf; + UINTN d, map_end; + UINTN i; + UINT32 desc_version; + EFI_STATUS err; + + err = memory_map(&map_buf, &map_size, &map_key, + &desc_size, &desc_version); + if (err != EFI_SUCCESS) + goto fail; + + d = (UINTN)map_buf; + map_end = (UINTN)map_buf + map_size; + + for (i = 0; d < map_end; d += desc_size, i++) { + EFI_MEMORY_DESCRIPTOR *desc; + EFI_PHYSICAL_ADDRESS start, end; + + desc = (EFI_MEMORY_DESCRIPTOR *)d; + if (desc->Type != EfiConventionalMemory) + continue; + + start = desc->PhysicalStart; + end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT); + + Print(L"[%d]start:%lx, end:%lx, type:%d\n", i, start, end, desc->Type); + } + + free_pool(map_buf); +fail: + return err; +} + diff --git a/misc/efi-stub/multiboot.h b/misc/efi-stub/multiboot.h new file mode 100644 index 000000000..572b2e94e --- /dev/null +++ b/misc/efi-stub/multiboot.h @@ -0,0 +1,378 @@ +/* [ORIGIN: src/sys/arch/i386/include/... */ +/* $NetBSD: multiboot.h,v 1.8 2009/02/22 18:05:42 ahoka Exp $ */ + +/*- + * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Julio M. Merino Vidal. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * multiboot.h + */ + +#ifndef _MULTIBOOT_H +#define _MULTIBOOT_H + +#include +#include + +struct multiboot_info; +extern struct multiboot_info mbi; + +/* + * Multiboot header structure. + */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 +#define MULTIBOOT_HEADER_MODS_ALIGNED 0x00000001 +#define MULTIBOOT_HEADER_WANT_MEMORY 0x00000002 +#define MULTIBOOT_HEADER_HAS_VBE 0x00000004 +#define MULTIBOOT_HEADER_HAS_ADDR 0x00010000 + +#define MULTIBOOT_HEADER_ALIGN 4 +#define MULTIBOOT_SEARCH 8192 + +#if !defined(_LOCORE) +struct multiboot_header { + uint32_t mh_magic; + uint32_t mh_flags; + uint32_t mh_checksum; + + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */ + uint32_t mh_header_addr; + uint32_t mh_load_addr; + uint32_t mh_load_end_addr; + uint32_t mh_bss_end_addr; + uint32_t mh_entry_addr; + + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. */ + uint32_t mh_mode_type; + uint32_t mh_width; + uint32_t mh_height; + uint32_t mh_depth; +}; +#endif /* !defined(_LOCORE) */ + +/* + * Symbols defined in locore.S. + */ +extern struct multiboot_header *Multiboot_Header; + +/* + * Multiboot information structure. + */ +#define MULTIBOOT_INFO_MAGIC 0x2BADB002U +#define MULTIBOOT_INFO_HAS_MEMORY 0x00000001U +#define MULTIBOOT_INFO_HAS_BOOT_DEVICE 0x00000002U +#define MULTIBOOT_INFO_HAS_CMDLINE 0x00000004U +#define MULTIBOOT_INFO_HAS_MODS 0x00000008U +#define MULTIBOOT_INFO_HAS_AOUT_SYMS 0x00000010U +#define MULTIBOOT_INFO_HAS_ELF_SYMS 0x00000020U +#define MULTIBOOT_INFO_HAS_MMAP 0x00000040U +#define MULTIBOOT_INFO_HAS_DRIVES 0x00000080U +#define MULTIBOOT_INFO_HAS_CONFIG_TABLE 0x00000100U +#define MULTIBOOT_INFO_HAS_LOADER_NAME 0x00000200U +#define MULTIBOOT_INFO_HAS_APM_TABLE 0x00000400U +#define MULTIBOOT_INFO_HAS_VBE 0x00000800U + +#if !defined(_LOCORE) +struct multiboot_info { + uint32_t mi_flags; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MEMORY. */ + uint32_t mi_mem_lower; + uint32_t mi_mem_upper; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_BOOT_DEVICE. */ + uint8_t mi_boot_device_part3; + uint8_t mi_boot_device_part2; + uint8_t mi_boot_device_part1; + uint8_t mi_boot_device_drive; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CMDLINE. */ + uint32_t mi_cmdline; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MODS. */ + uint32_t mi_mods_count; + uint32_t mi_mods_addr; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_{AOUT,ELF}_SYMS. */ + uint32_t mi_elfshdr_num; + uint32_t mi_elfshdr_size; + uint32_t mi_elfshdr_addr; + uint32_t mi_elfshdr_shndx; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_MMAP. */ + uint32_t mi_mmap_length; + uint32_t mi_mmap_addr; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_DRIVES. */ + uint32_t mi_drives_length; + uint32_t mi_drives_addr; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_CONFIG_TABLE. */ + uint32_t unused_mi_config_table; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_LOADER_NAME. */ + uint32_t mi_loader_name; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_APM. */ + uint32_t unused_mi_apm_table; + + /* Valid if mi_flags sets MULTIBOOT_INFO_HAS_VBE. */ + uint32_t unused_mi_vbe_control_info; + uint32_t unused_mi_vbe_mode_info; + uint32_t unused_mi_vbe_interface_seg; + uint32_t unused_mi_vbe_interface_off; + uint32_t unused_mi_vbe_interface_len; +}__aligned(8); + + +/* + * Memory mapping. This describes an entry in the memory mappings table + * as pointed to by mi_mmap_addr. + * + * Be aware that mm_size specifies the size of all other fields *except* + * for mm_size. In order to jump between two different entries, you + * have to count mm_size + 4 bytes. + */ +struct __attribute__((packed)) multiboot_mmap { + uint32_t mm_size; + uint64_t mm_base_addr; + uint64_t mm_length; + uint32_t mm_type; +}; + +/* + * Modules. This describes an entry in the modules table as pointed + * to by mi_mods_addr. + */ + +struct multiboot_module { + uint32_t mmo_start; + uint32_t mmo_end; + uint32_t mmo_string; + uint32_t mmo_reserved; +} __packed; + +#endif /* !defined(_LOCORE) */ + +struct multiboot2_header +{ + uint32_t magic; + uint32_t architecture; + uint32_t header_length; + uint32_t checksum; +}; + +#define MULTIBOOT2_SEARCH 32768 + +#define MULTIBOOT2_HEADER_ALIGN 8 + +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6U + +/* This should be in %eax. */ +#define MULTIBOOT2_INFO_MAGIC 0x36d76289U + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT2_INFO_ALIGN 0x00000008U + +/* Flags set in the 'flags' member of the multiboot header. */ + +#define MULTIBOOT2_TAG_ALIGN 8U +#define MULTIBOOT2_TAG_TYPE_END 0U +#define MULTIBOOT2_TAG_TYPE_CMDLINE 1U +#define MULTIBOOT2_TAG_TYPE_BOOT_LOADER_NAME 2U +#define MULTIBOOT2_TAG_TYPE_MODULE 3U +#define MULTIBOOT2_TAG_TYPE_BASIC_MEMINFO 4U +#define MULTIBOOT2_TAG_TYPE_BOOTDEV 5U +#define MULTIBOOT2_TAG_TYPE_MMAP 6U +#define MULTIBOOT2_TAG_TYPE_VBE 7U +#define MULTIBOOT2_TAG_TYPE_FRAMEBUFFER 8U +#define MULTIBOOT2_TAG_TYPE_ELF_SECTIONS 9U +#define MULTIBOOT2_TAG_TYPE_APM 10U +#define MULTIBOOT2_TAG_TYPE_EFI32 11U +#define MULTIBOOT2_TAG_TYPE_EFI64 12U +#define MULTIBOOT2_TAG_TYPE_SMBIOS 13U +#define MULTIBOOT2_TAG_TYPE_ACPI_OLD 14U +#define MULTIBOOT2_TAG_TYPE_ACPI_NEW 15U +#define MULTIBOOT2_TAG_TYPE_NETWORK 16U +#define MULTIBOOT2_TAG_TYPE_EFI_MMAP 17U +#define MULTIBOOT2_TAG_TYPE_EFI_BS 18U +#define MULTIBOOT2_TAG_TYPE_EFI32_IH 19U +#define MULTIBOOT2_TAG_TYPE_EFI64_IH 20U +#define MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR 21U + +#define MULTIBOOT2_HEADER_TAG_END 0 +#define MULTIBOOT2_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT2_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT2_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT2_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT2_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT2_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT2_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT2_HEADER_TAG_RELOCATABLE 10 +#define MULTIBOOT2_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT2_ARCHITECTURE_I386 0 + +#ifndef ASSEMBLER + +struct multiboot2_header_tag +{ + uint16_t type; + uint16_t flags; + uint32_t size; +}; + +struct multiboot2_header_tag_information_request +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t requests[0]; +}; + +struct multiboot2_header_tag_address +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; +}; + +struct multiboot2_header_tag_entry_address +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t entry_addr; +}; + +struct multiboot2_header_tag_console_flags +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t console_flags; +}; + +struct multiboot2_header_tag_framebuffer +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t width; + uint32_t height; + uint32_t depth; +}; + +struct multiboot2_header_tag_module_align +{ + uint16_t type; + uint16_t flags; + uint32_t size; +}; + +struct multiboot2_header_tag_relocatable +{ + uint16_t type; + uint16_t flags; + uint32_t size; + uint32_t min_addr; + uint32_t max_addr; + uint32_t align; + uint32_t preference; +}; + +struct multiboot2_mmap_entry +{ + uint64_t addr; + uint64_t len; + uint32_t type; + uint32_t zero; +}; + +struct multiboot2_tag +{ + uint32_t type; + uint32_t size; +}; + +struct multiboot2_tag_string +{ + uint32_t type; + uint32_t size; + char string[0]; +}; + +struct multiboot2_tag_module +{ + uint32_t type; + uint32_t size; + uint32_t mod_start; + uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot2_tag_mmap +{ + uint32_t type; + uint32_t size; + uint32_t entry_size; + uint32_t entry_version; + struct multiboot2_mmap_entry entries[0]; +}; + +struct multiboot2_tag_new_acpi +{ + uint32_t type; + uint32_t size; + uint8_t rsdp[0]; +}; + +struct multiboot2_tag_efi64 +{ + uint32_t type; + uint32_t size; + uint64_t pointer; +}; + +struct multiboot2_tag_efi_mmap { + uint32_t type; + uint32_t size; + uint32_t descr_size; + uint32_t descr_vers; + uint8_t efi_mmap[0]; +}; +#endif + +#endif /* _MULTIBOOT_H */ diff --git a/misc/efi-stub/pe.c b/misc/efi-stub/pe.c new file mode 100644 index 000000000..0c734aa4d --- /dev/null +++ b/misc/efi-stub/pe.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file contains some wrappers around the gnu-efi functions. As + * we're not going through uefi_call_wrapper() directly, this allows + * us to get some type-safety for function call arguments and for the + * compiler to check that the number of function call arguments is + * correct. + * + * It's also a good place to document the EFI interface. + */ + +#include +#include +#include "stdlib.h" + +#define DOS_FILE_MAGIC_NUMBER 0x5A4D /* "MZ" */ +struct DosFileHeader { + uint16_t mMagic; + uint16_t LastSize; + uint16_t nBlocks; + uint16_t nReloc; + uint16_t HdrSize; + uint16_t MinAlloc; + uint16_t MaxAlloc; + uint16_t ss; + uint16_t sp; + uint16_t Checksum; + uint16_t ip; + uint16_t cs; + uint16_t RelocPos; + uint16_t nOverlay; + uint16_t reserved[4]; + uint16_t OEMId; + uint16_t OEMInfo; + uint16_t reserved2[10]; + uint32_t ExeHeader; +} __attribute__((packed)); + +#define IMAGE_FILE_MACHINE_I386 0x14c +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define PE_FILE_MAGIC_NUMBER 0x00004550 /* "PE\0\0" */ +struct PeHeader { + uint32_t mMagic; + uint16_t mMachine; + uint16_t mNumberOfSections; + uint32_t mTimeDateStamp; + uint32_t mPointerToSymbolTable; + uint32_t mNumberOfSymbols; + uint16_t mSizeOfOptionalHeader; + uint16_t mCharacteristics; +} __attribute__((packed)); + +struct OptionHeader { + uint16_t Format; + uint8_t MajorLinkVer; + uint8_t MinorLinkVer; + uint32_t CodeSize; + uint32_t InitializedDataSize; + uint32_t UninitializedDataSize; + uint32_t EntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfDate; +} __attribute__((packed)); + + +struct PeSectionHeader { + char mName[8]; + uint32_t mVirtualSize; + uint32_t mVirtualAddress; + uint32_t mSizeOfRawData; + uint32_t mPointerToRawData; + uint32_t mPointerToRealocations; + uint32_t mPointerToLinenumbers; + uint16_t mNumberOfRealocations; + uint16_t mNumberOfLinenumbers; + uint32_t mCharacteristics; +} __attribute__((packed)); + + +EFI_STATUS get_pe_section(CHAR8 *base, char *section_name, + UINTN section_name_len, UINTN *vaddr, UINTN *size) +{ + struct PeSectionHeader *ph; + struct DosFileHeader *dh; + struct PeHeader *pe; + UINTN i; + UINTN offset; + + dh = (struct DosFileHeader *)base; + + if (dh->mMagic != DOS_FILE_MAGIC_NUMBER) + return EFI_LOAD_ERROR; + + pe = (struct PeHeader *)&base[dh->ExeHeader]; + if (pe->mMagic != PE_FILE_MAGIC_NUMBER) + return EFI_LOAD_ERROR; + + if ((pe->mMachine != IMAGE_FILE_MACHINE_AMD64) + && (pe->mMachine != IMAGE_FILE_MACHINE_I386)) + return EFI_LOAD_ERROR; + + offset = dh->ExeHeader + sizeof(*pe) + pe->mSizeOfOptionalHeader; + + for (i = 0; i < pe->mNumberOfSections; i++) { + ph = (struct PeSectionHeader *)&base[offset]; + if (CompareMem(ph->mName, section_name, section_name_len) == 0) { + *vaddr = (UINTN)ph->mVirtualAddress; + *size = (UINTN)ph->mVirtualSize; + break; + } + + offset += sizeof(*ph); + } + + return EFI_SUCCESS; +} + + +EFI_IMAGE_ENTRY_POINT get_pe_entry(CHAR8 *base) +{ + struct DosFileHeader* dh; + struct PeHeader* pe; + struct OptionHeader* oh; + UINTN offset; + + dh = (struct DosFileHeader *)base; + + if (dh->mMagic != DOS_FILE_MAGIC_NUMBER) + return NULL; + + pe = (struct PeHeader *)&base[dh->ExeHeader]; + if (pe->mMagic != PE_FILE_MAGIC_NUMBER) + return NULL; + + if ((pe->mMachine != IMAGE_FILE_MACHINE_AMD64) + && (pe->mMachine != IMAGE_FILE_MACHINE_I386)) + return NULL; + + offset = dh->ExeHeader + sizeof(*pe); + oh = (struct OptionHeader*)&base[offset]; + + return (EFI_IMAGE_ENTRY_POINT)((UINT64)base + oh->EntryPoint); +} diff --git a/misc/efi-stub/stdlib.h b/misc/efi-stub/stdlib.h new file mode 100644 index 000000000..9a7994fb0 --- /dev/null +++ b/misc/efi-stub/stdlib.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2011 - 2021, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file contains some wrappers around the gnu-efi functions. As + * we're not going through uefi_call_wrapper() directly, this allows + * us to get some type-safety for function call arguments and for the + * compiler to check that the number of function call arguments is + * correct. + * + * It's also a good place to document the EFI interface. + */ + + + +#ifndef __STDLIB_H__ +#define __STDLIB_H__ + +#include +#include + +static inline void memset(void *dstv, char ch, UINTN size) +{ + char *dst = dstv; + int32_t i; + + for (i = 0; i < size; i++) + dst[i] = ch; +} + +static inline void memcpy(char *dst, const char *src, UINTN size) +{ + int32_t i; + + for (i = 0; i < size; i++) + *dst++ = *src++; +} + +static inline int32_t strlen(const char *str) +{ + int32_t len; + + len = 0; + while (*str++) + len++; + + return len; +} + +static inline CHAR16 *strstr_16(CHAR16 *haystack, CHAR16 *needle, UINTN len) +{ + CHAR16 *p; + CHAR16 *word = NULL; + + if (!len) + return NULL; + + p = haystack; + while (*p) { + if (!StrnCmp(p, needle, len)) { + word = p; + break; + } + p++; + } + + return (CHAR16*)word; +} + +static inline char *ch16_2_ch8(CHAR16 *str16, UINTN len) +{ + UINTN i; + char *str8; + + str8 = AllocatePool((len + 1) * sizeof(char)); + + for (i = 0; i < len; i++) + str8[i] = str16[i]; + + str8[len] = 0; + + return str8; +} + +static inline CHAR16 *ch8_2_ch16(char *str8, UINTN len) +{ + UINTN i; + CHAR16 *str16; + + str16 = AllocatePool((len + 1) * sizeof(CHAR16)); + + for (i = 0; i < len; i++) + str16[i] = str8[i]; + + str16[len] = 0; + + return str16; +} + +#endif /* __STDLIB_H__ */