diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 84d1e6e60..b1eac9a3f 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -197,6 +197,9 @@ BOOT_S_SRCS += arch/x86/boot/cpu_primary.S BOOT_S_SRCS += arch/x86/boot/cpu_save_boot_ctx.S BOOT_S_SRCS += arch/x86/boot/trampoline.S BOOT_C_SRCS += boot/multiboot.c +ifeq ($(CONFIG_MULTIBOOT2),y) +BOOT_C_SRCS += boot/multiboot2.c +endif BOOT_C_SRCS += boot/reloc.c # hardware management component diff --git a/hypervisor/boot/include/boot.h b/hypervisor/boot/include/boot.h index 17cb115b1..ab7233ef9 100644 --- a/hypervisor/boot/include/boot.h +++ b/hypervisor/boot/include/boot.h @@ -8,6 +8,9 @@ #define BOOT_H_ #include +#ifdef CONFIG_MULTIBOOT2 +#include +#endif #include #define MAX_BOOTARGS_SIZE 2048U @@ -37,6 +40,15 @@ static inline bool boot_from_multiboot1(void) return ((boot_regs[0] == MULTIBOOT_INFO_MAGIC) && (boot_regs[1] != 0U)); } +#ifdef CONFIG_MULTIBOOT2 +static inline bool boot_from_multiboot2(void) +{ + return ((boot_regs[0] == MULTIBOOT2_INFO_MAGIC) && (boot_regs[1] != 0U)); +} + +int32_t multiboot2_to_acrn_mbi(struct acrn_multiboot_info *mbi, void *mb2_info); +#endif + struct acrn_multiboot_info *get_multiboot_info(void); int32_t sanitize_multiboot_info(void); void parse_hv_cmdline(void); diff --git a/hypervisor/boot/multiboot.c b/hypervisor/boot/multiboot.c index 21c016254..f2e3797dd 100644 --- a/hypervisor/boot/multiboot.c +++ b/hypervisor/boot/multiboot.c @@ -54,7 +54,10 @@ int32_t sanitize_multiboot_info(void) } else { acrn_mbi.mi_flags &= ~MULTIBOOT_INFO_HAS_MODS; } - +#ifdef CONFIG_MULTIBOOT2 + } else if (boot_from_multiboot2()) { + ret = multiboot2_to_acrn_mbi(&acrn_mbi, hpa2hva_early((uint64_t)boot_regs[1])); +#endif } else { pr_err("no multiboot info found!"); ret = -ENODEV; diff --git a/hypervisor/boot/multiboot2.c b/hypervisor/boot/multiboot2.c new file mode 100644 index 000000000..2b1bbf3c6 --- /dev/null +++ b/hypervisor/boot/multiboot2.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +/** + * @pre mbi != NULL && mb2_tag_mmap != NULL + */ +static void mb2_mmap_to_mbi(struct acrn_multiboot_info *mbi, struct multiboot2_tag_mmap *mb2_tag_mmap) +{ + uint32_t i; + + /* multiboot2 mmap tag header occupied 16 bytes */ + mbi->mi_mmap_entries = (mb2_tag_mmap->size - 16U) / sizeof(struct multiboot2_mmap_entry); + if (mbi->mi_mmap_entries > E820_MAX_ENTRIES) { + pr_err("Too many E820 entries %d\n", mbi->mi_mmap_entries); + mbi->mi_mmap_entries = E820_MAX_ENTRIES; + } + for (i = 0U; i < mbi->mi_mmap_entries; i++) { + mbi->mi_mmap_entry[i].baseaddr = mb2_tag_mmap->entries[i].addr; + mbi->mi_mmap_entry[i].length = mb2_tag_mmap->entries[i].len; + mbi->mi_mmap_entry[i].type = mb2_tag_mmap->entries[i].type; + } + mbi->mi_flags |= MULTIBOOT_INFO_HAS_MMAP; +} + +/** + * @pre mbi != NULL && mb2_info != NULL + */ +int32_t multiboot2_to_acrn_mbi(struct acrn_multiboot_info *mbi, void *mb2_info) +{ + int32_t ret = 0; + struct multiboot2_tag *mb2_tag, *mb2_tag_end; + uint32_t mb2_info_size = *(uint32_t *)mb2_info; + + /* The start part of multiboot2 info: total mbi size (4 bytes), reserved (4 bytes) */ + mb2_tag = (struct multiboot2_tag *)((uint8_t *)mb2_info + 8U); + mb2_tag_end = (struct multiboot2_tag *)((uint8_t *)mb2_info + mb2_info_size); + + while ((mb2_tag->type != MULTIBOOT2_TAG_TYPE_END) && (mb2_tag < mb2_tag_end)) { + if (mb2_tag->size == 0U) { + pr_err("the multiboot2 tag size should not be 0!"); + ret = -EINVAL; + break; + } + + switch (mb2_tag->type) { + case MULTIBOOT2_TAG_TYPE_MMAP: + mb2_mmap_to_mbi(mbi, (struct multiboot2_tag_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); + } else { + pr_err("unknown multiboot2 tag type: %d", mb2_tag->type); + ret = -EINVAL; + } + break; + } + if (ret != 0) { + pr_err("multiboot2 info format error!"); + break; + } + /* + * tag->size is not including padding whearas each tag + * start at 8-bytes aligned address. + */ + mb2_tag = (struct multiboot2_tag *)((uint8_t *)mb2_tag + + ((mb2_tag->size + (MULTIBOOT2_INFO_ALIGN - 1U)) & ~(MULTIBOOT2_INFO_ALIGN - 1U))); + } + return ret; +}