mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-02 20:35:32 +00:00
dm: TPM2 passthrough for post-launched VM with eventlog support
This patch enables TPM2 passthrough to post-launched VM with eventlog support. User starts by providing command line "--acpidev_pt <TPM2_HID>", of which the <TPM2_HID> will be searched from /proc/iomem for TPM2 buffer start address and size. Furthermore, If TPM2 eventlog is supported, TPM2 eventlog information will be retrieved from sysfs TPM2 table and passed-through as well. v4 -> v5: move tpm2 related logic from acpi.c to tpm.c multiple API rename Tracked-On: #6686 Signed-off-by: Yifan Liu <yifan1.liu@intel.com> Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
parent
ad5eb6e23d
commit
00631f113f
@ -325,22 +325,6 @@ struct mmio_dev_ops tpm2 = {
|
||||
};
|
||||
DEFINE_MMIO_DEV(tpm2);
|
||||
|
||||
/* @pre (pt_tpm2 == true) */
|
||||
uint64_t get_mmio_dev_tpm2_base_gpa(void)
|
||||
{
|
||||
int i;
|
||||
uint64_t base_gpa = 0UL;
|
||||
|
||||
for (i = 0; i < mmio_dev_idx; i++) {
|
||||
if (!strcmp(mmio_devs[i].name, "MSFT0101")) {
|
||||
base_gpa = mmio_devs[i].dev.res[0].user_vm_pa;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return base_gpa;
|
||||
}
|
||||
|
||||
struct mmio_dev_ops pt_mmiodev = {
|
||||
.name = "MMIODEV",
|
||||
/* ToDo: we may allocate the gpa MMIO resource in a reserved MMIO region
|
||||
|
@ -126,9 +126,6 @@ struct basl_fio {
|
||||
char f_name[MAXPATHLEN];
|
||||
};
|
||||
|
||||
#define EFPRINTF(...) fprintf(__VA_ARGS__)
|
||||
#define EFFLUSH(x) fflush(x)
|
||||
|
||||
static bool acpi_table_is_valid(int num);
|
||||
|
||||
static int
|
||||
@ -783,39 +780,6 @@ basl_fwrite_facs(FILE *fp, struct vmctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
basl_fwrite_tpm2(FILE *fp, struct vmctx *ctx)
|
||||
{
|
||||
EFPRINTF(fp, "/*\n");
|
||||
EFPRINTF(fp, " * dm TPM2 template\n");
|
||||
EFPRINTF(fp, " */\n");
|
||||
|
||||
EFPRINTF(fp, "[0004]\t\tSignature : \"TPM2\"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tTable Length : 0000004C\n");
|
||||
EFPRINTF(fp, "[0001]\t\tRevision : 00\n");
|
||||
EFPRINTF(fp, "[0001]\t\tChecksum : 00\n");
|
||||
EFPRINTF(fp, "[0006]\t\tOem ID : \"ACRNDM\"\n");
|
||||
EFPRINTF(fp, "[0008]\t\tOem Table ID : \"DMTPM2 \"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tOem Revision : 00000000\n");
|
||||
|
||||
/* iasl will fill the compiler ID/revision fields */
|
||||
EFPRINTF(fp, "[0004]\t\tAsl Compiler ID : \"xxxx\"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tAsl Compiler Revision : 00000000\n");
|
||||
|
||||
EFPRINTF(fp, "[0002]\t\tPlatform Class : 0000\n");
|
||||
EFPRINTF(fp, "[0002]\t\tReserved : 0000\n");
|
||||
EFPRINTF(fp, "[0008]\t\tControl Address : %016lX\n", get_tpm_crb_mmio_addr() + (long)CRB_REGS_CTRL_REQ);
|
||||
EFPRINTF(fp, "[0004]\t\tStart Method : 00000007\n");
|
||||
|
||||
EFPRINTF(fp, "[0012]\t\tMethod Parameters : 00 00 00 00 00 00 00 00 00 00 00 00\n");
|
||||
EFPRINTF(fp, "[0004]\t\tMinimum Log Length : 00000000\n");
|
||||
EFPRINTF(fp, "[0008]\t\tLog Address : 0000000000000000\n");
|
||||
|
||||
EFFLUSH(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper routines for writing to the DSDT from other modules.
|
||||
*/
|
||||
@ -885,28 +849,6 @@ dsdt_fixed_mem32(uint32_t base, uint32_t length)
|
||||
dsdt_line(" )");
|
||||
}
|
||||
|
||||
static void tpm2_crb_fwrite_dsdt(void)
|
||||
{
|
||||
dsdt_line(" Scope (\\_SB)");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Device (TPM)");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Name (_HID, \"MSFT0101\" /* TPM 2.0 Security Device */) // _HID: Hardware ID");
|
||||
dsdt_line(" Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings");
|
||||
dsdt_line(" {");
|
||||
dsdt_indent(4);
|
||||
/* TODO: consider a better framework for mmio likes pci's vdev_write_dsdt. */
|
||||
dsdt_fixed_mem32(get_tpm_crb_mmio_addr(), TPM_CRB_MMIO_SIZE);
|
||||
dsdt_unindent(4);
|
||||
dsdt_line(" })");
|
||||
dsdt_line(" Method (_STA, 0, NotSerialized) // _STA: Status");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Return (0x0F)");
|
||||
dsdt_line(" }");
|
||||
dsdt_line(" }");
|
||||
dsdt_line(" }");
|
||||
}
|
||||
|
||||
static int
|
||||
basl_fwrite_dsdt(FILE *fp, struct vmctx *ctx)
|
||||
{
|
||||
@ -953,9 +895,6 @@ basl_fwrite_dsdt(FILE *fp, struct vmctx *ctx)
|
||||
|
||||
pm_write_dsdt(ctx, basl_ncpu);
|
||||
|
||||
if (ctx->tpm_dev || pt_tpm2)
|
||||
tpm2_crb_fwrite_dsdt();
|
||||
|
||||
dsdt_line("}");
|
||||
|
||||
if (dsdt_error != 0)
|
||||
|
@ -9,7 +9,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "acpi.h"
|
||||
#include "vmmapi.h"
|
||||
#include "tpm.h"
|
||||
#include "tpm_internal.h"
|
||||
@ -27,17 +29,145 @@ static int tpm_debug;
|
||||
#define STR_MAX_LEN 1024U
|
||||
static char *sock_path = NULL;
|
||||
static uint32_t vtpm_crb_mmio_addr = 0U;
|
||||
struct acpi_dev_pt_ops pt_acpi_dev;
|
||||
|
||||
#define TPM2_TABLE_SYSFS_PATH "/sys/firmware/acpi/tables/TPM2"
|
||||
|
||||
static inline int checksum(uint8_t *buf, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t sum = 0;
|
||||
for (i = 0; i < size; i++)
|
||||
sum += buf[i];
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
static int read_sysfs_tpm2_table(struct acpi_table_tpm2 *tpm2_out)
|
||||
{
|
||||
FILE *fp;
|
||||
size_t ch_read;
|
||||
struct acpi_table_tpm2 tpm2 = { 0 };
|
||||
|
||||
fp = fopen(TPM2_TABLE_SYSFS_PATH, "r");
|
||||
if (!fp)
|
||||
return -errno;
|
||||
|
||||
ch_read = fread(&tpm2, 1, sizeof(tpm2), fp);
|
||||
fclose(fp);
|
||||
|
||||
/* we may read less than sizeof(tpm2) as laml and lasa are optional */
|
||||
if (!ch_read)
|
||||
return -errno;
|
||||
|
||||
if (strncmp(tpm2.header.signature, "TPM2", 4) ||
|
||||
!checksum((uint8_t *)&tpm2, tpm2.header.length))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(tpm2_out, &tpm2, ch_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_tpm2_eventlog_supported(struct acpi_table_tpm2 *tpm2)
|
||||
{
|
||||
/* Per TCG ACPI spec ver 1.2 rev 8, if LAML and LASA field are present, length is 76 */
|
||||
return ((tpm2->header.length == 76) && tpm2->lasa && tpm2->laml);
|
||||
}
|
||||
|
||||
static int is_hid_tpm2_device(char *hid)
|
||||
{
|
||||
int ret;
|
||||
struct acpi_dev_pt_ops *ops = &pt_acpi_dev;
|
||||
ret = get_more_acpi_dev_info(hid, 0, ops);
|
||||
if (ret)
|
||||
return false;
|
||||
return (strstr(ops->modalias, "MSFT0101") != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TPM2 device with HID hid to tpm2dev to be passed-through.
|
||||
* If eventlog is also supported, it will be added to the second resource of the
|
||||
* tpm2dev->dev.
|
||||
*
|
||||
* @pre: hid should be a valid HID of the TPM2 device being passed-through.
|
||||
* @pre: tpm2dev != NULL
|
||||
*/
|
||||
static int init_tpm2_pt(char *hid, struct mmio_dev *tpm2dev)
|
||||
{
|
||||
int err = 0;
|
||||
uint64_t tpm2_buffer_hpa, tpm2_buffer_size;
|
||||
uint32_t base = 0;
|
||||
struct acpi_table_tpm2 tpm2 = { 0 };
|
||||
|
||||
/* TODO: Currently we did not validate if the hid is a valid one.
|
||||
* We trust it to be valid as specifying --acpidev_pt is regarded
|
||||
* as root user operation.
|
||||
*/
|
||||
if (!hid || !*hid)
|
||||
return -EINVAL;
|
||||
|
||||
/* parse /proc/iomem to find the address and size of tpm buffer */
|
||||
if (!get_mmio_hpa_resource(hid, &tpm2_buffer_hpa, &tpm2_buffer_size))
|
||||
return -ENODEV;
|
||||
|
||||
err = read_sysfs_tpm2_table(&tpm2);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((tpm2.start_method != 6) && (tpm2.start_method != 7)) {
|
||||
pr_err("TPM2 start method %d not supported.\n", tpm2.start_method);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((tpm2.control_address < tpm2_buffer_hpa) ||
|
||||
(tpm2.control_address > tpm2_buffer_hpa + tpm2_buffer_size)) {
|
||||
pr_err("TPM2 control area address 0x%016lX outside of the \
|
||||
requested address region 0x%016lX-0x%016lX\n", tpm2.control_address,
|
||||
tpm2_buffer_hpa, tpm2_buffer_hpa + tpm2_buffer_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((tpm2.control_address >= MMIO_DEV_BASE) && (tpm2.control_address <= MMIO_DEV_LIMIT)) {
|
||||
/* we don't support if tpm2 buffer falls in MMIO region */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strncpy(tpm2dev->name, "MSFT0101", 8);
|
||||
strncpy(tpm2dev->dev.name, "tpm2", 4);
|
||||
tpm2dev->dev.res[0].host_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].user_vm_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].size = tpm2_buffer_size;
|
||||
|
||||
/* Search for eventlog */
|
||||
if (is_tpm2_eventlog_supported(&tpm2) &&
|
||||
!mmio_dev_alloc_gpa_resource32(&base, tpm2.laml)) {
|
||||
tpm2dev->dev.res[1].host_pa = tpm2.lasa;
|
||||
tpm2dev->dev.res[1].user_vm_pa = base;
|
||||
tpm2dev->dev.res[1].size = tpm2.laml;
|
||||
}
|
||||
|
||||
pt_tpm2 = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t get_vtpm_crb_mmio_addr(void) {
|
||||
return vtpm_crb_mmio_addr;
|
||||
}
|
||||
|
||||
static struct acrn_mmiodev *get_tpm2_mmio_dev()
|
||||
{
|
||||
struct mmio_dev *dev = get_mmiodev("MSFT0101");
|
||||
return dev ? &dev->dev : NULL;
|
||||
}
|
||||
|
||||
uint32_t get_tpm_crb_mmio_addr(void)
|
||||
{
|
||||
uint32_t base;
|
||||
|
||||
if (pt_tpm2) {
|
||||
base = (uint32_t)get_mmio_dev_tpm2_base_gpa();
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
base = d ? (uint32_t)d->res[0].host_pa : 0U;
|
||||
} else {
|
||||
base = get_vtpm_crb_mmio_addr();
|
||||
}
|
||||
@ -45,6 +175,23 @@ uint32_t get_tpm_crb_mmio_addr(void)
|
||||
return base;
|
||||
}
|
||||
|
||||
static uint32_t get_tpm_crb_mmio_size(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d) ? d->res[0].size : TPM_CRB_MMIO_SIZE;
|
||||
}
|
||||
|
||||
static uint32_t get_tpm2_table_minimal_log_length(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].size : 0U;
|
||||
}
|
||||
|
||||
static uint64_t get_tpm2_table_log_address(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].user_vm_pa : 0UL;
|
||||
}
|
||||
|
||||
enum {
|
||||
SOCK_PATH_OPT = 0
|
||||
@ -109,5 +256,64 @@ void deinit_vtpm2(struct vmctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
struct acpi_dev_pt_ops pt_tpm2_dev_ops = { 0 };
|
||||
static void tpm_write_dsdt(struct vmctx *ctx)
|
||||
{
|
||||
if (ctx->tpm_dev || pt_tpm2) {
|
||||
dsdt_line(" Scope (\\_SB)");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Device (TPM)");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Name (_HID, \"MSFT0101\" /* TPM 2.0 Security Device */) // _HID: Hardware ID");
|
||||
dsdt_line(" Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings");
|
||||
dsdt_line(" {");
|
||||
dsdt_indent(4);
|
||||
dsdt_fixed_mem32(get_tpm_crb_mmio_addr(), get_tpm_crb_mmio_size());
|
||||
dsdt_unindent(4);
|
||||
dsdt_line(" })");
|
||||
dsdt_line(" Method (_STA, 0, NotSerialized) // _STA: Status");
|
||||
dsdt_line(" {");
|
||||
dsdt_line(" Return (0x0F)");
|
||||
dsdt_line(" }");
|
||||
dsdt_line(" }");
|
||||
dsdt_line(" }");
|
||||
}
|
||||
}
|
||||
|
||||
int basl_fwrite_tpm2(FILE *fp, struct vmctx *ctx)
|
||||
{
|
||||
EFPRINTF(fp, "/*\n");
|
||||
EFPRINTF(fp, " * dm TPM2 template\n");
|
||||
EFPRINTF(fp, " */\n");
|
||||
|
||||
EFPRINTF(fp, "[0004]\t\tSignature : \"TPM2\"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tTable Length : 0000004C\n");
|
||||
EFPRINTF(fp, "[0001]\t\tRevision : 00\n");
|
||||
EFPRINTF(fp, "[0001]\t\tChecksum : 00\n");
|
||||
EFPRINTF(fp, "[0006]\t\tOem ID : \"ACRNDM\"\n");
|
||||
EFPRINTF(fp, "[0008]\t\tOem Table ID : \"DMTPM2 \"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tOem Revision : 00000000\n");
|
||||
|
||||
/* iasl will fill the compiler ID/revision fields */
|
||||
EFPRINTF(fp, "[0004]\t\tAsl Compiler ID : \"xxxx\"\n");
|
||||
EFPRINTF(fp, "[0004]\t\tAsl Compiler Revision : 00000000\n");
|
||||
|
||||
EFPRINTF(fp, "[0002]\t\tPlatform Class : 0000\n");
|
||||
EFPRINTF(fp, "[0002]\t\tReserved : 0000\n");
|
||||
EFPRINTF(fp, "[0008]\t\tControl Address : %016lX\n", get_tpm_crb_mmio_addr() + (long)CRB_REGS_CTRL_REQ);
|
||||
EFPRINTF(fp, "[0004]\t\tStart Method : 00000007\n");
|
||||
|
||||
EFPRINTF(fp, "[0012]\t\tMethod Parameters : 00 00 00 00 00 00 00 00 00 00 00 00\n");
|
||||
EFPRINTF(fp, "[0004]\t\tMinimum Log Length : %08X\n", get_tpm2_table_minimal_log_length());
|
||||
EFPRINTF(fp, "[0008]\t\tLog Address : %016lX\n", get_tpm2_table_log_address());
|
||||
|
||||
EFFLUSH(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct acpi_dev_pt_ops pt_tpm2_dev_ops = {
|
||||
.match = is_hid_tpm2_device,
|
||||
.init = init_tpm2_pt,
|
||||
.write_dsdt = tpm_write_dsdt,
|
||||
};
|
||||
DEFINE_ACPI_PT_DEV(pt_tpm2_dev_ops);
|
||||
|
@ -65,6 +65,9 @@ struct acpi_table_hdr {
|
||||
/* All dynamic table entry no. */
|
||||
#define NHLT_ENTRY_NO 8
|
||||
|
||||
#define EFPRINTF(...) fprintf(__VA_ARGS__)
|
||||
#define EFFLUSH(x) fflush(x)
|
||||
|
||||
void acpi_table_enable(int num);
|
||||
uint32_t get_acpi_base(void);
|
||||
uint32_t get_acpi_table_length(void);
|
||||
|
@ -38,7 +38,6 @@ int init_mmio_devs(struct vmctx *ctx);
|
||||
void deinit_mmio_devs(struct vmctx *ctx);
|
||||
|
||||
int mmio_dev_alloc_gpa_resource32(uint32_t *addr, uint32_t size_in);
|
||||
uint64_t get_mmio_dev_tpm2_base_gpa(void);
|
||||
|
||||
#define MMIO_DEV_BASE 0xF0000000U
|
||||
#define MMIO_DEV_LIMIT 0xFE000000U
|
||||
|
@ -8,11 +8,26 @@
|
||||
#ifndef _TPM_H_
|
||||
#define _TPM_H_
|
||||
|
||||
#include "mmio_dev.h"
|
||||
#include "acpi.h"
|
||||
|
||||
#define TPM_CRB_MMIO_ADDR 0xFED40000UL
|
||||
#define TPM_CRB_MMIO_SIZE 0x5000U
|
||||
|
||||
uint32_t get_vtpm_crb_mmio_addr(void);
|
||||
uint32_t get_tpm_crb_mmio_addr(void);
|
||||
int basl_fwrite_tpm2(FILE *fp, struct vmctx *ctx);
|
||||
|
||||
struct acpi_table_tpm2 {
|
||||
struct acpi_table_hdr header;
|
||||
uint16_t platform_class;
|
||||
uint16_t reserved;
|
||||
uint64_t control_address;
|
||||
uint32_t start_method;
|
||||
uint8_t start_method_spec_para[12];
|
||||
uint32_t laml;
|
||||
uint64_t lasa;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* TPM CRB registers */
|
||||
enum {
|
||||
|
Loading…
Reference in New Issue
Block a user