diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 22c7f3adb..f99a046d7 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -83,6 +83,7 @@ SRCS += hw/acpi/acpi.c #SRCS += core/bootrom.c SRCS += core/sw_load_common.c SRCS += core/sw_load_bzimage.c +SRCS += core/sw_load_vsbl.c SRCS += core/smbiostbl.c SRCS += core/mevent.c SRCS += core/gc.c diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c index 5e5dd8ef4..c0957087b 100644 --- a/devicemodel/core/main.c +++ b/devicemodel/core/main.c @@ -46,6 +46,7 @@ #include "types.h" #include "vmm.h" #include "vmmapi.h" +#include "sw_load.h" #include "cpuset.h" #include "dm.h" #include "acpi.h" @@ -72,6 +73,7 @@ char *vmname; int guest_ncpus; char *guest_uuid_str; +char *vsbl_file_name; bool stdio_in_use; static int guest_vmexit_on_hlt, guest_vmexit_on_pause; @@ -125,7 +127,8 @@ usage(int code) { fprintf(stderr, "Usage: %s [-abehuwxACHPSWY] [-c vcpus] [-g ] [-l ]\n" - " %*s [-m mem] [-p vcpu:hostcpu] [-s ] [-U uuid] \n" + " %*s [-m mem] [-p vcpu:hostcpu] [-s ] [-U uuid] \n" + " %*s [--vsbl vsbl_file_name] \n" " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create ACPI tables\n" " -c: # cpus (default 1)\n" @@ -150,8 +153,9 @@ usage(int code) " -k: kernel image path\n" " -r: ramdisk image path\n" " -B: bootargs for kernel\n" - " -v: version\n", - progname, (int)strlen(progname), ""); + " -v: version\n" + " --vsbl: vsbl file path\n", + progname, (int)strlen(progname), "", (int)strlen(progname), ""); exit(code); } @@ -545,6 +549,10 @@ sig_handler_term(int signo) mevent_notify(); } +enum { + CMD_OPT_VSBL = 1000, +}; + static struct option long_options[] = { {"no_x2apic_mode", no_argument, 0, 'a' }, {"acpi", no_argument, 0, 'A' }, @@ -573,6 +581,9 @@ static struct option long_options[] = { {"version", no_argument, 0, 'v' }, {"gvtargs", required_argument, 0, 'G' }, {"help", no_argument, 0, 'h' }, + + /* Following cmd option only has long option */ + {"vsbl", required_argument, 0, CMD_OPT_VSBL}, {0, 0, 0, 0 }, }; @@ -707,6 +718,12 @@ main(int argc, char *argv[]) case 'v': print_version(); break; + case CMD_OPT_VSBL: + if (acrn_parse_vsbl(optarg) != 0) { + errx(EX_USAGE, "invalid vsbl param %s", optarg); + exit(1); + } + break; case 'h': usage(0); default: diff --git a/devicemodel/core/sw_load_common.c b/devicemodel/core/sw_load_common.c index be3e83fb1..d637b422e 100644 --- a/devicemodel/core/sw_load_common.c +++ b/devicemodel/core/sw_load_common.c @@ -153,5 +153,8 @@ acrn_create_e820_table(struct vmctx *ctx, struct e820_entry *e820) int acrn_sw_load(struct vmctx *ctx) { - return acrn_sw_load_bzimage(ctx); + if (vsbl_file_name) + return acrn_sw_load_vsbl(ctx); + else + return acrn_sw_load_bzimage(ctx); } diff --git a/devicemodel/core/sw_load_vsbl.c b/devicemodel/core/sw_load_vsbl.c new file mode 100644 index 000000000..b22b49341 --- /dev/null +++ b/devicemodel/core/sw_load_vsbl.c @@ -0,0 +1,287 @@ +/*- + * 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 +#include + +#include "dm.h" +#include "acrn_common.h" +#include "vmmapi.h" +#include "sw_load.h" +#include "acpi.h" + + +/* If the vsbl is loaded by DM, the UOS memory layout will be like: + * + * | ... | + * +--------------------------------------------------+ + * | offset: 0xf2400 (ACPI table) | + * +--------------------------------------------------+ + * | ... | + * +--------------------------------------------------+ + * | offset: 16MB (vsbl image) | + * +--------------------------------------------------+ + * | ... | + * +--------------------------------------------------+ + * | offset: lowmem - 16K (partition blob) | + * +--------------------------------------------------+ + * | offset: lowmem - 12K (e820 table) | + * +--------------------------------------------------+ + * | offset: lowmem - 8K (boot_args_address) | + * +--------------------------------------------------+ + * | offset: lowmem - 6K (vsbl entry address) | + * +--------------------------------------------------+ + * | offset: lowmem - 4K (config_page with e820 table)| + * +--------------------------------------------------+ + */ + +/* Check default e820 table in sw_load_common.c for info about ctx->lowmem */ +#define CONFIGPAGE_OFF(ctx) ((ctx)->lowmem - 4*KB) +#define VSBL_ENTRY_OFF(ctx) ((ctx)->lowmem - 6*KB) +#define BOOTARGS_OFF(ctx) ((ctx)->lowmem - 8*KB) +#define E820_TABLE_OFF(ctx) ((ctx)->lowmem - 12*KB) +#define GUEST_PART_INFO_OFF(ctx) ((ctx)->lowmem - 16*KB) +/* vsbl real entry is saved in the first 4 bytes of vsbl image */ +#define VSBL_OFF(ctx) (16*MB) + +struct vsbl_para { + uint64_t e820_table_address; + uint64_t e820_entries; + uint64_t acpi_table_address; + uint64_t acpi_table_size; + uint64_t guest_part_info_address; + uint64_t guest_part_info_size; + uint64_t vsbl_address; + uint64_t vsbl_size; + uint64_t bootargs_address; + uint32_t trusty_enabled; + uint32_t key_info_lock; + uint32_t watchdog_reset; + uint32_t boot_device_address; +}; + +static char guest_part_info_path[STR_LEN]; +static int guest_part_info_size; +static bool with_guest_part_info; + +static char vsbl_path[STR_LEN]; +static int vsbl_size; + +static int boot_blk_bdf; + +#define LOW_8BIT(x) ((x) & 0xFF) +void +vsbl_set_bdf(int bnum, int snum, int fnum) +{ + boot_blk_bdf = (LOW_8BIT(bnum) << 16) | (LOW_8BIT(snum) << 8) | + LOW_8BIT(fnum); +} + +int +acrn_parse_guest_part_info(char *arg) +{ + int len = strlen(arg); + + if (len < STR_LEN) { + strncpy(guest_part_info_path, arg, len); + guest_part_info_path[len] = '\0'; + assert(check_image(guest_part_info_path) == 0); + + with_guest_part_info = true; + + printf("SW_LOAD: get partition blob path %s\n", + guest_part_info_path); + return 0; + } else + return -1; +} + +static int +acrn_prepare_guest_part_info(struct vmctx *ctx) +{ + FILE *fp; + int len, read; + + fp = fopen(guest_part_info_path, "r"); + if (fp == NULL) { + fprintf(stderr, + "SW_LOAD ERR: could not open partition blob %s\n", + guest_part_info_path); + return -1; + } + + fseek(fp, 0, SEEK_END); + len = ftell(fp); + if ((len + GUEST_PART_INFO_OFF(ctx)) > BOOTARGS_OFF(ctx)) { + fprintf(stderr, + "SW_LOAD ERR: too large partition blob\n"); + fclose(fp); + return -1; + } + + guest_part_info_size = len; + + fseek(fp, 0, SEEK_SET); + read = fread(ctx->baseaddr + GUEST_PART_INFO_OFF(ctx), + sizeof(char), len, fp); + if (read < len) { + 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 %d copy to guest 0x%lx\n", + guest_part_info_path, guest_part_info_size, + GUEST_PART_INFO_OFF(ctx)); + + return 0; +} + +int +acrn_parse_vsbl(char *arg) +{ + int len = strlen(arg); + + if (len < STR_LEN) { + strncpy(vsbl_path, arg, len); + vsbl_path[len] = '\0'; + assert(check_image(vsbl_path) == 0); + + vsbl_file_name = vsbl_path; + + printf("SW_LOAD: get vsbl path %s\n", + vsbl_path); + return 0; + } else + return -1; +} + +static int +acrn_prepare_vsbl(struct vmctx *ctx) +{ + FILE *fp; + int len, read; + + fp = fopen(vsbl_path, "r"); + if (fp == NULL) { + fprintf(stderr, + "SW_LOAD ERR: could not open vsbl file: %s\n", + vsbl_path); + return -1; + } + + fseek(fp, 0, SEEK_END); + len = ftell(fp); + if ((len + VSBL_OFF(ctx)) > GUEST_PART_INFO_OFF(ctx)) { + fprintf(stderr, + "SW_LOAD ERR: too large vsbl file\n"); + fclose(fp); + return -1; + } + + vsbl_size = len; + + fseek(fp, 0, SEEK_SET); + read = fread(ctx->baseaddr + VSBL_OFF(ctx), + sizeof(char), len, fp); + if (read < len) { + 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 %d copy to guest 0x%lx\n", + vsbl_path, vsbl_size, VSBL_OFF(ctx)); + + return 0; +} + +int +acrn_sw_load_vsbl(struct vmctx *ctx) +{ + int ret; + struct e820_entry *e820; + struct vsbl_para *vsbl_para; + uint64_t vsbl_start_addr = + (uint64_t)ctx->baseaddr + VSBL_OFF(ctx); + uint64_t *vsbl_entry = + (uint64_t *)(ctx->baseaddr + VSBL_ENTRY_OFF(ctx)); + uint64_t *cfg_offset = + (uint64_t *)(ctx->baseaddr + GUEST_CFG_OFFSET); + + *cfg_offset = ctx->lowmem; + + vsbl_para = (struct vsbl_para *) + (ctx->baseaddr + CONFIGPAGE_OFF(ctx)); + + memset(vsbl_para, 0x0, sizeof(struct vsbl_para)); + + e820 = (struct e820_entry *) + (ctx->baseaddr + E820_TABLE_OFF(ctx)); + + vsbl_para->e820_entries = acrn_create_e820_table(ctx, e820); + vsbl_para->e820_table_address = E820_TABLE_OFF(ctx); + + vsbl_para->acpi_table_address = get_acpi_base(); + vsbl_para->acpi_table_size = get_acpi_table_length(); + + if (with_bootargs) { + strcpy(ctx->baseaddr + BOOTARGS_OFF(ctx), get_bootargs()); + vsbl_para->bootargs_address = BOOTARGS_OFF(ctx); + } else { + vsbl_para->bootargs_address = 0; + } + + if (with_guest_part_info) { + ret = acrn_prepare_guest_part_info(ctx); + if (ret) + return ret; + vsbl_para->guest_part_info_address = GUEST_PART_INFO_OFF(ctx); + vsbl_para->guest_part_info_size = guest_part_info_size; + } else { + vsbl_para->guest_part_info_address = 0; + vsbl_para->guest_part_info_size = 0; + } + + ret = acrn_prepare_vsbl(ctx); + if (ret) + return ret; + + vsbl_para->vsbl_address = VSBL_OFF(ctx); + vsbl_para->vsbl_size = vsbl_size; + *vsbl_entry = *((uint32_t *) vsbl_start_addr); + + vsbl_para->boot_device_address = boot_blk_bdf; + + return 0; +} diff --git a/devicemodel/include/dm.h b/devicemodel/include/dm.h index d020e1cc9..8dd387caa 100644 --- a/devicemodel/include/dm.h +++ b/devicemodel/include/dm.h @@ -38,6 +38,7 @@ struct vmctx; extern int guest_ncpus; extern char *guest_uuid_str; +extern char *vsbl_file_name; extern char *vmname; extern bool stdio_in_use;