Add UEFI TPM2 driver
Add support for driving a TPM via UEFI firmware provided drivers, and bind those devices from the UEFI app. Signed-off-by: Matthew Garrett <mgarrett@aurora.tech> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
committed by
Simon Glass
parent
4bb984a205
commit
f07b9497ba
@@ -209,6 +209,13 @@ config TPM2_MMIO
|
||||
to the device using the standard TPM Interface Specification (TIS)
|
||||
protocol.
|
||||
|
||||
config TPM2_EFI
|
||||
bool "UEFI firmware based TPM2 Interface"
|
||||
depends on TPM_V2 && EFI_APP
|
||||
help
|
||||
This driver supports the use of UEFI firmware-provided drivers for
|
||||
interfacing with a TPM 2.
|
||||
|
||||
endif # TPM_V2
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -16,3 +16,4 @@ obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_core.o tpm2_tis_spi.o
|
||||
obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o
|
||||
obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o
|
||||
obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o
|
||||
obj-$(CONFIG_TPM2_EFI) += tpm2_efi.o
|
||||
|
||||
97
drivers/tpm/tpm2_efi.c
Normal file
97
drivers/tpm/tpm2_efi.c
Normal file
@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Aurora Innovation, Inc. Copyright 2022.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <dm.h>
|
||||
#include <efi.h>
|
||||
#include <efi_api.h>
|
||||
#include <efi_tcg2.h>
|
||||
#include <malloc.h>
|
||||
#include <tpm-v2.h>
|
||||
|
||||
static int efi_tpm_bind(struct udevice *dev)
|
||||
{
|
||||
struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
|
||||
struct efi_tpm_plat *plat = dev_get_plat(dev);
|
||||
struct efi_tcg2_boot_service_capability caps;
|
||||
efi_status_t status;
|
||||
|
||||
caps.size = sizeof(caps);
|
||||
status = plat->proto->get_capability(plat->proto, &caps);
|
||||
if (status != EFI_SUCCESS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!caps.tpm_present_flag)
|
||||
return -ENODEV;
|
||||
|
||||
priv->pcr_count = 24;
|
||||
priv->pcr_select_min = 3;
|
||||
priv->version = TPM_V2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efi_tpm_open(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efi_tpm_close(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efi_tpm_xfer(struct udevice *dev, const u8 *sendbuf,
|
||||
size_t send_size, u8 *recvbuf,
|
||||
size_t *recv_len)
|
||||
{
|
||||
struct efi_tpm_plat *plat = dev_get_plat(dev);
|
||||
efi_status_t status;
|
||||
|
||||
status = plat->proto->submit_command(plat->proto, send_size,
|
||||
(u8 *)sendbuf, *recv_len,
|
||||
recvbuf);
|
||||
switch (status) {
|
||||
case EFI_BUFFER_TOO_SMALL:
|
||||
debug("%s:response length is bigger than receive buffer\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
case EFI_DEVICE_ERROR:
|
||||
debug("%s:received error from device on write\n", __func__);
|
||||
return -EIO;
|
||||
case EFI_INVALID_PARAMETER:
|
||||
debug("%s:invalid parameter\n", __func__);
|
||||
return -EINVAL;
|
||||
case EFI_SUCCESS:
|
||||
return 0;
|
||||
default:
|
||||
debug("%s:received unknown error 0x%lx\n", __func__, status);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int efi_tpm_desc(struct udevice *dev, char *buf, int size)
|
||||
{
|
||||
if (size < 9)
|
||||
return -ENOSPC;
|
||||
|
||||
return snprintf(buf, size, "UEFI TPM");
|
||||
}
|
||||
|
||||
static const struct tpm_ops efi_tpm_ops = {
|
||||
.open = efi_tpm_open,
|
||||
.close = efi_tpm_close,
|
||||
.get_desc = efi_tpm_desc,
|
||||
.xfer = efi_tpm_xfer,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(efi_tpm) = {
|
||||
.name = "efi_tpm",
|
||||
.id = UCLASS_TPM,
|
||||
.bind = efi_tpm_bind,
|
||||
.ops = &efi_tpm_ops,
|
||||
.plat_auto = sizeof(struct efi_tpm_plat),
|
||||
};
|
||||
@@ -510,6 +510,17 @@ struct efi_net_plat {
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* EFI attributes of the udevice handled by efi_tpm driver
|
||||
*
|
||||
* @handle: handle of the controller on which this driver is installed
|
||||
* @proto: pointer to the TCG2 EFI protocol
|
||||
*/
|
||||
struct efi_tpm_plat {
|
||||
efi_handle_t handle;
|
||||
struct efi_tcg2_protocol *proto;
|
||||
};
|
||||
|
||||
/* Base address of the EFI image */
|
||||
extern char image_base[];
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define _EFI_TCG2_PROTOCOL_H_
|
||||
|
||||
#include <efi_api.h>
|
||||
#include <part_efi.h>
|
||||
#include <tpm-v2.h>
|
||||
#include <tpm_tcg2.h>
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <dm.h>
|
||||
#include <efi.h>
|
||||
#include <efi_api.h>
|
||||
#include <efi_tcg2.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/global_data.h>
|
||||
@@ -247,6 +248,71 @@ static int setup_net(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_tpm() - Find all TPMs and setup EFI devices for them
|
||||
*
|
||||
* Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
|
||||
* if a required protocol is not supported
|
||||
*/
|
||||
static int setup_tpm(void)
|
||||
{
|
||||
efi_guid_t efi_tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
|
||||
struct efi_boot_services *boot = efi_get_boot();
|
||||
efi_uintn_t num_handles;
|
||||
efi_handle_t *handle;
|
||||
int ret, i;
|
||||
|
||||
if (!boot)
|
||||
return log_msg_ret("sys", -ENOSYS);
|
||||
|
||||
/* Find all devices which support the TCG2 protocol */
|
||||
ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_tcg2_guid, NULL,
|
||||
&num_handles, &handle);
|
||||
|
||||
if (ret)
|
||||
return 0;
|
||||
log_debug("Found %d TPM handles:\n", (int)num_handles);
|
||||
|
||||
for (i = 0; i < num_handles; i++) {
|
||||
struct efi_tcg2_protocol *proto;
|
||||
struct efi_tpm_plat *plat;
|
||||
struct udevice *dev;
|
||||
char name[18];
|
||||
|
||||
ret = boot->handle_protocol(handle[i], &efi_tcg2_guid,
|
||||
(void **)&proto);
|
||||
|
||||
if (ret != EFI_SUCCESS) {
|
||||
log_warning("- TPM %d failed (ret=0x%x)\n", i, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
plat = malloc(sizeof(*plat));
|
||||
if (!plat) {
|
||||
log_warning("- TPM %d failed to alloc platform data", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
plat->handle = handle[i];
|
||||
plat->proto = proto;
|
||||
ret = device_bind(dm_root(), DM_DRIVER_GET(efi_net), "efi_tpm",
|
||||
plat, ofnode_null(), &dev);
|
||||
if (ret) {
|
||||
log_warning("- bind TPM %d failed (ret=0x%x)\n", i,
|
||||
ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "efi_tpm_%x", dev_seq(dev));
|
||||
device_set_name(dev, name);
|
||||
|
||||
printf("%2d: %-12s\n", i, dev->name);
|
||||
}
|
||||
boot->free_pool(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* board_early_init_r() - Scan for UEFI devices that should be available
|
||||
*
|
||||
@@ -266,6 +332,9 @@ int board_early_init_r(void)
|
||||
ret = setup_net();
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = setup_tpm();
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user