hv: tpm2: do tpm2 fixup for security vm

ACRN used to prepare the vTPM2 ACPI Table for pre-launched VM at the build stage
using config tools. This is OK if the TPM2 ACPI Table never changes. However,
TPM2 ACPI Table may be changed in some conditions: change BIOS configuration or
update BIOS.

This patch do TPM2 fixup to update the vTPM2 ACPI Table and TPM2 MMIO resource
configuration according to the physical TPM2 ACPI Table.

Tracked-On: #6366
Signed-off-by: Tao Yuhong <yuhong.tao@intel.com>
Signed-off-by: Fei Li <fei1.li@intel.com>
This commit is contained in:
Fei Li 2021-08-06 14:12:13 +08:00 committed by wenlingz
parent f81b39225c
commit 74e68e39d1
11 changed files with 125 additions and 4 deletions

View File

@ -287,6 +287,9 @@ 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
ifeq ($(CONFIG_SECURITY_VM_FIXUP),y)
VP_BASE_C_SRCS += quirks/security_vm_fixup.c
endif
# virtual platform device model
VP_DM_C_SRCS += dm/vpic.c

View File

@ -39,6 +39,9 @@
#include <asm/rtcm.h>
#include <asm/irq.h>
#include <uart16550.h>
#ifdef CONFIG_SECURITY_VM_FIXUP
#include <quirks/security_vm_fixup.h>
#endif
/* Local variables */
@ -898,6 +901,9 @@ void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config)
int32_t err = 0;
struct acrn_vm *vm = NULL;
#ifdef CONFIG_SECURITY_VM_FIXUP
security_vm_fixup(vm_id);
#endif
/* 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);

View File

@ -124,7 +124,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;

View File

@ -235,6 +235,11 @@ struct acpi_table_tpm2 {
uint16_t reserved;
uint64_t control_address;
uint32_t start_method;
#ifdef CONFIG_SECURITY_VM_FIXUP
uint8_t start_method_spec_para[12];
uint32_t laml;
uint64_t lasa;
#endif
} __packed;
void init_acpi(void);

View File

@ -73,4 +73,5 @@ 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 */

View File

@ -56,6 +56,7 @@
#define GUEST_FLAG_HIDE_MTRR (1UL << 3U) /* Whether hide MTRR from VM */
#define GUEST_FLAG_RT (1UL << 4U) /* Whether the vm is RT-VM */
#define GUEST_FLAG_NVMX_ENABLED (1UL << 5U) /* Whether this VM supports nested virtualization */
#define GUEST_FLAG_TPM2_FIXUP (1UL << 6U) /* Whether this VM needs to do TPM2 fixup */
/* TODO: We may need to get this addr from guest ACPI instead of hardcode here */
#define VIRTUAL_SLEEP_CTL_ADDR 0x400U /* Pre-launched VM uses ACPI reduced HW mode and sleep control register */

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <types.h>
#include <asm/vm_config.h>
#include <asm/guest/vm.h>
#include <vacpi.h>
#include <logmsg.h>
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 *vtpm2 = NULL, *tpm2 = NULL;
struct acrn_vm_config *config = get_vm_config(vm_id);
uint8_t checksum, i;
struct acrn_boot_info *abi = get_acrn_boot_info();
struct acrn_mmiodev *dev = NULL;
struct abi_module *mod = get_mod_by_tag(abi, config->acpi_config.acpi_mod_tag);
if (mod != NULL) {
vtpm2 = get_acpi_mod_entry(ACPI_SIG_TPM2, mod->start);
tpm2 = get_acpi_tbl(ACPI_SIG_TPM2);
if (config->pt_tpm2 && (vtpm2 != NULL) && (tpm2 != NULL)) {
for (i = 0U; i < MAX_MMIO_DEV_NUM; i++) {
if (strncmp(config->mmiodevs[i].name, "tpm2", 4) == 0) {
dev = &config->mmiodevs[i];
break;
}
}
if (dev != NULL) {
vtpm2->start_method = tpm2->start_method;
memcpy_s(&vtpm2->start_method_spec_para, sizeof(tpm2->start_method_spec_para),
&tpm2->start_method_spec_para, sizeof(tpm2->start_method_spec_para));
/* tpm2 has event log */
if (tpm2->laml != 0U) {
vtpm2->header.length = tpm2->header.length;
vtpm2->header.revision = tpm2->header.revision;
vtpm2->laml = tpm2->laml;
vtpm2->lasa = dev->res[1].user_vm_pa;
/* update log buffer length/HPA in vm_config */
dev->res[1].size = tpm2->laml;
dev->res[1].host_pa = tpm2->lasa;
}
/* update checksum */
vtpm2->header.checksum = 0;
checksum = calculate_checksum8(vtpm2, sizeof(struct acpi_table_tpm2));
vtpm2->header.checksum = checksum;
} else {
pr_err("%s, no TPM2 in acrn_vm_config", __func__);
}
}
}
}
void security_vm_fixup(uint16_t vm_id)
{
struct acrn_vm_config *vm_config = get_vm_config(vm_id);
if ((vm_config->guest_flags & GUEST_FLAG_TPM2_FIXUP) != 0UL) {
stac();
tpm2_fixup(vm_id);
clac();
}
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (C) 2018 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _SECURITY_VM_FIXUP_H_
#define _SECURITY_VM_FIXUP_H_
void security_vm_fixup(uint16_t vm_id);
#endif /* _SECURITY_VM_FIXUP_H_ */

View File

@ -23,7 +23,7 @@ DATACHECK_SCHEMA_FILE = SOURCE_ROOT_DIR + 'misc/config_tools/schema/datachecks.x
PY_CACHES = ["__pycache__", "../board_config/__pycache__", "../scenario_config/__pycache__"]
GUEST_FLAG = ["0", "0UL", "GUEST_FLAG_SECURE_WORLD_ENABLED", "GUEST_FLAG_LAPIC_PASSTHROUGH",
"GUEST_FLAG_IO_COMPLETION_POLLING", "GUEST_FLAG_NVMX_ENABLED", "GUEST_FLAG_HIDE_MTRR",
"GUEST_FLAG_RT"]
"GUEST_FLAG_RT", "GUEST_FLAG_TPM2_FIXUP"]
MULTI_ITEM = ["guest_flag", "pcpu_id", "vcpu_clos", "input", "block", "network", "pci_dev", "shm_region", "communication_vuart"]

