mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-26 00:53:15 +00:00
dm: add elf loader to dm
This patch adds a simple 32bit static elf binary loader to acrn DM. And if the elf binary follow multiboot protocol, only memory info will be included in multiboot info. Tracked-On: #1465 Signed-off-by: Yin Fengwei <fengwei.yin@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
0e897c0a6a
commit
9f7642648b
@ -108,6 +108,7 @@ SRCS += core/monitor.c
|
||||
SRCS += core/sw_load_common.c
|
||||
SRCS += core/sw_load_bzimage.c
|
||||
SRCS += core/sw_load_vsbl.c
|
||||
SRCS += core/sw_load_elf.c
|
||||
SRCS += core/smbiostbl.c
|
||||
SRCS += core/mevent.c
|
||||
SRCS += core/gc.c
|
||||
|
@ -77,6 +77,8 @@ char *vmname;
|
||||
int guest_ncpus;
|
||||
char *guest_uuid_str;
|
||||
char *vsbl_file_name;
|
||||
char *kernel_file_name;
|
||||
char *elf_file_name;
|
||||
uint8_t trusty_enabled;
|
||||
bool stdio_in_use;
|
||||
|
||||
@ -135,6 +137,7 @@ usage(int code)
|
||||
" -b: enable bvmcons\n"
|
||||
" -c: # cpus (default 1)\n"
|
||||
" -C: include guest memory in core file\n"
|
||||
" -E: elf image path\n"
|
||||
" -g: gdb port\n"
|
||||
" -h: help\n"
|
||||
" -l: LPC device configuration\n"
|
||||
@ -690,6 +693,7 @@ static struct option long_options[] = {
|
||||
{"pincpu", required_argument, 0, 'p' },
|
||||
{"ncpus", required_argument, 0, 'c' },
|
||||
{"memflags_incore", no_argument, 0, 'C' },
|
||||
{"elf_file", required_argument, 0, 'E' },
|
||||
{"gdb_port", required_argument, 0, 'g' },
|
||||
{"ioc node", required_argument, 0, 'i' },
|
||||
{"lpc", required_argument, 0, 'l' },
|
||||
@ -742,7 +746,7 @@ main(int argc, char *argv[])
|
||||
if (signal(SIGINT, sig_handler_term) == SIG_ERR)
|
||||
fprintf(stderr, "cannot register handler for SIGINT\n");
|
||||
|
||||
optstr = "abhuwxACSWYvk:r:B:p:g:c:s:m:l:U:G:i:";
|
||||
optstr = "abhuwxACSWYvE:k:r:B:p:g:c:s:m:l:U:G:i:";
|
||||
while ((c = getopt_long(argc, argv, optstr, long_options,
|
||||
&option_idx)) != -1) {
|
||||
switch (c) {
|
||||
@ -768,6 +772,12 @@ main(int argc, char *argv[])
|
||||
case 'C':
|
||||
memflags |= VM_MEM_F_INCORE;
|
||||
break;
|
||||
case 'E':
|
||||
if (acrn_parse_elf(optarg) != 0)
|
||||
exit(1);
|
||||
else
|
||||
break;
|
||||
break;
|
||||
case 'g':
|
||||
gdb_port = atoi(optarg);
|
||||
break;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "vmmapi.h"
|
||||
#include "sw_load.h"
|
||||
|
||||
@ -137,6 +138,8 @@ acrn_parse_kernel(char *arg)
|
||||
kernel_path);
|
||||
exit(10); /* Non-zero */
|
||||
}
|
||||
kernel_file_name = kernel_path;
|
||||
|
||||
with_kernel = 1;
|
||||
printf("SW_LOAD: get kernel path %s\n", kernel_path);
|
||||
return 0;
|
||||
|
@ -222,6 +222,10 @@ acrn_sw_load(struct vmctx *ctx)
|
||||
{
|
||||
if (vsbl_file_name)
|
||||
return acrn_sw_load_vsbl(ctx);
|
||||
else
|
||||
else if (kernel_file_name)
|
||||
return acrn_sw_load_bzimage(ctx);
|
||||
else if (elf_file_name)
|
||||
return acrn_sw_load_elf(ctx);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
321
devicemodel/core/sw_load_elf.c
Normal file
321
devicemodel/core/sw_load_elf.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*-
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This is a very simple elf binary loader. It only support static elf32 binary
|
||||
* loading. So we don't need to handle elf relocation. Just need to load the
|
||||
* PT_LOAD section to correct memory address and set correct entry.
|
||||
*
|
||||
* It also prepare simple multiboot info (only memory info) to guest. If some
|
||||
* other things are necessary for guest, we could add it per requirement.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "dm.h"
|
||||
#include "vmmapi.h"
|
||||
#include "sw_load.h"
|
||||
#include "acpi.h"
|
||||
|
||||
#define ELF_BUF_LEN (1024UL*8UL)
|
||||
#define MULTIBOOT_HEAD_MAGIC (0x1BADB002U)
|
||||
#define MULTIBOOT_MACHINE_STATE_MAGIC (0x2BADB002U)
|
||||
/* The max length for GDT is 8192 * 8 bytes */
|
||||
#define GDT_LOAD_OFF(ctx) (ctx->lowmem - 64U * KB)
|
||||
|
||||
static char elf_path[STR_LEN];
|
||||
/* Whether we need to setup multiboot info for guest */
|
||||
static int multiboot_image = 0;
|
||||
|
||||
/* Multiboot info. Compatible with Multiboot spec 0.6.96 with vesa removed */
|
||||
#define MULTIBOOT_INFO_MEMORY (0x00000001U)
|
||||
#define MULTIBOOT_INFO_BOOTDEV (0x00000002U)
|
||||
#define MULTIBOOT_INFO_CMDLINE (0x00000004U)
|
||||
#define MULTIBOOT_INFO_MODS (0x00000008U)
|
||||
#define MULTIBOOT_INFO_AOUT_SYMS (0x00000010U)
|
||||
#define MULTIBOOT_INFO_ELF_SHDR (0x00000020U)
|
||||
#define MULTIBOOT_INFO_MEM_MAP (0x00000040U)
|
||||
#define MULTIBOOT_INFO_DRIVE_INFO (0x00000080U)
|
||||
#define MULTIBOOT_INFO_CONFIG_TABLE (0x00000100U)
|
||||
#define MULTIBOOT_INFO_BOOT_LOADER_NAME (0x00000200U)
|
||||
#define MULTIBOOT_INFO_BOOT_APM_TABLE (0x00000400U)
|
||||
|
||||
struct multiboot_info {
|
||||
uint32_t flags;
|
||||
uint32_t mem_lower;
|
||||
uint32_t mem_upper;
|
||||
|
||||
uint32_t boot_device;
|
||||
uint32_t cmdline;
|
||||
uint32_t mods_count;
|
||||
uint32_t mods_addr;
|
||||
|
||||
uint32_t bin_sec[4];
|
||||
|
||||
uint32_t mmap_length;
|
||||
uint32_t mmap_addr;
|
||||
|
||||
uint32_t drives_length;
|
||||
uint32_t drives_addr;
|
||||
|
||||
uint32_t config_table;
|
||||
|
||||
uint32_t boot_loader_name;
|
||||
};
|
||||
|
||||
int
|
||||
acrn_parse_elf(char *arg)
|
||||
{
|
||||
size_t len = strnlen(arg, STR_LEN);
|
||||
|
||||
if (len < STR_LEN) {
|
||||
strncpy(elf_path, arg, len + 1);
|
||||
assert(check_image(elf_path) == 0);
|
||||
|
||||
elf_file_name = elf_path;
|
||||
|
||||
printf("SW_LOAD: get elf path %s\n", elf_path);
|
||||
return 0;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int load_elf32(struct vmctx *ctx, FILE *fp, void *buf)
|
||||
{
|
||||
int i;
|
||||
size_t phd_size, read_len;
|
||||
Elf32_Ehdr *elf32_header = (Elf32_Ehdr *)buf;
|
||||
Elf32_Phdr *elf32_phdr, *elf32_phdr_bk;
|
||||
|
||||
phd_size = elf32_header->e_phentsize * elf32_header->e_phnum;
|
||||
elf32_phdr_bk = elf32_phdr = (Elf32_Phdr *)calloc(1, phd_size);
|
||||
if (elf32_phdr == NULL) {
|
||||
fprintf(stderr, "Can't allocate memory for elf program header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(fp, elf32_header->e_phoff, SEEK_SET);
|
||||
read_len = fread((void *)elf32_phdr, 1, phd_size, fp);
|
||||
if (read_len != phd_size) {
|
||||
fprintf(stderr, "can't get %ld data from elf file\n", phd_size);
|
||||
}
|
||||
|
||||
for (i = 0; i < elf32_header->e_phnum; i++) {
|
||||
if (elf32_phdr->p_type == PT_LOAD) {
|
||||
if ((elf32_phdr->p_vaddr + elf32_phdr->p_memsz) >
|
||||
ctx->lowmem) {
|
||||
fprintf(stderr,
|
||||
"No enough memory to load elf file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *seg_ptr = ctx->baseaddr + elf32_phdr->p_vaddr;
|
||||
|
||||
/* Clear the segment memory in memory.
|
||||
* This is required for BSS section
|
||||
*/
|
||||
memset(seg_ptr, 0, elf32_phdr->p_memsz);
|
||||
fseek(fp, elf32_phdr->p_offset, SEEK_SET);
|
||||
read_len = fread(seg_ptr, 1, elf32_phdr->p_filesz, fp);
|
||||
if (read_len != elf32_phdr->p_filesz) {
|
||||
fprintf(stderr, "Can't get %d data\n",
|
||||
elf32_phdr->p_filesz);
|
||||
}
|
||||
}
|
||||
|
||||
elf32_phdr++;
|
||||
}
|
||||
|
||||
free(elf32_phdr_bk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
acrn_load_elf(struct vmctx *ctx, char *elf_file_name, unsigned long *entry,
|
||||
uint32_t *multiboot_flags)
|
||||
{
|
||||
int i, ret = 0;
|
||||
FILE *fp;
|
||||
size_t read_len = 0;
|
||||
unsigned int *ptr32;
|
||||
char *elf_buf;
|
||||
Elf32_Ehdr *elf_ehdr;
|
||||
|
||||
|
||||
elf_buf = calloc(1, ELF_BUF_LEN);
|
||||
if (elf_buf == NULL) {
|
||||
fprintf(stderr, "Can't allocate elf buf\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = fopen(elf_file_name, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Can't open elf file: %s\r\n", elf_file_name);
|
||||
free(elf_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
read_len = fread(elf_buf, 1, ELF_BUF_LEN, fp);
|
||||
if (read_len != ELF_BUF_LEN) {
|
||||
fprintf(stderr, "Can't get %ld data from elf file\n",
|
||||
ELF_BUF_LEN);
|
||||
}
|
||||
|
||||
/* Scan the first 8k to detect whether the elf needs multboot
|
||||
* info prepared.
|
||||
*/
|
||||
ptr32 = (unsigned int *) elf_buf;
|
||||
for (i = 0; i < ELF_BUF_LEN/4; i++) {
|
||||
if (ptr32[i] == MULTIBOOT_HEAD_MAGIC) {
|
||||
int j = 0;
|
||||
unsigned int sum = 0;
|
||||
|
||||
/* According to multiboot spec 0.6.96 sec 3.1.2.
|
||||
* There are three u32:
|
||||
* offset field
|
||||
* 0 multiboot_head_magic
|
||||
* 4 flags
|
||||
* 8 checksum
|
||||
* The sum of these three u32 should be u32 zero.
|
||||
*/
|
||||
for (j = 0; j < 3; j++) {
|
||||
sum += ptr32[j + i];
|
||||
}
|
||||
|
||||
if (0 == sum) {
|
||||
multiboot_image = 1;
|
||||
*multiboot_flags = ptr32[i + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
elf_ehdr = (Elf32_Ehdr *) elf_buf;
|
||||
|
||||
if ((elf_ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
|
||||
(elf_ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
|
||||
(elf_ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
|
||||
(elf_ehdr->e_ident[EI_MAG3] != ELFMAG3)) {
|
||||
fprintf(stderr, "This is not elf file\n");
|
||||
fclose(fp);
|
||||
free(elf_buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (elf_ehdr->e_ident[EI_CLASS] == ELFCLASS32) {
|
||||
ret = load_elf32(ctx, fp, elf_buf);
|
||||
} else {
|
||||
fprintf(stderr, "No available 64bit elf loader ready yet\n");
|
||||
fclose(fp);
|
||||
free(elf_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*entry = elf_ehdr->e_entry;
|
||||
free(elf_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Where we put multboot info to */
|
||||
#define MULTIBOOT_OFFSET (0x20000)
|
||||
static const uint64_t acrn_init_gdt[] = {
|
||||
0x0UL,
|
||||
0x00CF9B000000FFFFUL, /* Linear Code */
|
||||
0x00CF93000000FFFFUL, /* Linear Data */
|
||||
};
|
||||
|
||||
int
|
||||
acrn_sw_load_elf(struct vmctx *ctx)
|
||||
{
|
||||
int ret;
|
||||
uint32_t multiboot_flags = 0;
|
||||
uint64_t entry = 0;
|
||||
struct multiboot_info *mi;
|
||||
|
||||
ret = acrn_load_elf(ctx, elf_file_name, &entry, &multiboot_flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* set guest bsp state. Will call hypercall set bsp state
|
||||
* after bsp is created.
|
||||
*/
|
||||
memset(&ctx->bsp_regs, 0, sizeof( struct acrn_set_vcpu_regs));
|
||||
ctx->bsp_regs.vcpu_id = 0;
|
||||
|
||||
memcpy(ctx->baseaddr + GDT_LOAD_OFF(ctx), &acrn_init_gdt,
|
||||
sizeof(acrn_init_gdt));
|
||||
ctx->bsp_regs.vcpu_regs.gdt.limit = sizeof(acrn_init_gdt) - 1;
|
||||
ctx->bsp_regs.vcpu_regs.gdt.base = GDT_LOAD_OFF(ctx);
|
||||
|
||||
/* CR0_ET | CR0_NE | CR0_PE */
|
||||
ctx->bsp_regs.vcpu_regs.cr0 = 0x31U;
|
||||
|
||||
ctx->bsp_regs.vcpu_regs.cs_ar = 0xCF9BU;
|
||||
ctx->bsp_regs.vcpu_regs.cs_sel = 0x8U;
|
||||
|
||||
ctx->bsp_regs.vcpu_regs.ds_sel = 0x10U;
|
||||
ctx->bsp_regs.vcpu_regs.ss_sel = 0x10U;
|
||||
ctx->bsp_regs.vcpu_regs.es_sel = 0x10U;
|
||||
ctx->bsp_regs.vcpu_regs.gs_sel = 0x10U;
|
||||
ctx->bsp_regs.vcpu_regs.fs_sel = 0x10U;
|
||||
|
||||
ctx->bsp_regs.vcpu_regs.rip = entry;
|
||||
ctx->bsp_regs.vcpu_regs.gprs.rax = MULTIBOOT_MACHINE_STATE_MAGIC;
|
||||
|
||||
if (multiboot_image == 1) {
|
||||
mi = (struct multiboot_info *)ctx->baseaddr + MULTIBOOT_OFFSET;
|
||||
memset(mi, 0, sizeof(*mi));
|
||||
|
||||
if (multiboot_flags == (1 << 1)) {
|
||||
/* Now, we only support elf binary request multiboot
|
||||
* info with memory info filled case.
|
||||
*
|
||||
* TODO:
|
||||
* For other elf image with multiboot enabled, they
|
||||
* may need more fileds initialized here. We will add
|
||||
* them here per each requirement.
|
||||
*/
|
||||
mi->flags = MULTIBOOT_INFO_MEMORY;
|
||||
mi->mem_lower = 0;
|
||||
mi->mem_upper = GDT_LOAD_OFF(ctx) / 1024U;
|
||||
ctx->bsp_regs.vcpu_regs.gprs.rbx = MULTIBOOT_OFFSET;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Invalid multiboot header in elf binary\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -38,6 +38,8 @@ extern int guest_ncpus;
|
||||
extern char *guest_uuid_str;
|
||||
extern uint8_t trusty_enabled;
|
||||
extern char *vsbl_file_name;
|
||||
extern char *kernel_file_name;
|
||||
extern char *elf_file_name;
|
||||
extern char *vmname;
|
||||
extern bool stdio_in_use;
|
||||
|
||||
|
@ -60,6 +60,7 @@ int acrn_parse_ramdisk(char *arg);
|
||||
int acrn_parse_bootargs(char *arg);
|
||||
int acrn_parse_gvtargs(char *arg);
|
||||
int acrn_parse_vsbl(char *arg);
|
||||
int acrn_parse_elf(char *arg);
|
||||
int acrn_parse_guest_part_info(char *arg);
|
||||
char *get_bootargs(void);
|
||||
void vsbl_set_bdf(int bnum, int snum, int fnum);
|
||||
@ -70,6 +71,7 @@ int add_e820_entry(struct e820_entry *e820, int len, uint64_t start,
|
||||
uint64_t size, uint32_t type);
|
||||
|
||||
int acrn_sw_load_bzimage(struct vmctx *ctx);
|
||||
int acrn_sw_load_elf(struct vmctx *ctx);
|
||||
int acrn_sw_load_vsbl(struct vmctx *ctx);
|
||||
int acrn_sw_load(struct vmctx *ctx);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user