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