mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-08-13 13:56:19 +00:00
HV: move vm configuration check to pre-build time
This patch will move the VM configuration check to pre-build stage, a test program will do the check for pre-defined VM configuration data before making hypervisor binary. If test failed, the make process will be aborted. So once the hypervisor binary is built successfully or start to run, it means the VM configuration has been sanitized. The patch did not add any new VM configuration check function, it just port the original sanitize_vm_config() function from cpu.c to static_checks.c with below change: 1. remove runtime rdt detection for clos check; 2. replace pr_err() from logmsg.h with printf() from stdio.h; 3. replace runtime call get_pcpu_nums() in ALL_CPUS_MASK macro with static defined MAX_PCPU_NUM; The BOARD/SCENARIO parameter check and configuration folder check is also moved to prebuild Makefile. Tracked-On: #5077 Signed-off-by: Victor Sun <victor.sun@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
parent
070ac3c265
commit
978f899029
@ -162,6 +162,8 @@ INCLUDE_PATH += $(HV_OBJDIR)/include
|
||||
INCLUDE_PATH += $(BOARD_CFG_DIR)
|
||||
INCLUDE_PATH += $(SCENARIO_CFG_DIR)
|
||||
|
||||
override INCLUDE_PATH := $(realpath $(INCLUDE_PATH))
|
||||
|
||||
CC ?= gcc
|
||||
AS ?= as
|
||||
AR ?= ar
|
||||
@ -343,8 +345,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)
|
||||
@ -412,8 +412,13 @@ install-debug: $(HV_OBJDIR)/$(HV_FILE).map $(HV_OBJDIR)/$(HV_FILE).out
|
||||
install -D $(HV_OBJDIR)/$(HV_FILE).out $(DESTDIR)$(libdir)/acrn/$(HV_FILE).$(BOARD).$(FIRMWARE).$(SCENARIO).out
|
||||
install -D $(HV_OBJDIR)/$(HV_FILE).map $(DESTDIR)$(libdir)/acrn/$(HV_FILE).$(BOARD).$(FIRMWARE).$(SCENARIO).map
|
||||
|
||||
PRE_BUILD_DIR := ../misc/hv_prebuild
|
||||
|
||||
.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=$(realpath $(TARGET_DIR))
|
||||
@$(HV_OBJDIR)/hv_prebuild_check.out
|
||||
|
||||
.PHONY: header
|
||||
header: $(VERSION) $(HV_OBJDIR)/$(HV_CONFIG_H) $(TARGET_ACPI_INFO_HEADER)
|
||||
@ -492,19 +497,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`;\
|
||||
|
@ -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);
|
||||
|
49
misc/hv_prebuild/Makefile
Normal file
49
misc/hv_prebuild/Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
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),)
|
||||
BOARD_CFG_DIR := $(HV_SRC_DIR)/arch/x86/configs/$(BOARD)
|
||||
SCENARIO_CFG_DIR := $(HV_SRC_DIR)/scenarios/$(SCENARIO)
|
||||
else
|
||||
BOARD_CFG_DIR := $(TARGET_DIR)/$(BOARD)
|
||||
SCENARIO_CFG_DIR := $(TARGET_DIR)/$(SCENARIO)
|
||||
endif
|
||||
|
||||
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 $(SCENARIO_CFG_DIR)/pci_dev.c))
|
||||
PRE_BUILD_SRCS += $(SCENARIO_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 $(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
|
13
misc/hv_prebuild/hv_prebuild.h
Normal file
13
misc/hv_prebuild/hv_prebuild.h
Normal file
@ -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 <stdio.h>
|
||||
#undef size_t
|
||||
|
||||
bool uuid_is_equal(const uint8_t *uuid1, const uint8_t *uuid2);
|
||||
bool sanitize_vm_config(void);
|
22
misc/hv_prebuild/main.c
Normal file
22
misc/hv_prebuild/main.c
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <hv_prebuild.h>
|
||||
|
||||
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;
|
||||
}
|
@ -29,6 +29,10 @@ typedef int32_t CAT_(CTA_DummyType,__LINE__)[(expr) ? 1 : -1]
|
||||
#error "CONFIG_HV_RAM_SIZE must be integral multiple of 2MB"
|
||||
#endif
|
||||
|
||||
#if ((CONFIG_MAX_IR_ENTRIES < 256U) || (CONFIG_MAX_IR_ENTRIES & (CONFIG_MAX_IR_ENTRIES -1)) != 0U)
|
||||
#error "CONFIG_MAX_IR_ENTRIES must >=256 and be 2^n"
|
||||
#endif
|
||||
|
||||
/* Build time sanity checks to make sure hard-coded offset
|
||||
* is matching the actual offset!
|
||||
*/
|
200
misc/hv_prebuild/vm_cfg_checks.c
Normal file
200
misc/hv_prebuild/vm_cfg_checks.c
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <bits.h>
|
||||
#include <page.h>
|
||||
#include <vm_config.h>
|
||||
#include <rdt.h>
|
||||
#include <vuart.h>
|
||||
#include <vpci.h>
|
||||
#include <hv_prebuild.h>
|
||||
|
||||
static uint8_t rtvm_uuid1[16] = 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 RTVM
|
||||
*
|
||||
* @pre vmid < CONFIG_MAX_VM_NUM
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @pre vmid < CONFIG_MAX_VM_NUM
|
||||
*/
|
||||
static bool is_rtvm_uuid(const uint8_t *uuid)
|
||||
{
|
||||
/* TODO: Extend to check more rtvm uuid if we have more than one RTVM. */
|
||||
return uuid_is_equal(uuid, rtvm_uuid1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
uint64_t pre_launch_pcpu_bitmap = 0UL;
|
||||
struct acrn_vm_config *vm_config;
|
||||
|
||||
/* All physical CPUs except ocuppied by Pre-launched VMs are all
|
||||
* belong to SOS_VM. i.e. The cpu_affinity of a SOS_VM is decided
|
||||
* by cpu_affinity status in PRE_LAUNCHED_VMs.
|
||||
* 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 & ~PLATFORM_CPUS_MASK) != 0UL) {
|
||||
printf("%s: vm%u assigns invalid PCPU (0x%llx)", __func__, vm_id, vm_config->cpu_affinity);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
switch (vm_config->load_order) {
|
||||
case PRE_LAUNCHED_VM:
|
||||
if (vm_config->cpu_affinity == 0UL) {
|
||||
printf("%s: Pre-launch VM has no pcpus!\n", __func__);
|
||||
ret = false;
|
||||
/* GUEST_FLAG_RT must be set if we have GUEST_FLAG_LAPIC_PASSTHROUGH set in guest_flags */
|
||||
} else 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 {
|
||||
pre_launch_pcpu_bitmap |= vm_config->cpu_affinity;
|
||||
}
|
||||
break;
|
||||
case SOS_VM:
|
||||
/* Deduct pcpus of PRE_LAUNCHED_VMs */
|
||||
vm_config->cpu_affinity = PLATFORM_CPUS_MASK ^ pre_launch_pcpu_bitmap;
|
||||
if ((vm_config->cpu_affinity == 0UL) || (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->cpu_affinity == 0UL) ||
|
||||
((vm_config->cpu_affinity & pre_launch_pcpu_bitmap) != 0UL)) {
|
||||
printf("%s: Post-launch VM has no pcpus or share pcpu with Pre-launch VM!\n", __func__);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if ((vm_config->severity == (uint8_t)SEVERITY_SAFETY_VM) ||
|
||||
(vm_config->severity == (uint8_t)SEVERITY_SOS)) {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Nothing to do for a unknown VM, break directly. */
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user