diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 71119c3b6..9100ebf2a 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -290,6 +290,7 @@ VP_BASE_C_SRCS += common/hv_main.c VP_BASE_C_SRCS += common/vm_load.c VP_BASE_C_SRCS += arch/x86/configs/pci_dev.c VP_BASE_C_SRCS += arch/x86/configs/vacpi.c +VP_BASE_C_SRCS += quirks/acrn_vm_fixup.c # virtual platform device model VP_DM_C_SRCS += dm/vpic.c diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 8adbcaafe..ef4e5a909 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -39,6 +39,7 @@ #include #include #include +#include /* Local variables */ @@ -897,6 +898,7 @@ void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config) int32_t err = 0; struct acrn_vm *vm = NULL; + acrn_vm_fixup(vm_id); /* SOS and pre-launched VMs launch on all pCPUs defined in vm_config->cpu_affinity */ err = create_vm(vm_id, vm_config->cpu_affinity, vm_config, &vm); diff --git a/hypervisor/boot/guest/vboot_info.c b/hypervisor/boot/guest/vboot_info.c index 27bcad211..bac840f32 100644 --- a/hypervisor/boot/guest/vboot_info.c +++ b/hypervisor/boot/guest/vboot_info.c @@ -277,7 +277,7 @@ static void init_vm_bootargs_info(struct acrn_vm *vm, const struct acrn_boot_inf /* @pre abi != NULL && tag != NULL */ -static struct abi_module *get_mod_by_tag(const struct acrn_boot_info *abi, const char *tag) +struct abi_module *get_mod_by_tag(const struct acrn_boot_info *abi, const char *tag) { uint8_t i; struct abi_module *mod = NULL; diff --git a/hypervisor/boot/include/acpi.h b/hypervisor/boot/include/acpi.h index 7fdefe358..2dc69906a 100644 --- a/hypervisor/boot/include/acpi.h +++ b/hypervisor/boot/include/acpi.h @@ -235,6 +235,9 @@ struct acpi_table_tpm2 { uint16_t reserved; uint64_t control_address; uint32_t start_method; + uint8_t start_method_spec_para[12]; + uint32_t laml; + uint64_t lasa; } __packed; void init_acpi(void); diff --git a/hypervisor/boot/include/boot.h b/hypervisor/boot/include/boot.h index 117f9caf0..a020b4bdd 100644 --- a/hypervisor/boot/include/boot.h +++ b/hypervisor/boot/include/boot.h @@ -78,5 +78,5 @@ int32_t init_multiboot2_info(uint32_t *registers); void init_acrn_boot_info(uint32_t *registers); int32_t sanitize_acrn_boot_info(struct acrn_boot_info *abi); struct acrn_boot_info *get_acrn_boot_info(void); - +struct abi_module *get_mod_by_tag(const struct acrn_boot_info *abi, const char *tag); #endif /* BOOT_H */ diff --git a/hypervisor/quirks/acrn_vm_fixup.c b/hypervisor/quirks/acrn_vm_fixup.c new file mode 100644 index 000000000..7f91368df --- /dev/null +++ b/hypervisor/quirks/acrn_vm_fixup.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include + +static void *get_acpi_mod_entry(const char *signature, void *acpi) +{ + struct acpi_table_xsdt *xsdt; + uint32_t i, entry_cnt = 0U; + struct acpi_table_header *header = NULL, *find = NULL; + + xsdt = acpi + VIRT_XSDT_ADDR - VIRT_ACPI_DATA_ADDR; + entry_cnt = (xsdt->header.length - sizeof(xsdt->header)) / (sizeof(xsdt->table_offset_entry[0])); + + for (i = 0; i < entry_cnt; i++) { + header = acpi + xsdt->table_offset_entry[i] - VIRT_ACPI_DATA_ADDR; + if (strncmp(header->signature, signature, ACPI_NAME_SIZE) == 0) { + find = header; + break; + } + } + + return find; +} + +static void tpm2_fixup(uint16_t vm_id) +{ + struct acpi_table_tpm2 *tpm2 = NULL, *native = NULL; + struct acrn_vm_config *config = get_vm_config(vm_id); + bool need_fix = false; + uint8_t checksum; + struct acrn_boot_info *abi = get_acrn_boot_info(); + struct abi_module *mod; + + mod = get_mod_by_tag(abi, config->acpi_config.acpi_mod_tag); + + tpm2 = get_acpi_mod_entry(ACPI_SIG_TPM2, mod->start); + native = get_acpi_tbl(ACPI_SIG_TPM2); + + if (config->pt_tpm2) { + if ((tpm2 != NULL) && (native != NULL)) { + /* Native has different start method */ + need_fix = tpm2->start_method != native->start_method; + + /* Native has event log */ + if (native->header.length == + sizeof(struct acpi_table_tpm2)) { + need_fix |= tpm2->header.length == 0x34U; + need_fix |= strncmp((char *)tpm2->start_method_spec_para, (char *)native->start_method_spec_para, + sizeof(tpm2->start_method_spec_para)) != 0; + need_fix |= tpm2->laml != native->laml; + need_fix |= tpm2->lasa != native->lasa; + } + + if (need_fix) { + pr_err("%s tpm2 fix start method and event log field", __FUNCTION__); + tpm2->start_method = native->start_method; + tpm2->header.length = native->header.length; + tpm2->header.revision = native->header.revision; + memcpy_s(&native->start_method_spec_para, sizeof(native->start_method_spec_para), + &tpm2->start_method_spec_para, sizeof(native->start_method_spec_para)); + tpm2->laml = native->laml; + tpm2->lasa = config->mmiodevs[0].mmiores[1].base_gpa; + + tpm2->header.checksum = 0; + checksum = calculate_checksum8(tpm2, sizeof(struct acpi_table_tpm2)); + tpm2->header.checksum = checksum; + + config->mmiodevs[0].mmiores[1].base_hpa = native->lasa; + config->mmiodevs[0].mmiores[1].size = tpm2->laml; + } + } else { + pr_err("VM or native can't find TPM2 ACPI table"); + } + } +} + +void acrn_vm_fixup(uint16_t vm_id) +{ + struct acrn_vm_config *vm_config = get_vm_config(vm_id); + + if ((vm_config->load_order == PRE_LAUNCHED_VM)) { + stac(); + tpm2_fixup(vm_id); + clac(); + } +} + diff --git a/hypervisor/quirks/fixup.h b/hypervisor/quirks/fixup.h new file mode 100644 index 000000000..58061240d --- /dev/null +++ b/hypervisor/quirks/fixup.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FIXUP_H_ +#define _FIXUP_H_ + +void acrn_vm_fixup(uint16_t vm_id); + +#endif /* _FIXUP_H_ */