diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 89723fbd8..c3e6d6ae3 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -118,6 +118,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_ovmf.c SRCS += core/sw_load_elf.c SRCS += core/smbiostbl.c SRCS += core/mevent.c diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c index 2618f91fc..44e4ba6dd 100644 --- a/devicemodel/core/main.c +++ b/devicemodel/core/main.c @@ -83,6 +83,7 @@ char *vmname; int guest_ncpus; char *guest_uuid_str; char *vsbl_file_name; +char *ovmf_file_name; char *kernel_file_name; char *elf_file_name; uint8_t trusty_enabled; @@ -158,6 +159,7 @@ usage(int code) " --dump: show build-in VM configurations\n" #endif " --vsbl: vsbl file path\n" + " --ovmf: ovmf file path\n" " --part_info: guest partition info file path\n" " --enable_trusty: enable trusty for guest\n" " --ptdev_no_reset: disable reset check for ptdev\n" @@ -242,6 +244,9 @@ high_bios_size(void) { size_t size = 0; + if (ovmf_file_name) + size = ovmf_image_size(); + return roundup2(size, 2 * MB); } @@ -715,6 +720,7 @@ sig_handler_term(int signo) enum { CMD_OPT_VSBL = 1000, + CMD_OPT_OVMF, CMD_OPT_PART_INFO, CMD_OPT_TRUSTY_ENABLE, CMD_OPT_VIRTIO_POLL_ENABLE, @@ -752,6 +758,7 @@ static struct option long_options[] = { {"dump", required_argument, 0, CMD_OPT_DUMP}, #endif {"vsbl", required_argument, 0, CMD_OPT_VSBL}, + {"ovmf", required_argument, 0, CMD_OPT_OVMF}, {"part_info", required_argument, 0, CMD_OPT_PART_INFO}, {"enable_trusty", no_argument, 0, CMD_OPT_TRUSTY_ENABLE}, @@ -864,11 +871,17 @@ dm_run(int argc, char *argv[]) print_version(); break; case CMD_OPT_VSBL: - if (acrn_parse_vsbl(optarg) != 0) { + if (high_bios_size() == 0 && acrn_parse_vsbl(optarg) != 0) { errx(EX_USAGE, "invalid vsbl param %s", optarg); exit(1); } break; + case CMD_OPT_OVMF: + if (!vsbl_file_name && acrn_parse_ovmf(optarg) != 0) { + errx(EX_USAGE, "invalid ovmf param %s", optarg); + exit(1); + } + break; case CMD_OPT_PART_INFO: if (acrn_parse_guest_part_info(optarg) != 0) { errx(EX_USAGE, diff --git a/devicemodel/core/sw_load_common.c b/devicemodel/core/sw_load_common.c index 337161502..66030d965 100644 --- a/devicemodel/core/sw_load_common.c +++ b/devicemodel/core/sw_load_common.c @@ -239,6 +239,8 @@ acrn_sw_load(struct vmctx *ctx) { if (vsbl_file_name) return acrn_sw_load_vsbl(ctx); + else if (ovmf_file_name) + return acrn_sw_load_ovmf(ctx); else if (kernel_file_name) return acrn_sw_load_bzimage(ctx); else if (elf_file_name) diff --git a/devicemodel/core/sw_load_ovmf.c b/devicemodel/core/sw_load_ovmf.c new file mode 100644 index 000000000..f91e7cec9 --- /dev/null +++ b/devicemodel/core/sw_load_ovmf.c @@ -0,0 +1,158 @@ +/*- + * 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. + * + */ + +#include +#include +#include +#include + +#include "dm.h" +#include "vmmapi.h" +#include "sw_load.h" + + +/* ovmf binary layout: + * + * +--------------------------------------------------+ <--OVMF Top + * | |offset: Top - 0x10 (reset vector) | + * + SECFV |------------------------------------+ + * | |other | + * +--------------------------------------------------+ + * | | + * + FVMAIN_COMPACT + + * | | + * +--------------------------------------------------+ + * | | + * + NV data storage + + * | | + * +--------------------------------------------------+ + */ + +/* ovmf real entry is reset vector, which is (OVMF_TOP - 16) */ +#define OVMF_TOP(ctx) (4*GB) + +static char ovmf_path[STR_LEN]; +static size_t ovmf_size; + +extern int init_cmos_vrpmb(struct vmctx *ctx); + +size_t +ovmf_image_size(void) +{ + return ovmf_size; +} + +int +acrn_parse_ovmf(char *arg) +{ + int error; + size_t len = strlen(arg); + + if (len < STR_LEN) { + strncpy(ovmf_path, arg, len + 1); + error = check_image(ovmf_path, 2 * MB, &ovmf_size); + assert(!error); + + ovmf_file_name = ovmf_path; + printf("SW_LOAD: get ovmf path %s, size 0x%lx\n", + ovmf_path, ovmf_size); + return 0; + } else + return -1; +} + +static int +acrn_prepare_ovmf(struct vmctx *ctx) +{ + FILE *fp; + size_t read; + + fp = fopen(ovmf_path, "r"); + if (fp == NULL) { + fprintf(stderr, + "SW_LOAD ERR: could not open ovmf file: %s\n", + ovmf_path); + return -1; + } + + fseek(fp, 0, SEEK_END); + + if (ftell(fp) != ovmf_size) { + fprintf(stderr, + "SW_LOAD ERR: ovmf file changed\n"); + fclose(fp); + return -1; + } + + fseek(fp, 0, SEEK_SET); + read = fread(ctx->baseaddr + OVMF_TOP(ctx) - ovmf_size, + sizeof(char), ovmf_size, fp); + + if (read < ovmf_size) { + fprintf(stderr, + "SW_LOAD ERR: could not read whole partition blob\n"); + fclose(fp); + return -1; + } + + fclose(fp); + printf("SW_LOAD: partition blob %s size %lu copy to guest 0x%lx\n", + ovmf_path, ovmf_size, OVMF_TOP(ctx) - ovmf_size); + + return 0; +} + +int +acrn_sw_load_ovmf(struct vmctx *ctx) +{ + int ret; + + init_cmos_vrpmb(ctx); + + ret = acrn_prepare_ovmf(ctx); + + if (ret) + return ret; + + printf("SW_LOAD: ovmf_entry 0x%lx\n", OVMF_TOP(ctx) - 16); + + /* 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; + + /* CR0_ET | CR0_NE */ + ctx->bsp_regs.vcpu_regs.cr0 = 0x30U; + ctx->bsp_regs.vcpu_regs.cs_ar = 0x009FU; + ctx->bsp_regs.vcpu_regs.cs_sel = 0xF000U; + ctx->bsp_regs.vcpu_regs.cs_limit = 0xFFFFU; + ctx->bsp_regs.vcpu_regs.cs_base = (OVMF_TOP(ctx) - 16) & 0xFFFF0000UL; + ctx->bsp_regs.vcpu_regs.rip = (OVMF_TOP(ctx) - 16) & 0xFFFFUL; + + return 0; +} diff --git a/devicemodel/include/dm.h b/devicemodel/include/dm.h index 81a642044..0a949b737 100644 --- a/devicemodel/include/dm.h +++ b/devicemodel/include/dm.h @@ -38,6 +38,7 @@ extern int guest_ncpus; extern char *guest_uuid_str; extern uint8_t trusty_enabled; extern char *vsbl_file_name; +extern char *ovmf_file_name; extern char *kernel_file_name; extern char *elf_file_name; extern char *vmname; diff --git a/devicemodel/include/sw_load.h b/devicemodel/include/sw_load.h index 83b70242e..d62e90d82 100644 --- a/devicemodel/include/sw_load.h +++ b/devicemodel/include/sw_load.h @@ -55,11 +55,14 @@ struct e820_entry { extern const struct e820_entry e820_default_entries[NUM_E820_ENTRIES]; extern int with_bootargs; +size_t ovmf_image_size(void); + int acrn_parse_kernel(char *arg); 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_ovmf(char *arg); int acrn_parse_elf(char *arg); int acrn_parse_guest_part_info(char *arg); char *get_bootargs(void); @@ -73,6 +76,7 @@ int add_e820_entry(struct e820_entry *e820, int len, uint64_t start, 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_ovmf(struct vmctx *ctx); int acrn_sw_load(struct vmctx *ctx); #endif