diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 0fab62310..625cb9a6d 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -166,6 +166,8 @@ INCLUDE_PATH += $(BOARD_INFO_DIR) INCLUDE_PATH += $(BOARD_CFG_DIR) INCLUDE_PATH += $(SCENARIO_CFG_DIR) +override INCLUDE_PATH := $(realpath $(INCLUDE_PATH)) + CC ?= gcc AS ?= as AR ?= ar @@ -352,8 +354,6 @@ endif ifneq ($(FIRMWARE),uefi) CFLAGS += -DCONFIG_LAST_LEVEL_EPT_AT_BOOT endif -PRE_BUILD_SRCS += pre_build/static_checks.c -PRE_BUILD_OBJS := $(patsubst %.c,$(HV_OBJDIR)/%.o,$(PRE_BUILD_SRCS)) MODULES += $(LIB_MOD) MODULES += $(BOOT_MOD) @@ -376,6 +376,8 @@ MODULES += $(SYS_INIT_MOD) DISTCLEAN_OBJS := $(shell find $(BASEDIR) -name '*.o') VERSION := $(HV_OBJDIR)/include/version.h +PRE_BUILD_DIR := ../misc/hv_prebuild + .PHONY: all all: pre_build $(HV_OBJDIR)/$(HV_FILE).32.out $(HV_OBJDIR)/$(HV_FILE).bin @@ -388,7 +390,10 @@ install-debug: $(HV_OBJDIR)/$(HV_FILE).map $(HV_OBJDIR)/$(HV_FILE).out install -D $(HV_OBJDIR)/$(HV_FILE).map $(DESTDIR)$(libdir)/acrn/$(HV_FILE).$(BOARD).$(FIRMWARE).$(SCENARIO).map .PHONY: pre_build -pre_build: $(PRE_BUILD_OBJS) +pre_build: $(HV_OBJDIR)/$(HV_CONFIG_H) + @echo "Start pre-build static check ..." + $(MAKE) -C $(PRE_BUILD_DIR) BOARD=$(BOARD) SCENARIO=$(SCENARIO) TARGET_DIR=$(TARGET_DIR) + @$(HV_OBJDIR)/hv_prebuild_check.out .PHONY: header header: $(VERSION) $(HV_OBJDIR)/$(HV_CONFIG_H) @@ -467,19 +472,6 @@ distclean: PHONY: (VERSION) $(VERSION): $(HV_OBJDIR)/$(HV_CONFIG_H) - @if [ "$(SCENARIO)" = "" ]; then echo "Please specify SCENARIO for the build!"; exit 1; fi; - @if [ "$(BOARD)" = "" ]; then echo "Please specify BOARD for the build!"; exit 1; fi; - @echo "SCENARIO <$(SCENARIO)> for BOARD <$(BOARD)> is specified." - @if [ ! -d $(BOARD_CFG_DIR) ]; then \ - echo "Configurations for BOARD $(BOARD) is not found."; exit 1; \ - else \ - echo "Found BOARD configurations under $(BOARD_CFG_DIR)"; \ - fi; - @if [ ! -d $(SCENARIO_CFG_DIR) ]; then \ - echo "Configurations for SCENARIO $(SCENARIO) is not found."; exit 1; \ - else \ - echo "Found SCENARIO configurations under $(SCENARIO_CFG_DIR)"; \ - fi; touch $(VERSION) @COMMIT=`git rev-parse --verify --short HEAD 2>/dev/null`;\ DIRTY=`git diff-index --name-only HEAD`;\ diff --git a/hypervisor/arch/x86/configs/vm_config.c b/hypervisor/arch/x86/configs/vm_config.c index df313c8ad..2fd7fef76 100644 --- a/hypervisor/arch/x86/configs/vm_config.c +++ b/hypervisor/arch/x86/configs/vm_config.c @@ -23,7 +23,7 @@ uint8_t get_vm_severity(uint16_t vm_id) return vm_configs[vm_id].severity; } -static inline bool uuid_is_equal(const uint8_t *uuid1, const uint8_t *uuid2) +bool uuid_is_equal(const uint8_t *uuid1, const uint8_t *uuid2) { uint64_t uuid1_h = *(const uint64_t *)uuid1; uint64_t uuid1_l = *(const uint64_t *)(uuid1 + 8); diff --git a/misc/hv_prebuild/Makefile b/misc/hv_prebuild/Makefile new file mode 100644 index 000000000..eb887f8b0 --- /dev/null +++ b/misc/hv_prebuild/Makefile @@ -0,0 +1,54 @@ +HV_OBJDIR ?= $(CURDIR)/build +HV_CONFIG_H := $(HV_OBJDIR)/include/config.h +HV_SRC_DIR := ../../hypervisor + +ifneq ($(HV_CONFIG_H), $(wildcard $(HV_CONFIG_H))) + $(error $(HV_CONFIG_H) does not exist) +endif + +ifeq ($(BOARD),) + $(error please specify BOARD for the build!) +endif + +ifeq ($(SCENARIO),) + $(error please specify SCENARIO for the build!) +endif + +ifeq ($(TARGET_DIR),) + $(error please specify VM configs directory! ) +endif + +BOARD_INFO_DIR := $(TARGET_DIR)/boards/$(BOARD) +SCENARIO_CFG_DIR := $(TARGET_DIR)/scenarios/$(SCENARIO) +BOARD_CFG_DIR := $(SCENARIO_CFG_DIR)/$(BOARD) + +PRE_BUILD_SRCS += main.c +PRE_BUILD_SRCS += static_checks.c +PRE_BUILD_SRCS += vm_cfg_checks.c +PRE_BUILD_SRCS += $(HV_SRC_DIR)/arch/x86/configs/vm_config.c +PRE_BUILD_SRCS += $(SCENARIO_CFG_DIR)/vm_configurations.c +ifneq (,$(wildcard $(BOARD_CFG_DIR)/pci_dev.c)) +PRE_BUILD_SRCS += $(BOARD_CFG_DIR)/pci_dev.c +endif +PRE_BUILD_CFLAGS += -fno-stack-protector -fno-builtin -W -Wall +PRE_BUILD_INCLUDE := $(patsubst %, -I %, $(INCLUDE_PATH)) -include $(HV_CONFIG_H) -I . + +.PHONY: default +default: $(PRE_BUILD_SRCS) + @echo "SCENARIO <$(SCENARIO)> for BOARD <$(BOARD)> is specified." + @if [ ! -d $(BOARD_INFO_DIR) ]; then \ + echo "Information of BOARD $(BOARD) is not found."; exit 1; \ + else \ + echo "Found BOARD $(BOARD) information under $(BOARD_INFO_DIR)"; \ + fi; + @if [ ! -d $(SCENARIO_CFG_DIR) ]; then \ + echo "Configurations for SCENARIO $(SCENARIO) is not found."; exit 1; \ + else \ + echo "Found SCENARIO $(SCENARIO) configurations under $(SCENARIO_CFG_DIR)"; \ + fi; + @if [ ! -d $(BOARD_CFG_DIR) ]; then \ + echo "$(BOARD) configuration for SCENARIO $(SCENARIO) is not found."; exit 1; \ + else \ + echo "Found $(BOARD) configuration for SCENARIO $(SCENARIO) under $(BOARD_CFG_DIR)"; \ + fi; + $(CC) $(PRE_BUILD_SRCS) $(PRE_BUILD_INCLUDE) $(PRE_BUILD_CFLAGS) -o $(HV_OBJDIR)/hv_prebuild_check.out diff --git a/misc/hv_prebuild/hv_prebuild.h b/misc/hv_prebuild/hv_prebuild.h new file mode 100644 index 000000000..acf8efd51 --- /dev/null +++ b/misc/hv_prebuild/hv_prebuild.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* typedef size_t in types.h is conflicted with stdio.h, use below method as WR */ +#define size_t new_size_t +#include +#undef size_t + +bool uuid_is_equal(const uint8_t *uuid1, const uint8_t *uuid2); +bool sanitize_vm_config(void); diff --git a/misc/hv_prebuild/main.c b/misc/hv_prebuild/main.c new file mode 100644 index 000000000..5221339ef --- /dev/null +++ b/misc/hv_prebuild/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +int32_t main(void) +{ + int32_t ret = 0; + + if (!sanitize_vm_config()) { + printf("VM configuration check fail!\n"); + ret = -1; + } else { + printf("VM configuration check pass!\n"); + ret = 0; + } + return ret; +} diff --git a/hypervisor/pre_build/static_checks.c b/misc/hv_prebuild/static_checks.c similarity index 100% rename from hypervisor/pre_build/static_checks.c rename to misc/hv_prebuild/static_checks.c diff --git a/misc/hv_prebuild/vm_cfg_checks.c b/misc/hv_prebuild/vm_cfg_checks.c new file mode 100644 index 000000000..3e74c6fc4 --- /dev/null +++ b/misc/hv_prebuild/vm_cfg_checks.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2020 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +static uint8_t rtvm_uuids[][16] = { + PRE_RTVM_UUID1, + POST_RTVM_UUID1, +}; +static uint8_t safety_vm_uuid1[16] = SAFETY_VM_UUID1; + +/* sanity check for below structs is not needed, so use a empty struct instead */ +struct acrn_vm_pci_dev_config sos_pci_devs[CONFIG_MAX_PCI_DEV_NUM]; +const struct pci_vdev_ops vhostbridge_ops; + +#define PLATFORM_CPUS_MASK ((1UL << MAX_PCPU_NUM) - 1UL) + +/** + * return true if the input uuid is for safety VM + */ +static bool is_safety_vm_uuid(const uint8_t *uuid) +{ + /* TODO: Extend to check more safety VM uuid if we have more than one safety VM. */ + return uuid_is_equal(uuid, safety_vm_uuid1); +} + +/** + * return true if the input uuid is for RTVM + */ +static bool is_rtvm_uuid(const uint8_t *uuid) +{ + bool ret = false; + uint16_t i; + uint8_t *rtvm_uuid; + + for (i = 0U; i < ARRAY_SIZE(rtvm_uuids); i++) { + rtvm_uuid = rtvm_uuids[i]; + if (uuid_is_equal(uuid, rtvm_uuid)) { + ret = true; + break; + } + } + return ret; +} + +/** + * return true if no UUID collision is found in vm configs array start from vm_configs[vm_id] + * + * @pre vm_id < CONFIG_MAX_VM_NUM + */ +static bool check_vm_uuid_collision(uint16_t vm_id) +{ + uint16_t i; + bool ret = true; + struct acrn_vm_config *start_config = get_vm_config(vm_id); + struct acrn_vm_config *following_config; + + for (i = vm_id + 1U; i < CONFIG_MAX_VM_NUM; i++) { + following_config = get_vm_config(i); + if (uuid_is_equal(&start_config->uuid[0], &following_config->uuid[0])) { + ret = false; + break; + } + } + return ret; +} + +static bool check_vm_clos_config(uint16_t vm_id) +{ + uint16_t i; + uint16_t platform_clos_num = MAX_PLATFORM_CLOS_NUM; + bool ret = true; + struct acrn_vm_config *vm_config = get_vm_config(vm_id); + uint16_t vcpu_num = bitmap_weight(vm_config->cpu_affinity); + + for (i = 0U; i < vcpu_num; i++) { + if (((platform_clos_num != 0U) && (vm_config->clos[i] == platform_clos_num)) + || (vm_config->clos[i] > platform_clos_num)) { + printf("vm%u: vcpu%u clos(%u) exceed the max clos(%u).", + vm_id, i, vm_config->clos[i], platform_clos_num); + ret = false; + break; + } + } + return ret; +} + +/** + * @pre vm_config != NULL + */ +bool sanitize_vm_config(void) +{ + bool ret = true; + uint16_t vm_id, vuart_idx; + struct acrn_vm_config *vm_config; + + /* We need to setup a rule, that the vm_configs[] array should follow + * the order of PRE_LAUNCHED_VM first, and then SOS_VM. + */ + for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) { + vm_config = get_vm_config(vm_id); + + if ((vm_config->cpu_affinity == 0UL) || ((vm_config->cpu_affinity & ~PLATFORM_CPUS_MASK) != 0UL)) { + printf("%s: vm%u assigns invalid PCPU (affinity: 0x%016x)\n", __func__, vm_id, vm_config->cpu_affinity); + ret = false; + } + + switch (vm_config->load_order) { + case PRE_LAUNCHED_VM: + /* GUEST_FLAG_RT must be set if we have GUEST_FLAG_LAPIC_PASSTHROUGH set in guest_flags */ + if (((vm_config->guest_flags & GUEST_FLAG_LAPIC_PASSTHROUGH) != 0U) + && ((vm_config->guest_flags & GUEST_FLAG_RT) == 0U)) { + ret = false; + } else if (vm_config->epc.size != 0UL) { + ret = false; + } else if (is_safety_vm_uuid(vm_config->uuid) && (vm_config->severity != (uint8_t)SEVERITY_SAFETY_VM)) { + ret = false; + } else { + /* nothing to do here */ + } + break; + case SOS_VM: + if ((vm_config->severity != (uint8_t)SEVERITY_SOS) || ((vm_config->guest_flags & GUEST_FLAG_LAPIC_PASSTHROUGH) != 0U)) { + ret = false; + } + break; + case POST_LAUNCHED_VM: + if ((vm_config->severity == (uint8_t)SEVERITY_SAFETY_VM) || (vm_config->severity == (uint8_t)SEVERITY_SOS)) { + ret = false; + } + break; + default: + /* Nothing to do for a unknown VM, break directly. */ + break; + } + + if (ret) { + /* VM with RTVM uuid must have RTVM severity */ + if (is_rtvm_uuid(vm_config->uuid) && (vm_config->severity != (uint8_t)SEVERITY_RTVM)) { + ret = false; + } + + /* VM WITHOUT RTVM uuid must NOT have RTVM severity */ + if (!is_rtvm_uuid(vm_config->uuid) && (vm_config->severity == (uint8_t)SEVERITY_RTVM)) { + ret = false; + } + } + + if (ret) { + ret = check_vm_clos_config(vm_id); + } + + if (ret && + (((vm_config->epc.size | vm_config->epc.base) & ~PAGE_MASK) != 0UL)) { + ret = false; + } + + if (ret) { + /* make sure no identical UUID in following VM configurations */ + ret = check_vm_uuid_collision(vm_id); + } + + if (ret) { + /* vuart[1+] are used for VM communications */ + for (vuart_idx = 1U; vuart_idx < MAX_VUART_NUM_PER_VM; vuart_idx++) { + const struct vuart_config *vu_config = &vm_config->vuart[vuart_idx]; + + if (!(vu_config->type == VUART_LEGACY_PIO) && + (vu_config->addr.port_base == INVALID_COM_BASE)) { + if ((vu_config->t_vuart.vm_id >= CONFIG_MAX_VM_NUM) || + (vu_config->t_vuart.vm_id == vm_id)) { + printf("%s invalid vuart configuration for VM %d\n", __func__, vm_id); + ret = false; + } + } + } + } + + if (!ret) { + break; + } + } + return ret; +}