From da3d181f6223b1d611d7457f75e9ec88c9b41753 Mon Sep 17 00:00:00 2001 From: Victor Sun Date: Wed, 19 Feb 2020 16:12:55 +0800 Subject: [PATCH] HV: init efi info with multiboot2 Initialize efi info of acrn mbi when boot from multiboot2 protocol, with this patch hypervisor could get host efi info and pass it to Linux zeropage, then make guest Linux possible to boot with efi environment; Tracked-On: #4419 Signed-off-by: Victor Sun Acked-by: Eddie Dong --- hypervisor/arch/x86/boot/cpu_primary.S | 8 ++++++ hypervisor/boot/include/boot.h | 8 ++++++ hypervisor/boot/include/multiboot2.h | 16 +++++++++++ hypervisor/boot/multiboot2.c | 40 ++++++++++++++++++++++++++ hypervisor/common/vm_load.c | 11 +++++-- hypervisor/include/arch/x86/zeropage.h | 17 ++++++++++- 6 files changed, 97 insertions(+), 3 deletions(-) diff --git a/hypervisor/arch/x86/boot/cpu_primary.S b/hypervisor/arch/x86/boot/cpu_primary.S index eacadda2e..09e0ae69e 100644 --- a/hypervisor/arch/x86/boot/cpu_primary.S +++ b/hypervisor/arch/x86/boot/cpu_primary.S @@ -63,6 +63,8 @@ info_req_tag_start: .long MULTIBOOT2_TAG_TYPE_MMAP .long MULTIBOOT2_TAG_TYPE_MODULE .long MULTIBOOT2_TAG_TYPE_ACPI_NEW + .long MULTIBOOT2_TAG_TYPE_EFI64 + .long MULTIBOOT2_TAG_TYPE_EFI_MMAP info_req_tag_end: .align MULTIBOOT2_TAG_ALIGN @@ -246,3 +248,9 @@ cpu_primary32_pdt_addr: .quad address + 0x83 address = address + 0x200000 .endr + +#ifdef CONFIG_MULTIBOOT2 + .global efiloader_sig +efiloader_sig: + .asciz "EL64" +#endif diff --git a/hypervisor/boot/include/boot.h b/hypervisor/boot/include/boot.h index 0c079464d..ac7e7133d 100644 --- a/hypervisor/boot/include/boot.h +++ b/hypervisor/boot/include/boot.h @@ -12,10 +12,15 @@ #include #endif #include +#include #define MAX_BOOTARGS_SIZE 2048U #define MAX_MODULE_COUNT 4U +/* extended flags for acrn multiboot info from multiboot2 */ +#define MULTIBOOT_INFO_HAS_EFI_MMAP 0x00010000U +#define MULTIBOOT_INFO_HAS_EFI64 0x00020000U + struct acrn_multiboot_info { uint32_t mi_flags; /* the flags is back-compatible with multiboot1 */ @@ -32,11 +37,14 @@ struct acrn_multiboot_info { struct multiboot_mmap mi_mmap_entry[E820_MAX_ENTRIES]; void *mi_acpi_rsdp; + struct efi_info mi_efi_info; }; /* boot_regs store the multiboot info magic and address */ extern uint32_t boot_regs[2]; +extern char *efiloader_sig; + static inline bool boot_from_multiboot1(void) { return ((boot_regs[0] == MULTIBOOT_INFO_MAGIC) && (boot_regs[1] != 0U)); diff --git a/hypervisor/boot/include/multiboot2.h b/hypervisor/boot/include/multiboot2.h index 402bf7a3a..dbddec1d3 100644 --- a/hypervisor/boot/include/multiboot2.h +++ b/hypervisor/boot/include/multiboot2.h @@ -126,6 +126,22 @@ struct multiboot2_tag_new_acpi 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 /* ASSEMBLER */ #endif /* MULTIBOOT2_H */ diff --git a/hypervisor/boot/multiboot2.c b/hypervisor/boot/multiboot2.c index 5daf1d352..0136ad68b 100644 --- a/hypervisor/boot/multiboot2.c +++ b/hypervisor/boot/multiboot2.c @@ -49,6 +49,37 @@ static void mb2_mods_to_mbi(struct acrn_multiboot_info *mbi, mbi->mi_flags |= MULTIBOOT_INFO_HAS_MODS; } +/** + * @pre mbi != NULL && mb2_tag_efi64 != 0 + */ +static void mb2_efi64_to_mbi(struct acrn_multiboot_info *mbi, struct multiboot2_tag_efi64 *mb2_tag_efi64) +{ + mbi->mi_efi_info.efi_systab = (uint32_t)(uint64_t)mb2_tag_efi64->pointer; + mbi->mi_efi_info.efi_loader_signature = (uint32_t)(uint64_t)efiloader_sig; + mbi->mi_flags |= MULTIBOOT_INFO_HAS_EFI64; +} + +/** + * @pre mbi != NULL && mb2_tag_efimmap != 0 + */ +static int32_t mb2_efimmap_to_mbi(struct acrn_multiboot_info *mbi, struct multiboot2_tag_efi_mmap *mb2_tag_efimmap) +{ + int32_t ret = 0; + + mbi->mi_efi_info.efi_memdesc_size = mb2_tag_efimmap->descr_size; + mbi->mi_efi_info.efi_memdesc_version = mb2_tag_efimmap->descr_vers; + mbi->mi_efi_info.efi_memmap = (uint32_t)(uint64_t)mb2_tag_efimmap->efi_mmap; + mbi->mi_efi_info.efi_memmap_size = mb2_tag_efimmap->size - 16U; + mbi->mi_efi_info.efi_memmap_hi = (uint32_t)(((uint64_t)mb2_tag_efimmap->efi_mmap) >> 32U); + if (mbi->mi_efi_info.efi_memmap_hi != 0U) { + pr_err("the efi mmap address should be less than 4G!"); + ret = -EINVAL; + } else { + mbi->mi_flags |= MULTIBOOT_INFO_HAS_EFI64; + } + return ret; +} + /** * @pre mbi != NULL && mb2_info != NULL */ @@ -84,6 +115,12 @@ int32_t multiboot2_to_acrn_mbi(struct acrn_multiboot_info *mbi, void *mb2_info) case MULTIBOOT2_TAG_TYPE_ACPI_NEW: mbi->mi_acpi_rsdp = ((struct multiboot2_tag_new_acpi *)mb2_tag)->rsdp; break; + case MULTIBOOT2_TAG_TYPE_EFI64: + mb2_efi64_to_mbi(mbi, (struct multiboot2_tag_efi64 *)mb2_tag); + break; + case MULTIBOOT2_TAG_TYPE_EFI_MMAP: + ret = mb2_efimmap_to_mbi(mbi, (struct multiboot2_tag_efi_mmap *)mb2_tag); + break; default: if (mb2_tag->type <= MULTIBOOT2_TAG_TYPE_LOAD_BASE_ADDR) { pr_warn("unhandled multiboot2 tag type: %d", mb2_tag->type); @@ -104,5 +141,8 @@ int32_t multiboot2_to_acrn_mbi(struct acrn_multiboot_info *mbi, void *mb2_info) mb2_tag = (struct multiboot2_tag *)((uint8_t *)mb2_tag + ((mb2_tag->size + (MULTIBOOT2_INFO_ALIGN - 1U)) & ~(MULTIBOOT2_INFO_ALIGN - 1U))); } + if ((mbi->mi_flags & (MULTIBOOT_INFO_HAS_EFI64 | MULTIBOOT_INFO_HAS_EFI_MMAP)) == 0U) { + pr_err("no multiboot2 uefi info found!"); + } return ret; } diff --git a/hypervisor/common/vm_load.c b/hypervisor/common/vm_load.c index a0b8629b8..29258d3ec 100644 --- a/hypervisor/common/vm_load.c +++ b/hypervisor/common/vm_load.c @@ -58,11 +58,10 @@ static uint32_t create_zeropage_e820(struct zero_page *zp, const struct acrn_vm */ static uint64_t create_zero_page(struct acrn_vm *vm) { - struct zero_page *zeropage; + struct zero_page *zeropage, *hva; struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info); struct sw_module_info *bootargs_info = &(vm->sw.bootargs_info); struct sw_module_info *ramdisk_info = &(vm->sw.ramdisk_info); - struct zero_page *hva; uint64_t gpa, addr; /* Set zeropage in Linux Guest RAM region just past boot args */ @@ -74,6 +73,14 @@ static uint64_t create_zero_page(struct acrn_vm *vm) /* clear the zeropage */ (void)memset(zeropage, 0U, MEM_2K); +#ifdef CONFIG_MULTIBOOT2 + if (is_sos_vm(vm)) { + struct acrn_multiboot_info *mbi = get_multiboot_info(); + + (void)memcpy_s(&(zeropage->boot_efi_info), sizeof(zeropage->boot_efi_info), + &(mbi->mi_efi_info), sizeof(mbi->mi_efi_info)); + } +#endif /* copy part of the header into the zero page */ hva = (struct zero_page *)gpa2hva(vm, (uint64_t)sw_kernel->kernel_load_addr); (void)memcpy_s(&(zeropage->hdr), sizeof(zeropage->hdr), diff --git a/hypervisor/include/arch/x86/zeropage.h b/hypervisor/include/arch/x86/zeropage.h index 5cad176ae..935407754 100644 --- a/hypervisor/include/arch/x86/zeropage.h +++ b/hypervisor/include/arch/x86/zeropage.h @@ -8,8 +8,23 @@ #define ZEROPAGE_H #include +struct efi_info { + uint32_t efi_loader_signature; /* 0x1d0 */ + uint32_t efi_systab; /* 0x1c4 */ + uint32_t efi_memdesc_size; /* 0x1c8 */ + uint32_t efi_memdesc_version; /* 0x1cc */ + uint32_t efi_memmap; /* 0x1d0 */ + uint32_t efi_memmap_size; /* 0x1d4 */ + uint32_t efi_systab_hi; /* 0x1d8 */ + uint32_t efi_memmap_hi; /* 0x1dc */ +} __packed; + struct zero_page { - uint8_t pad1[0x1e8]; /* 0x000 */ + uint8_t pad0[0x1c0]; /* 0x000 */ + + struct efi_info boot_efi_info; + + uint8_t pad1[0x8]; /* 0x1e0 */ uint8_t e820_nentries; /* 0x1e8 */ uint8_t pad2[0x8]; /* 0x1e9 */