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 <victor.sun@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Victor Sun 2020-02-19 16:12:55 +08:00 committed by wenlingz
parent 69da0243f5
commit da3d181f62
6 changed files with 97 additions and 3 deletions

View File

@ -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

View File

@ -12,10 +12,15 @@
#include <multiboot2.h>
#endif
#include <e820.h>
#include <zeropage.h>
#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));

View File

@ -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 */

View File

@ -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;
}

View File

@ -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),

View File

@ -8,8 +8,23 @@
#define ZEROPAGE_H
#include <e820.h>
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 */