From 3b6e4b34f881251977ac4b1c332df1cf14c45b02 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Tue, 2 Jul 2024 18:30:48 +0800 Subject: [PATCH] HV: elf_loader: enable guest multiboot support This patch enable guest multiboot support. Try to find the multiboot header in normal elf guest image. Introduce the multiboot related basic functions to initialize multiboot structure. Including prepare_multiboot_mmap, prepare_loader_name and find_img_multiboot_header. Tracked-On: #8642 Signed-off-by: Victor Sun Signed-off-by: Zhang Chen Reviewed-by: Junjie Mao --- hypervisor/boot/guest/elf_loader.c | 124 ++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 3 deletions(-) diff --git a/hypervisor/boot/guest/elf_loader.c b/hypervisor/boot/guest/elf_loader.c index ebb7bca7c6..6e9b6915df 100644 --- a/hypervisor/boot/guest/elf_loader.c +++ b/hypervisor/boot/guest/elf_loader.c @@ -39,6 +39,41 @@ int32_t prepare_elf_cmdline(struct acrn_vm *vm, uint64_t param_cmd_gpa) vm->sw.bootargs_info.size); } +uint32_t prepare_multiboot_mmap(struct acrn_vm *vm, uint64_t param_mmap_gpa) +{ + uint32_t i, mmap_length = 0U; + struct multiboot_mmap mmap_entry; + uint64_t mmap_gpa = param_mmap_gpa; + + for (i = 0U; i < vm->e820_entry_num; i++) { + mmap_entry.size = 20U; + mmap_entry.baseaddr = vm->e820_entries[i].baseaddr; + mmap_entry.length = vm->e820_entries[i].length; + mmap_entry.type = vm->e820_entries[i].type; + if (mmap_entry.type > MULTIBOOT_MEMORY_BADRAM) { + mmap_entry.type = MULTIBOOT_MEMORY_RESERVED; + } + + if (copy_to_gpa(vm, &mmap_entry, mmap_gpa, + sizeof(struct multiboot_mmap)) != 0U) { + mmap_length = 0U; + break; + } + mmap_gpa += sizeof(struct multiboot_mmap); + mmap_length += sizeof(struct multiboot_mmap); + } + + return mmap_length; +} + +uint32_t prepare_loader_name(struct acrn_vm *vm, uint64_t param_ldrname_gpa) +{ + char loader_name[MAX_LOADER_NAME_SIZE] = "ACRN ELF LOADER"; + + return (copy_to_gpa(vm, (void *)loader_name, param_ldrname_gpa, + MAX_LOADER_NAME_SIZE)); +} + /** * @pre vm != NULL * must run in stac/clac context @@ -204,9 +239,42 @@ static int32_t load_elf(struct acrn_vm *vm) return ret; } +struct multiboot_header *find_img_multiboot_header(struct acrn_vm *vm) +{ + uint16_t i, j; + struct multiboot_header *ret = NULL; + uint32_t *p = (uint32_t *)vm->sw.kernel_info.kernel_src_addr; + + /* Scan the first 8k to detect whether the elf needs multboot info prepared. */ + for (i = 0U; i <= (((MEM_4K * 2U) / sizeof(uint32_t)) - 3U); i++) { + if (p[i] == MULTIBOOT_HEADER_MAGIC) { + uint32_t sum = 0U; + + /* According to multiboot spec 0.6.96 sec 3.1.2. + * There are three u32: + * offset field + * 0 multiboot_header_magic + * 4 flags + * 8 checksum + * The sum of these three u32 should be u32 zero. + */ + for (j = 0U; j < 3U; j++) { + sum += p[j + i]; + } + + if (0U == sum) { + ret = (struct multiboot_header *)(p + i); + break; + } + } + } + return ret; +} + int32_t elf_loader(struct acrn_vm *vm) { - int32_t ret = -ENOMEM; + int32_t ret = 0; + struct multiboot_header *mb_hdr; /* Get primary vcpu */ struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BSP_CPU_ID); /* @@ -222,9 +290,59 @@ int32_t elf_loader(struct acrn_vm *vm) /* We boot ELF Image from protected mode directly */ init_vcpu_protect_mode_regs(vcpu, load_params_gpa + offsetof(struct elf_boot_para, init_gdt)); + stac(); + mb_hdr = find_img_multiboot_header(vm); + clac(); + if (mb_hdr != NULL) { + uint32_t mmap_length = 0U; + struct multiboot_info mb_info; - ret = load_elf(vm); - } + stac(); + if ((mb_hdr->flags & MULTIBOOT_HEADER_NEED_MEMINFO) != 0U) { + mmap_length = prepare_multiboot_mmap(vm, load_params_gpa + + offsetof(struct elf_boot_para, mmap)); + } + if (mmap_length != 0U) { + mb_info.mi_flags |= MULTIBOOT_INFO_HAS_MMAP; + mb_info.mi_mmap_addr = (uint32_t)(load_params_gpa + + offsetof(struct elf_boot_para, mmap)); + mb_info.mi_mmap_length = mmap_length; + } + ret = prepare_elf_cmdline(vm, load_params_gpa + + offsetof(struct elf_boot_para, cmdline)); + if (ret == 0) { + mb_info.mi_flags |= MULTIBOOT_INFO_HAS_CMDLINE; + mb_info.mi_cmdline = load_params_gpa + + offsetof(struct elf_boot_para, cmdline); + ret = prepare_loader_name(vm, load_params_gpa + + offsetof(struct elf_boot_para, loader_name)); + } + + if (ret == 0) { + mb_info.mi_flags |= MULTIBOOT_INFO_HAS_LOADER_NAME; + mb_info.mi_loader_name = load_params_gpa + + offsetof(struct elf_boot_para, loader_name); + ret = copy_to_gpa(vm, (void *)&mb_info, load_params_gpa + + offsetof(struct elf_boot_para, mb_info), + sizeof(struct multiboot_info)); + } + + if (ret == 0) { + vcpu_set_gpreg(vcpu, CPU_REG_RAX, MULTIBOOT_INFO_MAGIC); + vcpu_set_gpreg(vcpu, CPU_REG_RBX, load_params_gpa + + offsetof(struct elf_boot_para, mb_info)); + /* other vcpu regs should have satisfied multiboot requirement already. */ + } + clac(); + } + /* + * elf_loader need support non-multiboot header image + * at the same time. + */ + if (ret == 0) { + ret = load_elf(vm); + } + } return ret; }