View File

@ -37,7 +37,8 @@
IO polling to completion
- ``GUEST_FLAG_HIDE_MTRR`` specify that MTRR is hidden from the VM
- ``GUEST_FLAG_RT`` specify that the VM is an RT-VM (real-time)
- ``GUEST_FLAG_NVMX_ENABLED`` specify that the VM supports nested virtualization</xs:documentation>
- ``GUEST_FLAG_NVMX_ENABLED`` specify that the VM supports nested virtualization
- ``GUEST_FLAG_TPM2_FIXUP`` specify that the VM needs to do fixup for TPM2 passthrough</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="" />
@ -49,6 +50,7 @@
<xs:enumeration value="GUEST_FLAG_HIDE_MTRR" />
<xs:enumeration value="GUEST_FLAG_RT" />
<xs:enumeration value="GUEST_FLAG_NVMX_ENABLED" />
<xs:enumeration value="GUEST_FLAG_TPM2_FIXUP" />
</xs:restriction>
</xs:simpleType>

View File

@ -50,7 +50,7 @@
<xsl:when test="count(vm[vm_type='SOS_VM'])">
<xsl:value-of select="acrn:comment('Bitmask of guest flags that can be programmed by device model. Other bits are set by hypervisor only.')" />
<xsl:value-of select="$newline" />
<xsl:value-of select="acrn:define('DM_OWNED_GUEST_FLAG_MASK', '(GUEST_FLAG_SECURE_WORLD_ENABLED | GUEST_FLAG_LAPIC_PASSTHROUGH | GUEST_FLAG_RT | GUEST_FLAG_IO_COMPLETION_POLLING)', '')" />
<xsl:value-of select="acrn:define('DM_OWNED_GUEST_FLAG_MASK', '(GUEST_FLAG_SECURE_WORLD_ENABLED | GUEST_FLAG_LAPIC_PASSTHROUGH | GUEST_FLAG_RT | GUEST_FLAG_IO_COMPLETION_POLLING | GUEST_FLAG_TPM2_FIXUP)', '')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="acrn:define('DM_OWNED_GUEST_FLAG_MASK', '0', 'UL')" />