On 11/12/20 7:49 PM, Heinrich Schuchardt wrote:
> On 11/11/20 10:18 AM, Ilias Apalodimas wrote:
>> Since U-boot EFI implementation is getting richer it makes sense to
>> add support for EFI_TCG2_PROTOCOL taking advantage of any hardware TPM
>> available on the device.
>>
>> This is the initial implementation of the protocol which only adds
>> support for GetCapability(). It's limited in the newer and safer
>> TPMv2 devices.
>>
>> Signed-off-by: Ilias Apalodimas <ilias.apalodi...@linaro.org>
>> ---
>> * changes since v3:
>> - added check for maximum number of PCRs allowed
>> - replaced multiple return Xl with goto out tags
>> * changes since v2:
>> - added description about include/efi_tcg2.h
>> - switch bool to u8 for tpm_present_flag
>> - removed superfluous 'default n' from Kconfig
>> - use 'goto 'tag' when possible
>>
>> * changes since v1:
>> - change return variable of platform_get_tpm2_device() when used
>> - since more headers were included in patch #2 use them in offset
>>   calculations for all tpm commands
>> - change the size of the response buffer regardless of what
>>   tpm2_get_capability() is doing
>>  include/efi_loader.h       |   2 +
>>  include/efi_tcg2.h         |  94 +++++++
>>  lib/efi_loader/Kconfig     |   7 +
>>  lib/efi_loader/Makefile    |   1 +
>>  lib/efi_loader/efi_setup.c |   7 +
>>  lib/efi_loader/efi_tcg2.c  | 539 +++++++++++++++++++++++++++++++++++++
>>  6 files changed, 650 insertions(+)
>>  create mode 100644 include/efi_tcg2.h
>>  create mode 100644 lib/efi_loader/efi_tcg2.c
>>
>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>> index f550ced56876..e5015d865ec9 100644
>> --- a/include/efi_loader.h
>> +++ b/include/efi_loader.h
>> @@ -405,6 +405,8 @@ efi_status_t efi_console_register(void);
>>  efi_status_t efi_disk_register(void);
>>  /* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
>>  efi_status_t efi_rng_register(void);
>> +/* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
>> +efi_status_t efi_tcg2_register(void);
>>  /* Create handles and protocols for the partitions of a block device */
>>  int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
>>                             const char *if_typename, int diskid,
>> diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
>> new file mode 100644
>> index 000000000000..4214f767eaba
>> --- /dev/null
>> +++ b/include/efi_tcg2.h
>> @@ -0,0 +1,94 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Defines data structures and APIs that allow an OS to interact with UEFI
>> + * firmware to query information about the device
>> + *
>> + * Copyright (c) 2020, Linaro Limited
>> + */
>> +
>> +#if !defined _EFI_TCG2_PROTOCOL_H_
>> +#define _EFI_TCG2_PROTOCOL_H_
>> +
>> +#include <tpm-v2.h>
>> +
>> +#define EFI_TCG2_PROTOCOL_GUID \
>> +    EFI_GUID(0x607f766c, 0x7455, 0x42be, 0x93, \
>> +             0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
>> +
>> +/* TPMV2 only */
>> +#define TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
>> +
>> +/* SHA1, SHA256, SHA384, SHA512, TPM_ALG_SM3_256 */
>> +#define MAX_HASH_COUNT 5
>> +/* Algorithm Registry */
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA1    0x00000001
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA256  0x00000002
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA384  0x00000004
>> +#define EFI_TCG2_BOOT_HASH_ALG_SHA512  0x00000008
>> +#define EFI_TCG2_BOOT_HASH_ALG_SM3_256 0x00000010
>> +
>> +typedef u32 efi_tcg_event_log_bitmap;
>> +typedef u32 efi_tcg_event_log_format;
>> +typedef u32 efi_tcg_event_algorithm_bitmap;
>> +
>> +struct efi_tcg2_version {
>> +    u8 major;
>> +    u8 minor;
>> +};
>> +
>> +struct efi_tcg2_event_header {
>> +    u32 header_size;
>> +    u16 header_version;
>> +    u32 pcr_index;
>> +    u32 event_type;
>> +} __packed;
>> +
>> +struct efi_tcg2_event {
>> +    u32 size;
>> +    struct efi_tcg2_event_header header;
>> +    u8 event[];
>> +} __packed;
>> +
>> +struct efi_tcg2_boot_service_capability {
>> +    u8 size;
>> +    struct efi_tcg2_version structure_version;
>> +    struct efi_tcg2_version protocol_version;
>> +    efi_tcg_event_algorithm_bitmap hash_algorithm_bitmap;
>> +    efi_tcg_event_log_bitmap supported_event_logs;
>> +    u8 tpm_present_flag;
>> +    u16 max_command_size;
>> +    u16 max_response_size;
>> +    u32 manufacturer_id;
>> +    u32 number_of_pcr_banks;
>> +    efi_tcg_event_algorithm_bitmap active_pcr_banks;
>> +};
>> +
>> +#define boot_service_capability_min \
>> +    sizeof(struct efi_tcg2_boot_service_capability) - \
>> +    offsetof(struct efi_tcg2_boot_service_capability, number_of_pcr_banks)
>> +
>> +struct efi_tcg2_protocol {
>> +    efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this,
>> +                                           struct 
>> efi_tcg2_boot_service_capability *capability);
>> +    efi_status_t (EFIAPI * get_eventlog)(struct efi_tcg2_protocol *this,
>> +                                         efi_tcg_event_log_format 
>> log_format,
>> +                                         u64 *event_log_location, u64 
>> *event_log_last_entry,
>> +                                         bool *event_log_truncated);
>> +    efi_status_t (EFIAPI * hash_log_extend_event)(struct efi_tcg2_protocol 
>> *this,
>> +                                                  u64 flags, u64 
>> data_to_hash,
>> +                                                  u64 data_to_hash_len,
>> +                                                  struct efi_tcg2_event 
>> *efi_tcg_event);
>> +    efi_status_t (EFIAPI * submit_command)(struct efi_tcg2_protocol *this,
>> +                                           u32 input_parameter_block_size,
>> +                                           u8 *input_parameter_block,
>> +                                           u32 output_parameter_block_size,
>> +                                           u8 *output_parameter_block);
>> +    efi_status_t (EFIAPI * get_active_pcr_banks)(struct efi_tcg2_protocol 
>> *this,
>> +                                                 u32 *active_pcr_banks);
>> +    efi_status_t (EFIAPI * set_active_pcr_banks)(struct efi_tcg2_protocol 
>> *this,
>> +                                                 u32 active_pcr_banks);
>> +    efi_status_t (EFIAPI * get_result_of_set_active_pcr_banks)(struct 
>> efi_tcg2_protocol *this,
>> +                                                               u32 
>> *operation_present,
>> +                                                               u32 
>> *response);
>> +};
>> +#endif
>> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
>> index 075481428cdf..29ea14b2ee2a 100644
>> --- a/lib/efi_loader/Kconfig
>> +++ b/lib/efi_loader/Kconfig
>> @@ -184,6 +184,13 @@ config EFI_RNG_PROTOCOL
>>        Provide a EFI_RNG_PROTOCOL implementation using the hardware random
>>        number generator of the platform.
>>
>> +config EFI_TCG2_PROTOCOL
>> +    bool "EFI_TCG2_PROTOCOL support"
>> +    depends on TPM_V2
>> +    help
>> +      Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
>> +      of the platform.
>> +
>>  config EFI_LOAD_FILE2_INITRD
>>      bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk"
>>      default n
>> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
>> index 8892fb01e125..cd4b252a417c 100644
>> --- a/lib/efi_loader/Makefile
>> +++ b/lib/efi_loader/Makefile
>> @@ -53,6 +53,7 @@ obj-$(CONFIG_NET) += efi_net.o
>>  obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o
>>  obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o
>>  obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
>> +obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
>>  obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
>>  obj-y += efi_signature.o
>>
>> diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
>> index 45226c5c1a53..e206b60bb82c 100644
>> --- a/lib/efi_loader/efi_setup.c
>> +++ b/lib/efi_loader/efi_setup.c
>> @@ -156,6 +156,13 @@ efi_status_t efi_init_obj_list(void)
>>              if (ret != EFI_SUCCESS)
>>                      goto out;
>>      }
>> +
>> +    if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
>> +            ret = efi_tcg2_register();
>> +            if (ret != EFI_SUCCESS)
>> +                    goto out;
>> +    }
>> +
>>      /* Initialize variable services */
>>      ret = efi_init_variables();
>>      if (ret != EFI_SUCCESS)
>> diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
>> new file mode 100644
>> index 000000000000..d600cff66af1
>> --- /dev/null
>> +++ b/lib/efi_loader/efi_tcg2.c
>> @@ -0,0 +1,539 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * Defines APIs that allow an OS to interact with UEFI firmware to query
>> + * information about the device.
>> + * 
>> https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/
>> + *
>> + * Copyright (c) 2020, Linaro Limited
>> + */
>> +
>> +#define LOG_CATEGORY LOGC_EFI
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <efi_loader.h>
>> +#include <efi_tcg2.h>
>> +#include <log.h>
>> +#include <tpm-v2.h>
>> +#include <linux/unaligned/access_ok.h>
>> +#include <linux/unaligned/generic.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +/*
>> + * When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard 
>> offset.
>> + * Since the current tpm2_get_capability() response buffers starts at
>> + * 'union tpmu_capabilities data' of 'struct tpms_capability_data', 
>> calculate
>> + * the response size and offset once for all consumers
>> + */
>> +#define TPM2_RESPONSE_BUFFER_SIZE (sizeof(struct tpms_capability_data) - \
>> +                               offsetof(struct tpms_capability_data, data))
>> +#define properties_offset (offsetof(struct tpml_tagged_tpm_property, 
>> tpm_property) + \
>> +                       offsetof(struct tpms_tagged_property, value))
>> +
>> +const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID;
>> +
>> +/**
>> + * platform_get_tpm_device() - retrieve TPM device
>> + *
>> + * This function retrieves the udevice implementing a TPM
>> + *
>> + * This function may be overridden if special initialization is needed.
>> + *
>> + * @dev:    udevice
>> + * Return:  status code
>> + */
>> +__weak efi_status_t platform_get_tpm2_device(struct udevice **dev)
>> +{
>> +    int ret;
>> +    struct udevice *devp;
>> +
>> +    ret = uclass_get_device(UCLASS_TPM, 0, &devp);
>
> 'dm tree' on the sandbox shows:
>
> tpm           0  [   ]   google_sandbox_tpm    |-- tpm
> tpm           1  [   ]   sandbox_tpm2          |-- tpm2
>
> You have to loop over all TPM devices and look for one supporting TPMv2
> using tpm_get_version(dev).

You must also ensure that the device is probed. for_each_tpm_device()
does the probing for you:

__weak efi_status_t platform_get_tpm2_device(struct udevice **dev)
{
        for_each_tpm_device((*dev)) {
                if (tpm_get_version(*dev) == TPM_V2)
                        return EFI_SUCCESS;
        }
        return EFI_NOT_FOUND;
}

Best regards

Heinrich

Reply via email to