From a53fb767cf62b300a6b975bc174c892bc103be17 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 5 Jun 2024 16:58:27 +0200 Subject: [PATCH 01/13] cmd: fwu: Also print information about size It is useful when structure is also used for saving vendor data covered by CRC32. Signed-off-by: Michal Simek Reviewed-by: Ilias Apalodimas --- cmd/fwu_mdata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c index 3c8be576ac7..9c048d69a13 100644 --- a/cmd/fwu_mdata.c +++ b/cmd/fwu_mdata.c @@ -22,6 +22,7 @@ static void print_mdata(struct fwu_data *data) printf("\tFWU Metadata\n"); printf("crc32: %#x\n", data->crc32); printf("version: %#x\n", data->version); + printf("size: %#x\n", data->metadata_size); printf("active_index: %#x\n", data->active_index); printf("previous_active_index: %#x\n", data->previous_active_index); From 392e6c14e341f0042106fd220ea32c810e3abc83 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 16 Jun 2024 10:59:48 +0200 Subject: [PATCH 02/13] doc: update requirements.txt Update all required Python packages to current release. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- doc/sphinx/requirements.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/sphinx/requirements.txt b/doc/sphinx/requirements.txt index 54eb70aa92c..306b05a995e 100644 --- a/doc/sphinx/requirements.txt +++ b/doc/sphinx/requirements.txt @@ -1,18 +1,18 @@ alabaster==0.7.16 -Babel==2.14.0 -certifi==2023.11.17 +Babel==2.15.0 +certifi==2024.6.2 charset-normalizer==3.3.2 docutils==0.20.1 idna==3.7 imagesize==1.4.1 Jinja2==3.1.4 -MarkupSafe==2.1.3 -packaging==23.2 -Pygments==2.17.2 -requests==2.32.2 +MarkupSafe==2.1.5 +packaging==24.1 +Pygments==2.18.0 +requests==2.32.3 six==1.16.0 snowballstemmer==2.2.0 -Sphinx==7.2.6 +Sphinx==7.3.7 sphinx-prompt==1.8.0 sphinx-rtd-theme==2.0.0 sphinxcontrib-applehelp==1.0.8 @@ -22,4 +22,4 @@ sphinxcontrib-jquery==4.1 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.7 sphinxcontrib-serializinghtml==1.1.10 -urllib3==2.1.0 +urllib3==2.2.1 From a5e31659cfebf74949096300617d847a4dcccba9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 18 Jun 2024 08:32:30 +0200 Subject: [PATCH 03/13] spl: correct link to FIT specification Replace the invalid link to the FIT file format specification. Signed-off-by: Heinrich Schuchardt --- common/spl/spl_fit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index 988125be008..2a097f4464c 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -587,7 +587,7 @@ __weak void *spl_load_simple_fit_fix_load(const void *fit) static void warn_deprecated(const char *msg) { printf("DEPRECATED: %s\n", msg); - printf("\tSee doc/uImage.FIT/source_file_format.txt\n"); + printf("\tSee https://fitspec.osfw.foundation/\n"); } static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node, From b94217adc97449ab0f3cf07ad253e1e7e15e0aec Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 18 Jun 2024 14:23:48 +0200 Subject: [PATCH 04/13] efi_selftest: can't have measured device-tree with kaslr-seed Test that we don't have a /chosen/kaslr-seed property if we measure the device-tree. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_selftest/efi_selftest_fdt.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c index aa3b13ae3ab..a4b0cef20e4 100644 --- a/lib/efi_selftest/efi_selftest_fdt.c +++ b/lib/efi_selftest/efi_selftest_fdt.c @@ -227,6 +227,13 @@ static int execute(void) return EFI_ST_FAILURE; } } + if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL_MEASURE_DTB)) { + str = get_property(u"kaslr-seed", u"chosen"); + if (str) { + efi_st_error("kaslr-seed with measured fdt\n"); + return EFI_ST_FAILURE; + } + } if (IS_ENABLED(CONFIG_RISCV)) { u32 fdt_hartid; From 0b07b5ed8153869e2e71a7e008d2ced78756d657 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 18 Jun 2024 14:29:13 +0200 Subject: [PATCH 05/13] cmd: correct kaslrseed description The number of random bytes generated is hard coded as 8. The command takes no argument. Signed-off-by: Heinrich Schuchardt --- cmd/kaslrseed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c index e0d3c7fe748..e9b0e3d5985 100644 --- a/cmd/kaslrseed.c +++ b/cmd/kaslrseed.c @@ -68,7 +68,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int argc, char *const } U_BOOT_LONGHELP(kaslrseed, - "[n]\n" + "\n" " - append random bytes to chosen kaslr-seed node\n"); U_BOOT_CMD( From 6ea97fe44159dbbcb7bea914654da7f99dc348fa Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:13 +0300 Subject: [PATCH 06/13] efi_loader: remove unused TCG algo definitions commit 97707f12fdab ("tpm: Support boot measurements") moved some of the EFI TCG code to the TPM subsystem. Those definitions are now in tpm-v2.h. Let's remove the stale entries Reviewed-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- include/efi_tcg2.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h index a75b5a35b6e..54490969b2d 100644 --- a/include/efi_tcg2.h +++ b/include/efi_tcg2.h @@ -25,14 +25,6 @@ #define PE_COFF_IMAGE 0x0000000000000010 #define EFI_TCG2_MAX_PCR_INDEX 23 - -/* 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 - #define EFI_TCG2_FINAL_EVENTS_TABLE_VERSION 1 #define TPM2_EVENT_LOG_SIZE CONFIG_EFI_TCG2_PROTOCOL_EVENTLOG_SIZE From 27b462cec15c994f9490425094c7e405d539f3e7 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:14 +0300 Subject: [PATCH 07/13] tpm: Move TCG headers into a separate file commit 97707f12fdab ("tpm: Support boot measurements") moved out code from the EFI subsystem into the TPM one to support measurements when booting with !EFI. Those were moved directly into the TPM subsystem and in the tpm-v2.c library. In hindsight, it would have been better to move it in new files since the TCG2 is governed by its own spec, it's overeall cleaner and also easier to enable certain parts of the TPM functionality. So let's start moving the headers in a new file containing the TCG specific bits. Signed-off-by: Ilias Apalodimas --- boot/bootm.c | 1 + include/efi_tcg2.h | 1 + include/tpm-v2.h | 131 ---------------------------------------- include/tpm_tcg2.h | 146 +++++++++++++++++++++++++++++++++++++++++++++ lib/tpm-v2.c | 1 + 5 files changed, 149 insertions(+), 131 deletions(-) create mode 100644 include/tpm_tcg2.h diff --git a/boot/bootm.c b/boot/bootm.c index 3de87eb185d..376d63aafc9 100644 --- a/boot/bootm.c +++ b/boot/bootm.c @@ -24,6 +24,7 @@ #include #include #include +#include #if defined(CONFIG_CMD_USB) #include #endif diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h index 54490969b2d..8dfb1bc9527 100644 --- a/include/efi_tcg2.h +++ b/include/efi_tcg2.h @@ -18,6 +18,7 @@ #include #include +#include /* TPMV2 only */ #define TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002 diff --git a/include/tpm-v2.h b/include/tpm-v2.h index c9d5cb6d3e5..38d79207e32 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -55,59 +55,6 @@ struct udevice; #define TPM2_PT_MAX_COMMAND_SIZE (u32)(TPM2_PT_FIXED + 30) #define TPM2_PT_MAX_RESPONSE_SIZE (u32)(TPM2_PT_FIXED + 31) -/* - * event types, cf. - * "TCG Server Management Domain Firmware Profile Specification", - * rev 1.00, 2020-05-01 - */ -#define EV_POST_CODE ((u32)0x00000001) -#define EV_NO_ACTION ((u32)0x00000003) -#define EV_SEPARATOR ((u32)0x00000004) -#define EV_ACTION ((u32)0x00000005) -#define EV_TAG ((u32)0x00000006) -#define EV_S_CRTM_CONTENTS ((u32)0x00000007) -#define EV_S_CRTM_VERSION ((u32)0x00000008) -#define EV_CPU_MICROCODE ((u32)0x00000009) -#define EV_PLATFORM_CONFIG_FLAGS ((u32)0x0000000A) -#define EV_TABLE_OF_DEVICES ((u32)0x0000000B) -#define EV_COMPACT_HASH ((u32)0x0000000C) - -/* - * event types, cf. - * "TCG PC Client Platform Firmware Profile Specification", Family "2.0" - * Level 00 Version 1.05 Revision 23, May 7, 2021 - */ -#define EV_EFI_EVENT_BASE ((u32)0x80000000) -#define EV_EFI_VARIABLE_DRIVER_CONFIG ((u32)0x80000001) -#define EV_EFI_VARIABLE_BOOT ((u32)0x80000002) -#define EV_EFI_BOOT_SERVICES_APPLICATION ((u32)0x80000003) -#define EV_EFI_BOOT_SERVICES_DRIVER ((u32)0x80000004) -#define EV_EFI_RUNTIME_SERVICES_DRIVER ((u32)0x80000005) -#define EV_EFI_GPT_EVENT ((u32)0x80000006) -#define EV_EFI_ACTION ((u32)0x80000007) -#define EV_EFI_PLATFORM_FIRMWARE_BLOB ((u32)0x80000008) -#define EV_EFI_HANDOFF_TABLES ((u32)0x80000009) -#define EV_EFI_PLATFORM_FIRMWARE_BLOB2 ((u32)0x8000000A) -#define EV_EFI_HANDOFF_TABLES2 ((u32)0x8000000B) -#define EV_EFI_VARIABLE_BOOT2 ((u32)0x8000000C) -#define EV_EFI_HCRTM_EVENT ((u32)0x80000010) -#define EV_EFI_VARIABLE_AUTHORITY ((u32)0x800000E0) -#define EV_EFI_SPDM_FIRMWARE_BLOB ((u32)0x800000E1) -#define EV_EFI_SPDM_FIRMWARE_CONFIG ((u32)0x800000E2) - -#define EFI_CALLING_EFI_APPLICATION \ - "Calling EFI Application from Boot Option" -#define EFI_RETURNING_FROM_EFI_APPLICATION \ - "Returning from EFI Application from Boot Option" -#define EFI_EXIT_BOOT_SERVICES_INVOCATION \ - "Exit Boot Services Invocation" -#define EFI_EXIT_BOOT_SERVICES_FAILED \ - "Exit Boot Services Returned with Failure" -#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED \ - "Exit Boot Services Returned with Success" -#define EFI_DTB_EVENT_STRING \ - "DTB DATA" - /* TPMS_TAGGED_PROPERTY Structure */ struct tpms_tagged_property { u32 property; @@ -149,23 +96,6 @@ struct tpms_capability_data { union tpmu_capabilities data; } __packed; -/** - * SHA1 Event Log Entry Format - * - * @pcr_index: PCRIndex event extended to - * @event_type: Type of event (see EFI specs) - * @digest: Value extended into PCR index - * @event_size: Size of event - * @event: Event data - */ -struct tcg_pcr_event { - u32 pcr_index; - u32 event_type; - u8 digest[TPM2_SHA1_DIGEST_SIZE]; - u32 event_size; - u8 event[]; -} __packed; - /** * Definition of TPMU_HA Union */ @@ -199,67 +129,6 @@ struct tpml_digest_values { struct tpmt_ha digests[TPM2_NUM_PCR_BANKS]; } __packed; -/** - * Crypto Agile Log Entry Format - * - * @pcr_index: PCRIndex event extended to - * @event_type: Type of event - * @digests: List of digestsextended to PCR index - * @event_size: Size of the event data - * @event: Event data - */ -struct tcg_pcr_event2 { - u32 pcr_index; - u32 event_type; - struct tpml_digest_values digests; - u32 event_size; - u8 event[]; -} __packed; - -/** - * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information - * - * @algorithm_id: algorithm defined in enum tpm2_algorithms - * @digest_size: size of the algorithm - */ -struct tcg_efi_spec_id_event_algorithm_size { - u16 algorithm_id; - u16 digest_size; -} __packed; - -#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03" -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2 -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0 -#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2 - -/** - * struct TCG_EfiSpecIDEventStruct - content of the event log header - * - * @signature: signature, set to Spec ID Event03 - * @platform_class: class defined in TCG ACPI Specification - * Client Common Header. - * @spec_version_minor: minor version - * @spec_version_major: major version - * @spec_version_errata: major version - * @uintn_size: size of the efi_uintn_t fields used in various - * data structures used in this specification. - * 0x01 indicates u32 and 0x02 indicates u64 - * @number_of_algorithms: hashing algorithms used in this event log - * @digest_sizes: array of number_of_algorithms pairs - * 1st member defines the algorithm id - * 2nd member defines the algorithm size - */ -struct tcg_efi_spec_id_event { - u8 signature[16]; - u32 platform_class; - u8 spec_version_minor; - u8 spec_version_major; - u8 spec_errata; - u8 uintn_size; - u32 number_of_algorithms; - struct tcg_efi_spec_id_event_algorithm_size digest_sizes[]; -} __packed; - /** * TPM2 Structure Tags for command/response buffers. * diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h new file mode 100644 index 00000000000..581ff6f24a4 --- /dev/null +++ b/include/tpm_tcg2.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Defines APIs and structures that adhere to + * https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ + * https://trustedcomputinggroup.org/resource/tcg-efi-protocol-specification/ + * + * Copyright (c) 2020 Linaro Limited + */ + +#ifndef __TPM_TCG_V2_H +#define __TPM_TCG_V2_H + +#include + +/* + * event types, cf. + * "TCG Server Management Domain Firmware Profile Specification", + * rev 1.00, 2020-05-01 + */ +#define EV_POST_CODE ((u32)0x00000001) +#define EV_NO_ACTION ((u32)0x00000003) +#define EV_SEPARATOR ((u32)0x00000004) +#define EV_ACTION ((u32)0x00000005) +#define EV_TAG ((u32)0x00000006) +#define EV_S_CRTM_CONTENTS ((u32)0x00000007) +#define EV_S_CRTM_VERSION ((u32)0x00000008) +#define EV_CPU_MICROCODE ((u32)0x00000009) +#define EV_PLATFORM_CONFIG_FLAGS ((u32)0x0000000A) +#define EV_TABLE_OF_DEVICES ((u32)0x0000000B) +#define EV_COMPACT_HASH ((u32)0x0000000C) + +/* + * event types, cf. + * "TCG PC Client Platform Firmware Profile Specification", Family "2.0" + * Level 00 Version 1.05 Revision 23, May 7, 2021 + */ +#define EV_EFI_EVENT_BASE ((u32)0x80000000) +#define EV_EFI_VARIABLE_DRIVER_CONFIG ((u32)0x80000001) +#define EV_EFI_VARIABLE_BOOT ((u32)0x80000002) +#define EV_EFI_BOOT_SERVICES_APPLICATION ((u32)0x80000003) +#define EV_EFI_BOOT_SERVICES_DRIVER ((u32)0x80000004) +#define EV_EFI_RUNTIME_SERVICES_DRIVER ((u32)0x80000005) +#define EV_EFI_GPT_EVENT ((u32)0x80000006) +#define EV_EFI_ACTION ((u32)0x80000007) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB ((u32)0x80000008) +#define EV_EFI_HANDOFF_TABLES ((u32)0x80000009) +#define EV_EFI_PLATFORM_FIRMWARE_BLOB2 ((u32)0x8000000A) +#define EV_EFI_HANDOFF_TABLES2 ((u32)0x8000000B) +#define EV_EFI_VARIABLE_BOOT2 ((u32)0x8000000C) +#define EV_EFI_HCRTM_EVENT ((u32)0x80000010) +#define EV_EFI_VARIABLE_AUTHORITY ((u32)0x800000E0) +#define EV_EFI_SPDM_FIRMWARE_BLOB ((u32)0x800000E1) +#define EV_EFI_SPDM_FIRMWARE_CONFIG ((u32)0x800000E2) + +#define EFI_CALLING_EFI_APPLICATION \ + "Calling EFI Application from Boot Option" +#define EFI_RETURNING_FROM_EFI_APPLICATION \ + "Returning from EFI Application from Boot Option" +#define EFI_EXIT_BOOT_SERVICES_INVOCATION \ + "Exit Boot Services Invocation" +#define EFI_EXIT_BOOT_SERVICES_FAILED \ + "Exit Boot Services Returned with Failure" +#define EFI_EXIT_BOOT_SERVICES_SUCCEEDED \ + "Exit Boot Services Returned with Success" +#define EFI_DTB_EVENT_STRING \ + "DTB DATA" + +/** + * struct TCG_EfiSpecIdEventAlgorithmSize - hashing algorithm information + * + * @algorithm_id: algorithm defined in enum tpm2_algorithms + * @digest_size: size of the algorithm + */ +struct tcg_efi_spec_id_event_algorithm_size { + u16 algorithm_id; + u16 digest_size; +} __packed; + +/** + * SHA1 Event Log Entry Format + * + * @pcr_index: PCRIndex event extended to + * @event_type: Type of event (see EFI specs) + * @digest: Value extended into PCR index + * @event_size: Size of event + * @event: Event data + */ +struct tcg_pcr_event { + u32 pcr_index; + u32 event_type; + u8 digest[TPM2_SHA1_DIGEST_SIZE]; + u32 event_size; + u8 event[]; +} __packed; + +/** + * Crypto Agile Log Entry Format + * + * @pcr_index: PCRIndex event extended to + * @event_type: Type of event + * @digests: List of digestsextended to PCR index + * @event_size: Size of the event data + * @event: Event data + */ +struct tcg_pcr_event2 { + u32 pcr_index; + u32 event_type; + struct tpml_digest_values digests; + u32 event_size; + u8 event[]; +} __packed; + +/** + * struct TCG_EfiSpecIDEventStruct - content of the event log header + * + * @signature: signature, set to Spec ID Event03 + * @platform_class: class defined in TCG ACPI Specification + * Client Common Header. + * @spec_version_minor: minor version + * @spec_version_major: major version + * @spec_version_errata: major version + * @uintn_size: size of the efi_uintn_t fields used in various + * data structures used in this specification. + * 0x01 indicates u32 and 0x02 indicates u64 + * @number_of_algorithms: hashing algorithms used in this event log + * @digest_sizes: array of number_of_algorithms pairs + * 1st member defines the algorithm id + * 2nd member defines the algorithm size + */ +struct tcg_efi_spec_id_event { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintn_size; + u32 number_of_algorithms; + struct tcg_efi_spec_id_event_algorithm_size digest_sizes[]; +} __packed; + +#define TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03 "Spec ID Event03" +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2 +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0 +#define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2 + +#endif /* __TPM_TCG_V2_H */ diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 91526af33ac..c3832bb7f76 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include From a56037a461b54d9f17b8cd82bfe9543a159c0c2f Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:15 +0300 Subject: [PATCH 08/13] tpm: Move TCG functions into a separate file The previous patch is moving the TPM TCG headers in their own file for a cleaner API. Move the functions in their own file as well. Signed-off-by: Ilias Apalodimas --- include/tpm-v2.h | 190 ------------- include/tpm_tcg2.h | 189 ++++++++++++ lib/Makefile | 2 + lib/tpm-v2.c | 675 +------------------------------------------ lib/tpm_tcg2.c | 695 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 887 insertions(+), 864 deletions(-) create mode 100644 lib/tpm_tcg2.c diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 38d79207e32..fc7c58204e5 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -399,188 +399,6 @@ enum { HR_NV_INDEX = TPM_HT_NV_INDEX << HR_SHIFT, }; -/** - * struct tcg2_event_log - Container for managing the platform event log - * - * @log: Address of the log - * @log_position: Current entry position - * @log_size: Log space available - * @found: Boolean indicating if an existing log was discovered - */ -struct tcg2_event_log { - u8 *log; - u32 log_position; - u32 log_size; - bool found; -}; - -/** - * Create a list of digests of the supported PCR banks for a given input data - * - * @dev TPM device - * @input Data - * @length Length of the data to calculate the digest - * @digest_list List of digests to fill in - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, - struct tpml_digest_values *digest_list); - -/** - * Get the event size of the specified digests - * - * @digest_list List of digests for the event - * - * Return: Size in bytes of the event - */ -u32 tcg2_event_get_size(struct tpml_digest_values *digest_list); - -/** - * tcg2_get_active_pcr_banks - * - * @dev TPM device - * @active_pcr_banks Bitmask of PCR algorithms supported - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks); - -/** - * tcg2_log_append - Append an event to an event log - * - * @pcr_index Index of the PCR - * @event_type Type of event - * @digest_list List of digests to add - * @size Size of event - * @event Event data - * @log Log buffer to append the event to - */ -void tcg2_log_append(u32 pcr_index, u32 event_type, - struct tpml_digest_values *digest_list, u32 size, - const u8 *event, u8 *log); - -/** - * Extend the PCR with specified digests - * - * @dev TPM device - * @pcr_index Index of the PCR - * @digest_list List of digests to extend - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list); - -/** - * Read the PCR into a list of digests - * - * @dev TPM device - * @pcr_index Index of the PCR - * @digest_list List of digests to extend - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list); - -/** - * Measure data into the TPM PCRs and the platform event log. - * - * @dev TPM device - * @log Platform event log - * @pcr_index Index of the PCR - * @size Size of the data or 0 for event only - * @data Pointer to the data or NULL for event only - * @event_type Event log type - * @event_size Size of the event - * @event Pointer to the event - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, - u32 pcr_index, u32 size, const u8 *data, u32 event_type, - u32 event_size, const u8 *event); - -#define tcg2_measure_event(dev, elog, pcr_index, event_type, size, event) \ - tcg2_measure_data(dev, elog, pcr_index, 0, NULL, event_type, size, \ - event) - -/** - * Prepare the event log buffer. This function tries to discover an existing - * event log in memory from a previous bootloader stage. If such a log exists - * and the PCRs are not extended, the log is "replayed" to extend the PCRs. - * If no log is discovered, create the log header. - * - * @dev TPM device - * @elog Platform event log. The log pointer and log_size - * members must be initialized to either 0 or to a valid - * memory region, in which case any existing log - * discovered will be copied to the specified memory - * region. - * @ignore_existing_log Boolean to indicate whether or not to ignore an - * existing platform log in memory - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, - bool ignore_existing_log); - -/** - * Begin measurements. - * - * @dev TPM device - * @elog Platform event log. The log pointer and log_size - * members must be initialized to either 0 or to a valid - * memory region, in which case any existing log - * discovered will be copied to the specified memory - * region. - * @ignore_existing_log Boolean to indicate whether or not to ignore an - * existing platform log in memory - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, - bool ignore_existing_log); - -/** - * Stop measurements and record separator events. - * - * @dev TPM device - * @elog Platform event log - * @error Boolean to indicate whether an error ocurred or not - */ -void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, - bool error); - -/** - * Get the platform event log address and size. - * - * @dev TPM device - * @addr Address of the log - * @size Size of the log - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size); - -/** - * Get the first TPM2 device found. - * - * @dev TPM device - * - * Return: zero on success, negative errno otherwise - */ -int tcg2_platform_get_tpm2(struct udevice **dev); - -/** - * Platform-specific function for handling TPM startup errors - * - * @dev TPM device - * @rc The TPM response code - */ -void tcg2_platform_startup_error(struct udevice *dev, int rc); - /** * Issue a TPM2_Startup command. * @@ -897,12 +715,4 @@ enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); */ const char *tpm2_algorithm_name(enum tpm2_algorithms); -/** - * tpm2_algorithm_to_mask() - Get a TCG hash mask for algorithm - * - * @hash_alg: TCG defined algorithm - * Return: TCG hashing algorithm bitmaps (or 0 if algo not supported) - */ -u32 tpm2_algorithm_to_mask(enum tpm2_algorithms); - #endif /* __TPM_V2_H */ diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h index 581ff6f24a4..4e4ea1e8067 100644 --- a/include/tpm_tcg2.h +++ b/include/tpm_tcg2.h @@ -142,5 +142,194 @@ struct tcg_efi_spec_id_event { #define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2 2 #define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 0 #define TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2 2 +/** + * struct tcg2_event_log - Container for managing the platform event log + * + * @log: Address of the log + * @log_position: Current entry position + * @log_size: Log space available + * @found: Boolean indicating if an existing log was discovered + */ +struct tcg2_event_log { + u8 *log; + u32 log_position; + u32 log_size; + bool found; +}; + +/** + * Create a list of digests of the supported PCR banks for a given input data + * + * @dev TPM device + * @input Data + * @length Length of the data to calculate the digest + * @digest_list List of digests to fill in + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, + struct tpml_digest_values *digest_list); + +/** + * Get the event size of the specified digests + * + * @digest_list List of digests for the event + * + * Return: Size in bytes of the event + */ +u32 tcg2_event_get_size(struct tpml_digest_values *digest_list); + +/** + * tcg2_get_active_pcr_banks + * + * @dev TPM device + * @active_pcr_banks Bitmask of PCR algorithms supported + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks); + +/** + * tcg2_log_append - Append an event to an event log + * + * @pcr_index Index of the PCR + * @event_type Type of event + * @digest_list List of digests to add + * @size Size of event + * @event Event data + * @log Log buffer to append the event to + */ +void tcg2_log_append(u32 pcr_index, u32 event_type, + struct tpml_digest_values *digest_list, u32 size, + const u8 *event, u8 *log); + +/** + * Extend the PCR with specified digests + * + * @dev TPM device + * @pcr_index Index of the PCR + * @digest_list List of digests to extend + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list); + +/** + * Read the PCR into a list of digests + * + * @dev TPM device + * @pcr_index Index of the PCR + * @digest_list List of digests to extend + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list); + +/** + * Measure data into the TPM PCRs and the platform event log. + * + * @dev TPM device + * @log Platform event log + * @pcr_index Index of the PCR + * @size Size of the data or 0 for event only + * @data Pointer to the data or NULL for event only + * @event_type Event log type + * @event_size Size of the event + * @event Pointer to the event + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, + u32 pcr_index, u32 size, const u8 *data, u32 event_type, + u32 event_size, const u8 *event); + +#define tcg2_measure_event(dev, elog, pcr_index, event_type, size, event) \ + tcg2_measure_data(dev, elog, pcr_index, 0, NULL, event_type, size, \ + event) + +/** + * Prepare the event log buffer. This function tries to discover an existing + * event log in memory from a previous bootloader stage. If such a log exists + * and the PCRs are not extended, the log is "replayed" to extend the PCRs. + * If no log is discovered, create the log header. + * + * @dev TPM device + * @elog Platform event log. The log pointer and log_size + * members must be initialized to either 0 or to a valid + * memory region, in which case any existing log + * discovered will be copied to the specified memory + * region. + * @ignore_existing_log Boolean to indicate whether or not to ignore an + * existing platform log in memory + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, + bool ignore_existing_log); + +/** + * Begin measurements. + * + * @dev TPM device + * @elog Platform event log. The log pointer and log_size + * members must be initialized to either 0 or to a valid + * memory region, in which case any existing log + * discovered will be copied to the specified memory + * region. + * @ignore_existing_log Boolean to indicate whether or not to ignore an + * existing platform log in memory + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, + bool ignore_existing_log); + +/** + * Stop measurements and record separator events. + * + * @dev TPM device + * @elog Platform event log + * @error Boolean to indicate whether an error ocurred or not + */ +void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, + bool error); + +/** + * Get the platform event log address and size. + * + * @dev TPM device + * @addr Address of the log + * @size Size of the log + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size); + +/** + * Get the first TPM2 device found. + * + * @dev TPM device + * + * Return: zero on success, negative errno otherwise + */ +int tcg2_platform_get_tpm2(struct udevice **dev); + +/** + * Platform-specific function for handling TPM startup errors + * + * @dev TPM device + * @rc The TPM response code + */ +void tcg2_platform_startup_error(struct udevice *dev, int rc); + +/** + * tcg2_algorithm_to_mask() - Get a TCG hash mask for algorithm + * + * @hash_alg: TCG defined algorithm + * Return: TCG hashing algorithm bitmaps (or 0 if algo not supported) + */ +u32 tcg2_algorithm_to_mask(enum tpm2_algorithms); #endif /* __TPM_TCG_V2_H */ diff --git a/lib/Makefile b/lib/Makefile index 2a76acf100d..e389ad014f8 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,6 +61,8 @@ ifeq ($(CONFIG_$(SPL_TPL_)TPM),y) obj-$(CONFIG_TPM) += tpm_api.o obj-$(CONFIG_TPM_V1) += tpm-v1.o obj-$(CONFIG_TPM_V2) += tpm-v2.o +obj-$(CONFIG_EFI_TCG2_PROTOCOL) += tpm_tcg2.o +obj-$(CONFIG_MEASURED_BOOT) += tpm_tcg2.o endif obj-$(CONFIG_$(SPL_TPL_)CRC8) += crc8.o diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index c3832bb7f76..62ab804b4b3 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -23,668 +23,6 @@ #include "tpm-utils.h" -int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) -{ - u32 supported = 0; - u32 pcr_banks = 0; - u32 active = 0; - int rc; - - rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks); - if (rc) - return rc; - - *active_pcr_banks = active; - - return 0; -} - -u32 tcg2_event_get_size(struct tpml_digest_values *digest_list) -{ - u32 len; - size_t i; - - len = offsetof(struct tcg_pcr_event2, digests); - len += offsetof(struct tpml_digest_values, digests); - for (i = 0; i < digest_list->count; ++i) { - u16 l = tpm2_algorithm_to_len(digest_list->digests[i].hash_alg); - - if (!l) - continue; - - len += l + offsetof(struct tpmt_ha, digest); - } - len += sizeof(u32); - - return len; -} - -int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, - struct tpml_digest_values *digest_list) -{ - u8 final[sizeof(union tpmu_ha)]; - sha256_context ctx_256; - sha512_context ctx_512; - sha1_context ctx; - u32 active; - size_t i; - u32 len; - int rc; - - rc = tcg2_get_active_pcr_banks(dev, &active); - if (rc) - return rc; - - digest_list->count = 0; - for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - switch (hash_algo_list[i].hash_alg) { - case TPM2_ALG_SHA1: - sha1_starts(&ctx); - sha1_update(&ctx, input, length); - sha1_finish(&ctx, final); - len = TPM2_SHA1_DIGEST_SIZE; - break; - case TPM2_ALG_SHA256: - sha256_starts(&ctx_256); - sha256_update(&ctx_256, input, length); - sha256_finish(&ctx_256, final); - len = TPM2_SHA256_DIGEST_SIZE; - break; - case TPM2_ALG_SHA384: - sha384_starts(&ctx_512); - sha384_update(&ctx_512, input, length); - sha384_finish(&ctx_512, final); - len = TPM2_SHA384_DIGEST_SIZE; - break; - case TPM2_ALG_SHA512: - sha512_starts(&ctx_512); - sha512_update(&ctx_512, input, length); - sha512_finish(&ctx_512, final); - len = TPM2_SHA512_DIGEST_SIZE; - break; - default: - printf("%s: unsupported algorithm %x\n", __func__, - hash_algo_list[i].hash_alg); - continue; - } - - digest_list->digests[digest_list->count].hash_alg = - hash_algo_list[i].hash_alg; - memcpy(&digest_list->digests[digest_list->count].digest, final, - len); - digest_list->count++; - } - - return 0; -} - -void tcg2_log_append(u32 pcr_index, u32 event_type, - struct tpml_digest_values *digest_list, u32 size, - const u8 *event, u8 *log) -{ - size_t len; - size_t pos; - u32 i; - - pos = offsetof(struct tcg_pcr_event2, pcr_index); - put_unaligned_le32(pcr_index, log); - pos = offsetof(struct tcg_pcr_event2, event_type); - put_unaligned_le32(event_type, log + pos); - pos = offsetof(struct tcg_pcr_event2, digests) + - offsetof(struct tpml_digest_values, count); - put_unaligned_le32(digest_list->count, log + pos); - - pos = offsetof(struct tcg_pcr_event2, digests) + - offsetof(struct tpml_digest_values, digests); - for (i = 0; i < digest_list->count; ++i) { - u16 hash_alg = digest_list->digests[i].hash_alg; - - len = tpm2_algorithm_to_len(hash_alg); - if (!len) - continue; - - pos += offsetof(struct tpmt_ha, hash_alg); - put_unaligned_le16(hash_alg, log + pos); - pos += offsetof(struct tpmt_ha, digest); - memcpy(log + pos, (u8 *)&digest_list->digests[i].digest, len); - pos += len; - } - - put_unaligned_le32(size, log + pos); - pos += sizeof(u32); - memcpy(log + pos, event, size); -} - -static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index, - u32 event_type, - struct tpml_digest_values *digest_list, - u32 size, const u8 *event) -{ - u32 event_size; - u8 *log; - - event_size = size + tcg2_event_get_size(digest_list); - if (elog->log_position + event_size > elog->log_size) { - printf("%s: log too large: %u + %u > %u\n", __func__, - elog->log_position, event_size, elog->log_size); - return -ENOBUFS; - } - - log = elog->log + elog->log_position; - elog->log_position += event_size; - - tcg2_log_append(pcr_index, event_type, digest_list, size, event, log); - - return 0; -} - -static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) -{ - struct tcg_efi_spec_id_event *ev; - struct tcg_pcr_event *log; - u32 event_size; - u32 count = 0; - u32 log_size; - u32 active; - size_t i; - u16 len; - int rc; - - rc = tcg2_get_active_pcr_banks(dev, &active); - if (rc) - return rc; - - event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes); - for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - switch (hash_algo_list[i].hash_alg) { - case TPM2_ALG_SHA1: - case TPM2_ALG_SHA256: - case TPM2_ALG_SHA384: - case TPM2_ALG_SHA512: - count++; - break; - default: - continue; - } - } - - event_size += 1 + - (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count); - log_size = offsetof(struct tcg_pcr_event, event) + event_size; - - if (log_size > elog->log_size) { - printf("%s: log too large: %u > %u\n", __func__, log_size, - elog->log_size); - return -ENOBUFS; - } - - log = (struct tcg_pcr_event *)elog->log; - put_unaligned_le32(0, &log->pcr_index); - put_unaligned_le32(EV_NO_ACTION, &log->event_type); - memset(&log->digest, 0, sizeof(log->digest)); - put_unaligned_le32(event_size, &log->event_size); - - ev = (struct tcg_efi_spec_id_event *)log->event; - strlcpy((char *)ev->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, - sizeof(ev->signature)); - put_unaligned_le32(0, &ev->platform_class); - ev->spec_version_minor = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2; - ev->spec_version_major = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2; - ev->spec_errata = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2; - ev->uintn_size = sizeof(size_t) / sizeof(u32); - put_unaligned_le32(count, &ev->number_of_algorithms); - - count = 0; - for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { - if (!(active & hash_algo_list[i].hash_mask)) - continue; - - len = hash_algo_list[i].hash_len; - if (!len) - continue; - - put_unaligned_le16(hash_algo_list[i].hash_alg, - &ev->digest_sizes[count].algorithm_id); - put_unaligned_le16(len, &ev->digest_sizes[count].digest_size); - count++; - } - - *((u8 *)ev + (event_size - 1)) = 0; - elog->log_position = log_size; - - return 0; -} - -static int tcg2_replay_eventlog(struct tcg2_event_log *elog, - struct udevice *dev, - struct tpml_digest_values *digest_list, - u32 log_position) -{ - const u32 offset = offsetof(struct tcg_pcr_event2, digests) + - offsetof(struct tpml_digest_values, digests); - u32 event_size; - u32 count; - u16 algo; - u32 pcr; - u32 pos; - u16 len; - u8 *log; - int rc; - u32 i; - - while (log_position + offset < elog->log_size) { - log = elog->log + log_position; - - pos = offsetof(struct tcg_pcr_event2, pcr_index); - pcr = get_unaligned_le32(log + pos); - pos = offsetof(struct tcg_pcr_event2, event_type); - if (!get_unaligned_le32(log + pos)) - return 0; - - pos = offsetof(struct tcg_pcr_event2, digests) + - offsetof(struct tpml_digest_values, count); - count = get_unaligned_le32(log + pos); - if (count > ARRAY_SIZE(hash_algo_list) || - (digest_list->count && digest_list->count != count)) - return 0; - - pos = offsetof(struct tcg_pcr_event2, digests) + - offsetof(struct tpml_digest_values, digests); - for (i = 0; i < count; ++i) { - pos += offsetof(struct tpmt_ha, hash_alg); - if (log_position + pos + sizeof(u16) >= elog->log_size) - return 0; - - algo = get_unaligned_le16(log + pos); - pos += offsetof(struct tpmt_ha, digest); - switch (algo) { - case TPM2_ALG_SHA1: - case TPM2_ALG_SHA256: - case TPM2_ALG_SHA384: - case TPM2_ALG_SHA512: - len = tpm2_algorithm_to_len(algo); - break; - default: - return 0; - } - - if (digest_list->count) { - if (algo != digest_list->digests[i].hash_alg || - log_position + pos + len >= elog->log_size) - return 0; - - memcpy(digest_list->digests[i].digest.sha512, - log + pos, len); - } - - pos += len; - } - - if (log_position + pos + sizeof(u32) >= elog->log_size) - return 0; - - event_size = get_unaligned_le32(log + pos); - pos += event_size + sizeof(u32); - if (log_position + pos > elog->log_size) - return 0; - - if (digest_list->count) { - rc = tcg2_pcr_extend(dev, pcr, digest_list); - if (rc) - return rc; - } - - log_position += pos; - } - - elog->log_position = log_position; - elog->found = true; - return 0; -} - -static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) -{ - struct tpml_digest_values digest_list; - struct tcg_efi_spec_id_event *event; - struct tcg_pcr_event *log; - u32 log_active; - u32 calc_size; - u32 active; - u32 count; - u32 evsz; - u32 mask; - u16 algo; - u16 len; - int rc; - u32 i; - u16 j; - - if (elog->log_size <= offsetof(struct tcg_pcr_event, event)) - return 0; - - log = (struct tcg_pcr_event *)elog->log; - if (get_unaligned_le32(&log->pcr_index) != 0 || - get_unaligned_le32(&log->event_type) != EV_NO_ACTION) - return 0; - - for (i = 0; i < sizeof(log->digest); i++) { - if (log->digest[i]) - return 0; - } - - evsz = get_unaligned_le32(&log->event_size); - if (evsz < offsetof(struct tcg_efi_spec_id_event, digest_sizes) || - evsz + offsetof(struct tcg_pcr_event, event) > elog->log_size) - return 0; - - event = (struct tcg_efi_spec_id_event *)log->event; - if (memcmp(event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, - sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) - return 0; - - if (event->spec_version_minor != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 || - event->spec_version_major != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2) - return 0; - - count = get_unaligned_le32(&event->number_of_algorithms); - if (count > ARRAY_SIZE(hash_algo_list)) - return 0; - - calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) + - (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count) + - 1; - if (evsz != calc_size) - return 0; - - rc = tcg2_get_active_pcr_banks(dev, &active); - if (rc) - return rc; - - digest_list.count = 0; - log_active = 0; - - for (i = 0; i < count; ++i) { - algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id); - mask = tpm2_algorithm_to_mask(algo); - - if (!(active & mask)) - return 0; - - switch (algo) { - case TPM2_ALG_SHA1: - case TPM2_ALG_SHA256: - case TPM2_ALG_SHA384: - case TPM2_ALG_SHA512: - len = get_unaligned_le16(&event->digest_sizes[i].digest_size); - if (tpm2_algorithm_to_len(algo) != len) - return 0; - digest_list.digests[digest_list.count++].hash_alg = algo; - break; - default: - return 0; - } - - log_active |= mask; - } - - /* Ensure the previous firmware extended all the PCRs. */ - if (log_active != active) - return 0; - - /* Read PCR0 to check if previous firmware extended the PCRs or not. */ - rc = tcg2_pcr_read(dev, 0, &digest_list); - if (rc) - return rc; - - for (i = 0; i < digest_list.count; ++i) { - len = tpm2_algorithm_to_len(digest_list.digests[i].hash_alg); - for (j = 0; j < len; ++j) { - if (digest_list.digests[i].digest.sha512[j]) - break; - } - - /* PCR is non-zero; it has been extended, so skip extending. */ - if (j != len) { - digest_list.count = 0; - break; - } - } - - return tcg2_replay_eventlog(elog, dev, &digest_list, - offsetof(struct tcg_pcr_event, event) + - evsz); -} - -int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list) -{ - u32 rc; - u32 i; - - for (i = 0; i < digest_list->count; i++) { - u32 alg = digest_list->digests[i].hash_alg; - - rc = tpm2_pcr_extend(dev, pcr_index, alg, - (u8 *)&digest_list->digests[i].digest, - tpm2_algorithm_to_len(alg)); - if (rc) { - printf("%s: error pcr:%u alg:%08x\n", __func__, - pcr_index, alg); - return rc; - } - } - - return 0; -} - -int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, - struct tpml_digest_values *digest_list) -{ - struct tpm_chip_priv *priv; - u32 rc; - u32 i; - - priv = dev_get_uclass_priv(dev); - if (!priv) - return -ENODEV; - - for (i = 0; i < digest_list->count; i++) { - u32 alg = digest_list->digests[i].hash_alg; - u8 *digest = (u8 *)&digest_list->digests[i].digest; - - rc = tpm2_pcr_read(dev, pcr_index, priv->pcr_select_min, alg, - digest, tpm2_algorithm_to_len(alg), NULL); - if (rc) { - printf("%s: error pcr:%u alg:%08x\n", __func__, - pcr_index, alg); - return rc; - } - } - - return 0; -} - -int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, - u32 pcr_index, u32 size, const u8 *data, u32 event_type, - u32 event_size, const u8 *event) -{ - struct tpml_digest_values digest_list; - int rc; - - if (data) - rc = tcg2_create_digest(dev, data, size, &digest_list); - else - rc = tcg2_create_digest(dev, event, event_size, &digest_list); - if (rc) - return rc; - - rc = tcg2_pcr_extend(dev, pcr_index, &digest_list); - if (rc) - return rc; - - return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list, - event_size, event); -} - -int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, - bool ignore_existing_log) -{ - struct tcg2_event_log log; - int rc; - - elog->log_position = 0; - elog->found = false; - - rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); - if (!rc) { - log.log_position = 0; - log.found = false; - - if (!ignore_existing_log) { - rc = tcg2_log_parse(dev, &log); - if (rc) - return rc; - } - - if (elog->log_size) { - if (log.found) { - if (elog->log_size < log.log_position) - return -ENOBUFS; - - /* - * Copy the discovered log into the user buffer - * if there's enough space. - */ - memcpy(elog->log, log.log, log.log_position); - } - - unmap_physmem(log.log, MAP_NOCACHE); - } else { - elog->log = log.log; - elog->log_size = log.log_size; - } - - elog->log_position = log.log_position; - elog->found = log.found; - } - - /* - * Initialize the log buffer if no log was discovered and the buffer is - * valid. User's can pass in their own buffer as a fallback if no - * memory region is found. - */ - if (!elog->found && elog->log_size) - rc = tcg2_log_init(dev, elog); - - return rc; -} - -int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, - bool ignore_existing_log) -{ - int rc; - - rc = tcg2_platform_get_tpm2(dev); - if (rc) - return rc; - - rc = tpm_auto_start(*dev); - if (rc) - return rc; - - rc = tcg2_log_prepare_buffer(*dev, elog, ignore_existing_log); - if (rc) { - tcg2_measurement_term(*dev, elog, true); - return rc; - } - - rc = tcg2_measure_event(*dev, elog, 0, EV_S_CRTM_VERSION, - strlen(version_string) + 1, - (u8 *)version_string); - if (rc) { - tcg2_measurement_term(*dev, elog, true); - return rc; - } - - return 0; -} - -void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, - bool error) -{ - u32 event = error ? 0x1 : 0xffffffff; - int i; - - for (i = 0; i < 8; ++i) - tcg2_measure_event(dev, elog, i, EV_SEPARATOR, sizeof(event), - (const u8 *)&event); - - if (elog->log) - unmap_physmem(elog->log, MAP_NOCACHE); -} - -__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size) -{ - const __be32 *addr_prop; - const __be32 *size_prop; - int asize; - int ssize; - - *addr = NULL; - *size = 0; - - addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize); - if (!addr_prop) - addr_prop = dev_read_prop(dev, "linux,sml-base", &asize); - - size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize); - if (!size_prop) - size_prop = dev_read_prop(dev, "linux,sml-size", &ssize); - - if (addr_prop && size_prop) { - u64 a = of_read_number(addr_prop, asize / sizeof(__be32)); - u64 s = of_read_number(size_prop, ssize / sizeof(__be32)); - - *addr = map_physmem(a, s, MAP_NOCACHE); - *size = (u32)s; - } else { - struct ofnode_phandle_args args; - phys_addr_t a; - fdt_size_t s; - - if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0, - 0, &args)) - return -ENODEV; - - a = ofnode_get_addr_size(args.node, "reg", &s); - if (a == FDT_ADDR_T_NONE) - return -ENOMEM; - - *addr = map_physmem(a, s, MAP_NOCACHE); - *size = (u32)s; - } - - return 0; -} - -__weak int tcg2_platform_get_tpm2(struct udevice **dev) -{ - for_each_tpm_device(*dev) { - if (tpm_get_version(*dev) == TPM_V2) - return 0; - } - - return -ENODEV; -} - -__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {} - u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) { const u8 command_v2[12] = { @@ -1141,7 +479,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, } for (i = 0; i < pcrs.count; i++) { - u32 hash_mask = tpm2_algorithm_to_mask(pcrs.selection[i].hash); + u32 hash_mask = tcg2_algorithm_to_mask(pcrs.selection[i].hash); if (hash_mask) { *supported_pcr |= hash_mask; @@ -1567,14 +905,3 @@ const char *tpm2_algorithm_name(enum tpm2_algorithms algo) return ""; } -u32 tpm2_algorithm_to_mask(enum tpm2_algorithms algo) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { - if (hash_algo_list[i].hash_alg == algo) - return hash_algo_list[i].hash_mask; - } - - return 0; -} diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c new file mode 100644 index 00000000000..91b9612fd3f --- /dev/null +++ b/lib/tpm_tcg2.c @@ -0,0 +1,695 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tpm-utils.h" + +int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) +{ + u32 supported = 0; + u32 pcr_banks = 0; + u32 active = 0; + int rc; + + rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks); + if (rc) + return rc; + + *active_pcr_banks = active; + + return 0; +} + +u32 tcg2_event_get_size(struct tpml_digest_values *digest_list) +{ + u32 len; + size_t i; + + len = offsetof(struct tcg_pcr_event2, digests); + len += offsetof(struct tpml_digest_values, digests); + for (i = 0; i < digest_list->count; ++i) { + u16 l = tpm2_algorithm_to_len(digest_list->digests[i].hash_alg); + + if (!l) + continue; + + len += l + offsetof(struct tpmt_ha, digest); + } + len += sizeof(u32); + + return len; +} + +int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length, + struct tpml_digest_values *digest_list) +{ + u8 final[sizeof(union tpmu_ha)]; + sha256_context ctx_256; + sha512_context ctx_512; + sha1_context ctx; + u32 active; + size_t i; + u32 len; + int rc; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + digest_list->count = 0; + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + switch (hash_algo_list[i].hash_alg) { + case TPM2_ALG_SHA1: + sha1_starts(&ctx); + sha1_update(&ctx, input, length); + sha1_finish(&ctx, final); + len = TPM2_SHA1_DIGEST_SIZE; + break; + case TPM2_ALG_SHA256: + sha256_starts(&ctx_256); + sha256_update(&ctx_256, input, length); + sha256_finish(&ctx_256, final); + len = TPM2_SHA256_DIGEST_SIZE; + break; + case TPM2_ALG_SHA384: + sha384_starts(&ctx_512); + sha384_update(&ctx_512, input, length); + sha384_finish(&ctx_512, final); + len = TPM2_SHA384_DIGEST_SIZE; + break; + case TPM2_ALG_SHA512: + sha512_starts(&ctx_512); + sha512_update(&ctx_512, input, length); + sha512_finish(&ctx_512, final); + len = TPM2_SHA512_DIGEST_SIZE; + break; + default: + printf("%s: unsupported algorithm %x\n", __func__, + hash_algo_list[i].hash_alg); + continue; + } + + digest_list->digests[digest_list->count].hash_alg = + hash_algo_list[i].hash_alg; + memcpy(&digest_list->digests[digest_list->count].digest, final, + len); + digest_list->count++; + } + + return 0; +} + +void tcg2_log_append(u32 pcr_index, u32 event_type, + struct tpml_digest_values *digest_list, u32 size, + const u8 *event, u8 *log) +{ + size_t len; + size_t pos; + u32 i; + + pos = offsetof(struct tcg_pcr_event2, pcr_index); + put_unaligned_le32(pcr_index, log); + pos = offsetof(struct tcg_pcr_event2, event_type); + put_unaligned_le32(event_type, log + pos); + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, count); + put_unaligned_le32(digest_list->count, log + pos); + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + for (i = 0; i < digest_list->count; ++i) { + u16 hash_alg = digest_list->digests[i].hash_alg; + + len = tpm2_algorithm_to_len(hash_alg); + if (!len) + continue; + + pos += offsetof(struct tpmt_ha, hash_alg); + put_unaligned_le16(hash_alg, log + pos); + pos += offsetof(struct tpmt_ha, digest); + memcpy(log + pos, (u8 *)&digest_list->digests[i].digest, len); + pos += len; + } + + put_unaligned_le32(size, log + pos); + pos += sizeof(u32); + memcpy(log + pos, event, size); +} + +static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index, + u32 event_type, + struct tpml_digest_values *digest_list, + u32 size, const u8 *event) +{ + u32 event_size; + u8 *log; + + event_size = size + tcg2_event_get_size(digest_list); + if (elog->log_position + event_size > elog->log_size) { + printf("%s: log too large: %u + %u > %u\n", __func__, + elog->log_position, event_size, elog->log_size); + return -ENOBUFS; + } + + log = elog->log + elog->log_position; + elog->log_position += event_size; + + tcg2_log_append(pcr_index, event_type, digest_list, size, event, log); + + return 0; +} + +static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog) +{ + struct tcg_efi_spec_id_event *ev; + struct tcg_pcr_event *log; + u32 event_size; + u32 count = 0; + u32 log_size; + u32 active; + size_t i; + u16 len; + int rc; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes); + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + switch (hash_algo_list[i].hash_alg) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + count++; + break; + default: + continue; + } + } + + event_size += 1 + + (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count); + log_size = offsetof(struct tcg_pcr_event, event) + event_size; + + if (log_size > elog->log_size) { + printf("%s: log too large: %u > %u\n", __func__, log_size, + elog->log_size); + return -ENOBUFS; + } + + log = (struct tcg_pcr_event *)elog->log; + put_unaligned_le32(0, &log->pcr_index); + put_unaligned_le32(EV_NO_ACTION, &log->event_type); + memset(&log->digest, 0, sizeof(log->digest)); + put_unaligned_le32(event_size, &log->event_size); + + ev = (struct tcg_efi_spec_id_event *)log->event; + strlcpy((char *)ev->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, + sizeof(ev->signature)); + put_unaligned_le32(0, &ev->platform_class); + ev->spec_version_minor = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2; + ev->spec_version_major = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2; + ev->spec_errata = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2; + ev->uintn_size = sizeof(size_t) / sizeof(u32); + put_unaligned_le32(count, &ev->number_of_algorithms); + + count = 0; + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (!(active & hash_algo_list[i].hash_mask)) + continue; + + len = hash_algo_list[i].hash_len; + if (!len) + continue; + + put_unaligned_le16(hash_algo_list[i].hash_alg, + &ev->digest_sizes[count].algorithm_id); + put_unaligned_le16(len, &ev->digest_sizes[count].digest_size); + count++; + } + + *((u8 *)ev + (event_size - 1)) = 0; + elog->log_position = log_size; + + return 0; +} + +static int tcg2_replay_eventlog(struct tcg2_event_log *elog, + struct udevice *dev, + struct tpml_digest_values *digest_list, + u32 log_position) +{ + const u32 offset = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + u32 event_size; + u32 count; + u16 algo; + u32 pcr; + u32 pos; + u16 len; + u8 *log; + int rc; + u32 i; + + while (log_position + offset < elog->log_size) { + log = elog->log + log_position; + + pos = offsetof(struct tcg_pcr_event2, pcr_index); + pcr = get_unaligned_le32(log + pos); + pos = offsetof(struct tcg_pcr_event2, event_type); + if (!get_unaligned_le32(log + pos)) + return 0; + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, count); + count = get_unaligned_le32(log + pos); + if (count > ARRAY_SIZE(hash_algo_list) || + (digest_list->count && digest_list->count != count)) + return 0; + + pos = offsetof(struct tcg_pcr_event2, digests) + + offsetof(struct tpml_digest_values, digests); + for (i = 0; i < count; ++i) { + pos += offsetof(struct tpmt_ha, hash_alg); + if (log_position + pos + sizeof(u16) >= elog->log_size) + return 0; + + algo = get_unaligned_le16(log + pos); + pos += offsetof(struct tpmt_ha, digest); + switch (algo) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + len = tpm2_algorithm_to_len(algo); + break; + default: + return 0; + } + + if (digest_list->count) { + if (algo != digest_list->digests[i].hash_alg || + log_position + pos + len >= elog->log_size) + return 0; + + memcpy(digest_list->digests[i].digest.sha512, + log + pos, len); + } + + pos += len; + } + + if (log_position + pos + sizeof(u32) >= elog->log_size) + return 0; + + event_size = get_unaligned_le32(log + pos); + pos += event_size + sizeof(u32); + if (log_position + pos > elog->log_size) + return 0; + + if (digest_list->count) { + rc = tcg2_pcr_extend(dev, pcr, digest_list); + if (rc) + return rc; + } + + log_position += pos; + } + + elog->log_position = log_position; + elog->found = true; + return 0; +} + +static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) +{ + struct tpml_digest_values digest_list; + struct tcg_efi_spec_id_event *event; + struct tcg_pcr_event *log; + u32 log_active; + u32 calc_size; + u32 active; + u32 count; + u32 evsz; + u32 mask; + u16 algo; + u16 len; + int rc; + u32 i; + u16 j; + + if (elog->log_size <= offsetof(struct tcg_pcr_event, event)) + return 0; + + log = (struct tcg_pcr_event *)elog->log; + if (get_unaligned_le32(&log->pcr_index) != 0 || + get_unaligned_le32(&log->event_type) != EV_NO_ACTION) + return 0; + + for (i = 0; i < sizeof(log->digest); i++) { + if (log->digest[i]) + return 0; + } + + evsz = get_unaligned_le32(&log->event_size); + if (evsz < offsetof(struct tcg_efi_spec_id_event, digest_sizes) || + evsz + offsetof(struct tcg_pcr_event, event) > elog->log_size) + return 0; + + event = (struct tcg_efi_spec_id_event *)log->event; + if (memcmp(event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03, + sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03))) + return 0; + + if (event->spec_version_minor != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 || + event->spec_version_major != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2) + return 0; + + count = get_unaligned_le32(&event->number_of_algorithms); + if (count > ARRAY_SIZE(hash_algo_list)) + return 0; + + calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) + + (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count) + + 1; + if (evsz != calc_size) + return 0; + + rc = tcg2_get_active_pcr_banks(dev, &active); + if (rc) + return rc; + + digest_list.count = 0; + log_active = 0; + + for (i = 0; i < count; ++i) { + algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id); + mask = tcg2_algorithm_to_mask(algo); + + if (!(active & mask)) + return 0; + + switch (algo) { + case TPM2_ALG_SHA1: + case TPM2_ALG_SHA256: + case TPM2_ALG_SHA384: + case TPM2_ALG_SHA512: + len = get_unaligned_le16(&event->digest_sizes[i].digest_size); + if (tpm2_algorithm_to_len(algo) != len) + return 0; + digest_list.digests[digest_list.count++].hash_alg = algo; + break; + default: + return 0; + } + + log_active |= mask; + } + + /* Ensure the previous firmware extended all the PCRs. */ + if (log_active != active) + return 0; + + /* Read PCR0 to check if previous firmware extended the PCRs or not. */ + rc = tcg2_pcr_read(dev, 0, &digest_list); + if (rc) + return rc; + + for (i = 0; i < digest_list.count; ++i) { + len = tpm2_algorithm_to_len(digest_list.digests[i].hash_alg); + for (j = 0; j < len; ++j) { + if (digest_list.digests[i].digest.sha512[j]) + break; + } + + /* PCR is non-zero; it has been extended, so skip extending. */ + if (j != len) { + digest_list.count = 0; + break; + } + } + + return tcg2_replay_eventlog(elog, dev, &digest_list, + offsetof(struct tcg_pcr_event, event) + + evsz); +} + +int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list) +{ + u32 rc; + u32 i; + + for (i = 0; i < digest_list->count; i++) { + u32 alg = digest_list->digests[i].hash_alg; + + rc = tpm2_pcr_extend(dev, pcr_index, alg, + (u8 *)&digest_list->digests[i].digest, + tpm2_algorithm_to_len(alg)); + if (rc) { + printf("%s: error pcr:%u alg:%08x\n", __func__, + pcr_index, alg); + return rc; + } + } + + return 0; +} + +int tcg2_pcr_read(struct udevice *dev, u32 pcr_index, + struct tpml_digest_values *digest_list) +{ + struct tpm_chip_priv *priv; + u32 rc; + u32 i; + + priv = dev_get_uclass_priv(dev); + if (!priv) + return -ENODEV; + + for (i = 0; i < digest_list->count; i++) { + u32 alg = digest_list->digests[i].hash_alg; + u8 *digest = (u8 *)&digest_list->digests[i].digest; + + rc = tpm2_pcr_read(dev, pcr_index, priv->pcr_select_min, alg, + digest, tpm2_algorithm_to_len(alg), NULL); + if (rc) { + printf("%s: error pcr:%u alg:%08x\n", __func__, + pcr_index, alg); + return rc; + } + } + + return 0; +} + +int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog, + u32 pcr_index, u32 size, const u8 *data, u32 event_type, + u32 event_size, const u8 *event) +{ + struct tpml_digest_values digest_list; + int rc; + + if (data) + rc = tcg2_create_digest(dev, data, size, &digest_list); + else + rc = tcg2_create_digest(dev, event, event_size, &digest_list); + if (rc) + return rc; + + rc = tcg2_pcr_extend(dev, pcr_index, &digest_list); + if (rc) + return rc; + + return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list, + event_size, event); +} + +int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, + bool ignore_existing_log) +{ + struct tcg2_event_log log; + int rc; + + elog->log_position = 0; + elog->found = false; + + rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); + if (!rc) { + log.log_position = 0; + log.found = false; + + if (!ignore_existing_log) { + rc = tcg2_log_parse(dev, &log); + if (rc) + return rc; + } + + if (elog->log_size) { + if (log.found) { + if (elog->log_size < log.log_position) + return -ENOBUFS; + + /* + * Copy the discovered log into the user buffer + * if there's enough space. + */ + memcpy(elog->log, log.log, log.log_position); + } + + unmap_physmem(log.log, MAP_NOCACHE); + } else { + elog->log = log.log; + elog->log_size = log.log_size; + } + + elog->log_position = log.log_position; + elog->found = log.found; + } + + /* + * Initialize the log buffer if no log was discovered and the buffer is + * valid. User's can pass in their own buffer as a fallback if no + * memory region is found. + */ + if (!elog->found && elog->log_size) + rc = tcg2_log_init(dev, elog); + + return rc; +} + +int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog, + bool ignore_existing_log) +{ + int rc; + + rc = tcg2_platform_get_tpm2(dev); + if (rc) + return rc; + + rc = tpm_auto_start(*dev); + if (rc) + return rc; + + rc = tcg2_log_prepare_buffer(*dev, elog, ignore_existing_log); + if (rc) { + tcg2_measurement_term(*dev, elog, true); + return rc; + } + + rc = tcg2_measure_event(*dev, elog, 0, EV_S_CRTM_VERSION, + strlen(version_string) + 1, + (u8 *)version_string); + if (rc) { + tcg2_measurement_term(*dev, elog, true); + return rc; + } + + return 0; +} + +void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog, + bool error) +{ + u32 event = error ? 0x1 : 0xffffffff; + int i; + + for (i = 0; i < 8; ++i) + tcg2_measure_event(dev, elog, i, EV_SEPARATOR, sizeof(event), + (const u8 *)&event); + + if (elog->log) + unmap_physmem(elog->log, MAP_NOCACHE); +} + +__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size) +{ + const __be32 *addr_prop; + const __be32 *size_prop; + int asize; + int ssize; + + *addr = NULL; + *size = 0; + + addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize); + if (!addr_prop) + addr_prop = dev_read_prop(dev, "linux,sml-base", &asize); + + size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize); + if (!size_prop) + size_prop = dev_read_prop(dev, "linux,sml-size", &ssize); + + if (addr_prop && size_prop) { + u64 a = of_read_number(addr_prop, asize / sizeof(__be32)); + u64 s = of_read_number(size_prop, ssize / sizeof(__be32)); + + *addr = map_physmem(a, s, MAP_NOCACHE); + *size = (u32)s; + } else { + struct ofnode_phandle_args args; + phys_addr_t a; + fdt_size_t s; + + if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0, + 0, &args)) + return -ENODEV; + + a = ofnode_get_addr_size(args.node, "reg", &s); + if (a == FDT_ADDR_T_NONE) + return -ENOMEM; + + *addr = map_physmem(a, s, MAP_NOCACHE); + *size = (u32)s; + } + + return 0; +} + +__weak int tcg2_platform_get_tpm2(struct udevice **dev) +{ + for_each_tpm_device(*dev) { + if (tpm_get_version(*dev) == TPM_V2) + return 0; + } + + return -ENODEV; +} + +u32 tcg2_algorithm_to_mask(enum tpm2_algorithms algo) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + if (hash_algo_list[i].hash_alg == algo) + return hash_algo_list[i].hash_mask; + } + + return 0; +} + +__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {} From fed9c11c3b58de804059915b33f9e9263ce6ce75 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:16 +0300 Subject: [PATCH 09/13] efi_loader: remove unneeded header files efi_tcg2.h already includes tpm-v2.h. Remove it Reviewed-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_tcg2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index 1400e675704..ba0ea7ea73c 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include From cba3fa90240df783cb040f25833dd420f7f39f16 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:17 +0300 Subject: [PATCH 10/13] tpm: Untangle tpm2_get_pcr_info() This function was used on measured boot to retrieve the number of active PCR banks and was designed to work with the TCG protocols. Since we now have the need to retrieve the active PCRs outside the measured boot context -- e.g use the in the command line, decouple the function. Create one that will only adheres to TCG TSS2.0 [0] specification called tpm2_get_pcr_info() which can be used by the TPM2.0 APIs and a new one that is called from the measured boot context called tcg2_get_pcr_info() [0] https://trustedcomputinggroup.org/wp-content/uploads/TSS_Overview_Common_Structures_Version-0.9_Revision-03_Review_030918.pdf Signed-off-by: Ilias Apalodimas --- include/tpm-v2.h | 16 ++++++--- include/tpm_tcg2.h | 13 +++++++ lib/efi_loader/efi_tcg2.c | 2 +- lib/tpm-v2.c | 73 +++++++++++++-------------------------- lib/tpm_tcg2.c | 38 +++++++++++++++++++- 5 files changed, 86 insertions(+), 56 deletions(-) diff --git a/include/tpm-v2.h b/include/tpm-v2.h index fc7c58204e5..aedf2c0f4f5 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -522,14 +522,11 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, * tpm2_get_pcr_info() - get the supported, active PCRs and number of banks * * @dev: TPM device - * @supported_pcr: bitmask with the algorithms supported - * @active_pcr: bitmask with the active algorithms - * @pcr_banks: number of PCR banks + * @pcrs: struct tpml_pcr_selection of available PCRs * * @return 0 on success, code of operation or negative errno on failure */ -int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, - u32 *pcr_banks); +int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs); /** * Issue a TPM2_DictionaryAttackLockReset command. @@ -715,4 +712,13 @@ enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); */ const char *tpm2_algorithm_name(enum tpm2_algorithms); +/** + * tpm2_is_active_pcr() - check the pcr_select. If at least one of the PCRs + * supports the algorithm add it on the active ones + * + * @selection: PCR selection structure + * Return: True if the algorithm is active + */ +bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection); + #endif /* __TPM_V2_H */ diff --git a/include/tpm_tcg2.h b/include/tpm_tcg2.h index 4e4ea1e8067..6519004cc41 100644 --- a/include/tpm_tcg2.h +++ b/include/tpm_tcg2.h @@ -93,6 +93,19 @@ struct tcg_pcr_event { u8 event[]; } __packed; +/** + * tcg2_get_pcr_info() - get the supported, active PCRs and number of banks + * + * @dev: TPM device + * @supported_pcr: bitmask with the algorithms supported + * @active_pcr: bitmask with the active algorithms + * @pcr_banks: number of PCR banks + * + * @return 0 on success, code of operation or negative errno on failure + */ +int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks); + /** * Crypto Agile Log Entry Format * diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c index ba0ea7ea73c..45f451ef6b6 100644 --- a/lib/efi_loader/efi_tcg2.c +++ b/lib/efi_loader/efi_tcg2.c @@ -276,7 +276,7 @@ efi_tcg2_get_capability(struct efi_tcg2_protocol *this, /* Supported and active PCRs */ capability->hash_algorithm_bitmap = 0; capability->active_pcr_banks = 0; - ret = tpm2_get_pcr_info(dev, &capability->hash_algorithm_bitmap, + ret = tcg2_get_pcr_info(dev, &capability->hash_algorithm_bitmap, &capability->active_pcr_banks, &capability->number_of_pcr_banks); if (ret) { diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 62ab804b4b3..36aace03cf4 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -395,48 +395,26 @@ static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) return 0; } -static bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection) -{ - int i; - - /* - * check the pcr_select. If at least one of the PCRs supports the - * algorithm add it on the active ones - */ - for (i = 0; i < selection->size_of_select; i++) { - if (selection->pcr_select[i]) - return true; - } - - return false; -} - -int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, - u32 *pcr_banks) +int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs) { u8 response[(sizeof(struct tpms_capability_data) - offsetof(struct tpms_capability_data, data))]; - struct tpml_pcr_selection pcrs; u32 num_pcr; size_t i; u32 ret; - *supported_pcr = 0; - *active_pcr = 0; - *pcr_banks = 0; - memset(response, 0, sizeof(response)); ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1); if (ret) return ret; - pcrs.count = get_unaligned_be32(response); + pcrs->count = get_unaligned_be32(response); /* * We only support 5 algorithms for now so check against that * instead of TPM2_NUM_PCR_BANKS */ - if (pcrs.count > ARRAY_SIZE(hash_algo_list) || - pcrs.count < 1) { - printf("%s: too many pcrs: %u\n", __func__, pcrs.count); + if (pcrs->count > ARRAY_SIZE(hash_algo_list) || + pcrs->count < 1) { + printf("%s: too many pcrs: %u\n", __func__, pcrs->count); return -EMSGSIZE; } @@ -444,7 +422,7 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, if (ret) return ret; - for (i = 0; i < pcrs.count; i++) { + for (i = 0; i < pcrs->count; i++) { /* * Definition of TPMS_PCR_SELECTION Structure * hash: u16 @@ -464,35 +442,20 @@ int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, hash_offset + offsetof(struct tpms_pcr_selection, pcr_select); - pcrs.selection[i].hash = + pcrs->selection[i].hash = get_unaligned_be16(response + hash_offset); - pcrs.selection[i].size_of_select = + pcrs->selection[i].size_of_select = __get_unaligned_be(response + size_select_offset); - if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) { + if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) { printf("%s: pcrs selection too large: %u\n", __func__, - pcrs.selection[i].size_of_select); + pcrs->selection[i].size_of_select); return -ENOBUFS; } /* copy the array of pcr_select */ - memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset, - pcrs.selection[i].size_of_select); + memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset, + pcrs->selection[i].size_of_select); } - for (i = 0; i < pcrs.count; i++) { - u32 hash_mask = tcg2_algorithm_to_mask(pcrs.selection[i].hash); - - if (hash_mask) { - *supported_pcr |= hash_mask; - if (tpm2_is_active_pcr(&pcrs.selection[i])) - *active_pcr |= hash_mask; - } else { - printf("%s: unknown algorithm %x\n", __func__, - pcrs.selection[i].hash); - } - } - - *pcr_banks = pcrs.count; - return 0; } @@ -880,6 +843,18 @@ u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, return 0; } +bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection) +{ + int i; + + for (i = 0; i < selection->size_of_select; i++) { + if (selection->pcr_select[i]) + return true; + } + + return false; +} + enum tpm2_algorithms tpm2_name_to_algorithm(const char *name) { size_t i; diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c index 91b9612fd3f..7f868cc8837 100644 --- a/lib/tpm_tcg2.c +++ b/lib/tpm_tcg2.c @@ -20,6 +20,42 @@ #include #include "tpm-utils.h" +int tcg2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr, + u32 *pcr_banks) +{ + u8 response[(sizeof(struct tpms_capability_data) - + offsetof(struct tpms_capability_data, data))]; + struct tpml_pcr_selection pcrs; + size_t i; + u32 ret; + + *supported_pcr = 0; + *active_pcr = 0; + *pcr_banks = 0; + memset(response, 0, sizeof(response)); + + ret = tpm2_get_pcr_info(dev, &pcrs); + if (ret) + return ret; + + for (i = 0; i < pcrs.count; i++) { + u32 hash_mask = tcg2_algorithm_to_mask(pcrs.selection[i].hash); + + if (hash_mask) { + *supported_pcr |= hash_mask; + if (tpm2_is_active_pcr(&pcrs.selection[i])) + *active_pcr |= hash_mask; + } else { + printf("%s: unknown algorithm %x\n", __func__, + pcrs.selection[i].hash); + } + } + + *pcr_banks = pcrs.count; + + return 0; +} + int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) { u32 supported = 0; @@ -27,7 +63,7 @@ int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks) u32 active = 0; int rc; - rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks); + rc = tcg2_get_pcr_info(dev, &supported, &active, &pcr_banks); if (rc) return rc; From e7505b3b8bcd1bca2d30291367713f442b453c41 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sun, 23 Jun 2024 14:48:18 +0300 Subject: [PATCH 11/13] tpm: allow the user to select the compiled algorithms Simon reports that after enabling all algorithms on the TPM some boards fail since they don't have enough storage to accommodate the ~5KB growth. The choice of hash algorithms is determined by the platform and the TPM configuration. Failing to cap a PCR in a bank which the platform left active is a security vulnerability. It might allow unsealing of secrets if an attacker can replay a good set of measurements into an unused bank. If MEASURED_BOOT or EFI_TCG2_PROTOCOL is enabled our Kconfig will enable all supported hashing algorithms. We still want to allow users to add a TPM and not enable measured boot via EFI or bootm though and at the same time, control the compiled algorithms for size reasons. So let's add a function tpm2_allow_extend() which checks the TPM active PCRs banks against the one U-Boot was compiled with. We only allow extending PCRs if the algorithms selected during build match the TPM configuration. It's worth noting that this is only added for TPM2.0, since TPM1.2 is lacking a lot of code at the moment to read the available PCR banks. We unconditionally enable SHA1 when a TPM is selected, which is the only hashing algorithm v1.2 supports. Signed-off-by: Ilias Apalodimas Reviewed-by: Simon Glass Tested-by: Simon Glass # chromebook-link --- boot/Kconfig | 4 ++++ include/tpm-v2.h | 59 +++++++++++++++++++++++++++++++++++------------- lib/Kconfig | 6 ++--- lib/tpm-v2.c | 40 +++++++++++++++++++++++++++++--- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index a212f262274..11175fb7bb2 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -734,6 +734,10 @@ config LEGACY_IMAGE_FORMAT config MEASURED_BOOT bool "Measure boot images and configuration when booting without EFI" depends on HASH && TPM_V2 + select SHA1 + select SHA256 + select SHA384 + select SHA512 help This option enables measurement of the boot process when booting without UEFI . Measurement involves creating cryptographic hashes diff --git a/include/tpm-v2.h b/include/tpm-v2.h index aedf2c0f4f5..4fd19c52fd7 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -278,48 +278,40 @@ struct digest_info { #define TCG2_BOOT_HASH_ALG_SM3_256 0x00000010 static const struct digest_info hash_algo_list[] = { +#if IS_ENABLED(CONFIG_SHA1) { "sha1", TPM2_ALG_SHA1, TCG2_BOOT_HASH_ALG_SHA1, TPM2_SHA1_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA256) { "sha256", TPM2_ALG_SHA256, TCG2_BOOT_HASH_ALG_SHA256, TPM2_SHA256_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA384) { "sha384", TPM2_ALG_SHA384, TCG2_BOOT_HASH_ALG_SHA384, TPM2_SHA384_DIGEST_SIZE, }, +#endif +#if IS_ENABLED(CONFIG_SHA512) { "sha512", TPM2_ALG_SHA512, TCG2_BOOT_HASH_ALG_SHA512, TPM2_SHA512_DIGEST_SIZE, }, +#endif }; -static inline u16 tpm2_algorithm_to_len(enum tpm2_algorithms a) -{ - switch (a) { - case TPM2_ALG_SHA1: - return TPM2_SHA1_DIGEST_SIZE; - case TPM2_ALG_SHA256: - return TPM2_SHA256_DIGEST_SIZE; - case TPM2_ALG_SHA384: - return TPM2_SHA384_DIGEST_SIZE; - case TPM2_ALG_SHA512: - return TPM2_SHA512_DIGEST_SIZE; - default: - return 0; - } -} - /* NV index attributes */ enum tpm_index_attrs { TPMA_NV_PPWRITE = 1UL << 0, @@ -712,6 +704,41 @@ enum tpm2_algorithms tpm2_name_to_algorithm(const char *name); */ const char *tpm2_algorithm_name(enum tpm2_algorithms); +/** + * tpm2_algorithm_to_len() - Return an algorithm length for supported algorithm id + * + * @algorithm_id: algorithm defined in enum tpm2_algorithms + * Return: len or 0 if not supported + */ +u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo); + +/* + * When measured boot is enabled via EFI or bootX commands all the algorithms + * above are selected by our Kconfigs. Due to U-Boots nature of being small there + * are cases where we need some functionality from the TPM -- e.g storage or RNG + * but we don't want to support measurements. + * + * The choice of hash algorithms are determined by the platform and the TPM + * configuration. Failing to cap a PCR in a bank which the platform left + * active is a security vulnerability. It permits the unsealing of secrets + * if an attacker can replay a good set of measurements into an unused bank. + * + * On top of that a previous stage bootloader (e.g TF-A), migh pass an eventlog + * since it doesn't have a TPM driver, which U-Boot needs to replace. The algorit h + * choice is a compile time option in that case and we need to make sure we conform. + * + * Add a variable here that sums the supported algorithms U-Boot was compiled + * with so we can refuse to do measurements if we don't support all of them + */ + +/** + * tpm2_allow_extend() - Check if extending PCRs is allowed and safe + * + * @dev: TPM device + * Return: true if allowed + */ +bool tpm2_allow_extend(struct udevice *dev); + /** * tpm2_is_active_pcr() - check the pcr_select. If at least one of the PCRs * supports the algorithm add it on the active ones diff --git a/lib/Kconfig b/lib/Kconfig index 189e6eb31aa..b3baa4b85b0 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -439,9 +439,6 @@ config TPM depends on DM imply DM_RNG select SHA1 - select SHA256 - select SHA384 - select SHA512 help This enables support for TPMs which can be used to provide security features for your board. The TPM can be connected via LPC or I2C @@ -449,6 +446,9 @@ config TPM command to interactive the TPM. Driver model support is provided for the low-level TPM interface, but only one TPM is supported at a time by the TPM library. + For size reasons only SHA1 is selected which is supported on TPM1.2. + If you want a fully functional TPM enable all hashing algorithms. + If you enabled measured boot all hashing algorithms are selected. config SPL_TPM bool "Trusted Platform Module (TPM) Support in SPL" diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 36aace03cf4..59e6cbafafa 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -196,6 +196,11 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, if (!digest) return -EINVAL; + + if (!tpm2_allow_extend(dev)) { + log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n"); + return -EINVAL; + } /* * Fill the command structure starting from the first buffer: * - the digest @@ -409,11 +414,10 @@ int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs) pcrs->count = get_unaligned_be32(response); /* - * We only support 5 algorithms for now so check against that + * We only support 4 algorithms for now so check against that * instead of TPM2_NUM_PCR_BANKS */ - if (pcrs->count > ARRAY_SIZE(hash_algo_list) || - pcrs->count < 1) { + if (pcrs->count > 4 || pcrs->count < 1) { printf("%s: too many pcrs: %u\n", __func__, pcrs->count); return -EMSGSIZE; } @@ -880,3 +884,33 @@ const char *tpm2_algorithm_name(enum tpm2_algorithms algo) return ""; } +u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { + if (hash_algo_list[i].hash_alg == algo) + return hash_algo_list[i].hash_len; + } + + return 0; +} + +bool tpm2_allow_extend(struct udevice *dev) +{ + struct tpml_pcr_selection pcrs; + size_t i; + int rc; + + rc = tpm2_get_pcr_info(dev, &pcrs); + if (rc) + return false; + + for (i = 0; i < pcrs.count; i++) { + if (tpm2_is_active_pcr(&pcrs.selection[i]) && + !tpm2_algorithm_to_len(pcrs.selection[i].hash)) + return false; + } + + return true; +} From 43b6b577bceda5f75204352b3dc4f0613b14e7d4 Mon Sep 17 00:00:00 2001 From: Bastian Germann Date: Mon, 24 Jun 2024 19:00:38 +0200 Subject: [PATCH 12/13] doc: fit: Make data-size a conditionally mandatory property Before 9d0750064e (doc: Move external FIT docs into the main body), the FIT property data-size was not a mandatory property and still it is not expected to be set alongside the data property. Move the data-size property to the "Conditionally mandatory property" section, where it actually belongs. Signed-off-by: Bastian Germann Reviewed-by: Simon Glass --- doc/usage/fit/source_file_format.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/usage/fit/source_file_format.rst b/doc/usage/fit/source_file_format.rst index 7727ab77c54..15990e3ff54 100644 --- a/doc/usage/fit/source_file_format.rst +++ b/doc/usage/fit/source_file_format.rst @@ -254,9 +254,6 @@ compression zstd zstd compressed ==================== ================== -data-size - size of the data in bytes - Conditionally mandatory property ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -276,6 +273,9 @@ data-position not relative to the loading of the FIT. This is mandatory if external data used with a fixed address. +data-size + Size of the data in bytes. This is mandatory if external data is used. + os OS name, mandatory for types "kernel". Valid OS names are: From 636480e4e7088d05d7ff77af72ca00443c62b3e9 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Wed, 26 Jun 2024 12:47:18 +0200 Subject: [PATCH 13/13] doc: develop: Add a general section on gdb usage Mashed up from different sources linked below, including the now gone Wiki and doc/README.arm-relocation file. Tested on a custom board with AT91 SAMA5D2 SoC and Segger J-Link Base adapter. This is only generic advice here, the usage is not board specific. Some board docs have more specific instructions on using gdb with a particular board. Link: https://www.slideshare.net/slideshow/embedded-recipes-2019-introduction-to-jtag-debugging/177511981 Link: https://boundarydevices.com/debugging-using-segger-j-link-jtag/ Link: https://web.archive.org/web/20141224200032/http://www.denx.de/wiki/view/DULG/DebuggingUBoot Link: https://web.archive.org/web/20141206064148/http://www.denx.de/wiki/view/DULG/GDBScripts1 Suggested-by: Marek Vasut Signed-off-by: Alexander Dahl Reviewed-by: Heinrich Schuchardt --- doc/develop/gdb.rst | 171 ++++++++++++++++++++++++++++++++++++++++++ doc/develop/index.rst | 1 + 2 files changed, 172 insertions(+) create mode 100644 doc/develop/gdb.rst diff --git a/doc/develop/gdb.rst b/doc/develop/gdb.rst new file mode 100644 index 00000000000..4e359c7f226 --- /dev/null +++ b/doc/develop/gdb.rst @@ -0,0 +1,171 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (c) 2024 Alexander Dahl + +Debugging U-Boot with GDB +========================= + +Using a JTAG adapter it is possible to debug a running U-Boot with GDB. +A common way is to connect a debug adapter to the JTAG connector of your +board, run a GDB server, connect GDB to the GDB server, and use GDB as usual. + +Similarly QEMU can provide a GDB server. + +Preparing build +--------------- + +Building U-Boot with with reduced optimization (-Og) and without link time +optimization is recommended for easier debugging:: + + CONFIG_CC_OPTIMIZE_FOR_DEBUG=y + CONFIG_LTO=n + +Otherwise build, install, and run U-Boot as usual. + +Using OpenOCD as GDB server +--------------------------- + +`OpenOCD `_ is an open source tool supporting hardware +debug probes, and providing a GDB server. It is readily available in major Linux +distributions or you can build it from source. + +Here is example of starting OpenOCD on Debian using a J-Link adapter and a +board with an AT91 SAMA5D2 SoC: + +.. code-block:: console + + $ openocd -f interface/jlink.cfg -f target/at91sama5d2.cfg -c 'adapter speed 4000' + Open On-Chip Debugger 0.12.0 + Licensed under GNU GPL v2 + For bug reports, read + http://openocd.org/doc/doxygen/bugs.html + Info : auto-selecting first available session transport "jtag". To override use 'transport select '. + adapter speed: 4000 kHz + + Info : Listening on port 6666 for tcl connections + Info : Listening on port 4444 for telnet connections + Info : J-Link V10 compiled Jan 30 2023 11:28:07 + Info : Hardware version: 10.10 + Info : VTarget = 3.244 V + Info : clock speed 4000 kHz + Info : JTAG tap: at91sama5d2.cpu tap/device found: 0x5ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x5) + Info : at91sama5d2.cpu_a5.0: hardware has 3 breakpoints, 2 watchpoints + Info : at91sama5d2.cpu_a5.0: MPIDR level2 0, cluster 0, core 0, mono core, no SMT + Info : starting gdb server for at91sama5d2.cpu_a5.0 on 3333 + Info : Listening on port 3333 for gdb connections + +Notice that OpenOCD is listening on port 3333 for GDB connections. + +Using QEMU as GDB server +------------------------ + +When running U-Boot on QEMU you can used the '-gdb' parameter to provide a +GDB server: + + qemu-system-riscv64 -M virt -nographic -gdb tcp::3333 -kernel u-boot + +Running a GDB session +---------------------- + +You need a GDB suited for your target. This can be the GDB coming with your +toolchain or *gdb-multiarch* available in your Linux distribution. + +.. prompt:: bash $ + + gdb-multiarch u-boot + +In the above command-line *u-boot* is the U-boot binary in your build +directory. You may need to adjust the path when calling GDB. + +Connect to the GDB server like this: + +.. code-block:: console + + (gdb) target extended-remote :3333 + Remote debugging using :3333 + 0x27fa9ac6 in ?? () + (gdb) + +This is fine for debugging before U-Boot relocates itself. + +For debugging U-Boot after relocation you need to indicate the relocation +address to GDB. You can retrieve the relocation address from the U-Boot shell +with the command *bdinfo*: + +.. code-block:: console + + U-Boot> bdinfo + boot_params = 0x20000100 + DRAM bank = 0x00000000 + -> start = 0x20000000 + -> size = 0x08000000 + flashstart = 0x00000000 + flashsize = 0x00000000 + flashoffset = 0x00000000 + baudrate = 115200 bps + relocaddr = 0x27f7a000 + reloc off = 0x0607a000 + Build = 32-bit + current eth = ethernet@f8008000 + ethaddr = 00:50:c2:31:58:d4 + IP addr = + fdt_blob = 0x27b36060 + new_fdt = 0x27b36060 + fdt_size = 0x00003e40 + lmb_dump_all: + memory.cnt = 0x1 / max = 0x10 + memory[0] [0x20000000-0x27ffffff], 0x08000000 bytes flags: 0 + reserved.cnt = 0x1 / max = 0x10 + reserved[0] [0x27b31d00-0x27ffffff], 0x004ce300 bytes flags: 0 + devicetree = separate + arch_number = 0x00000000 + TLB addr = 0x27ff0000 + irq_sp = 0x27b36050 + sp start = 0x27b36040 + Early malloc usage: cd8 / 2000 + +Look out for the line starting with *relocaddr* which has the address +you need, ``0x27f7a000`` in this case. + +On most architectures (not sandbox, x86, Xtensa) the global data pointer is +stored in a fixed register: + +============ ======== +Architecture Register +============ ======== +arc r25 +arm r9 +arm64 x18 +m68k d7 +microblaze r31 +mips k0 +nios2 gp +powerpc r2 +riscv gp +sh r13 +============ ======== + +On these architecture the relocation address cat be determined by +dereferencing the global data pointer stored in register, *r9* in the example: + +.. code-block:: console + + (gdb) p/x (*(struct global_data*)$r9)->relocaddr + $1 = 0x27f7a000 + +In the GDB shell discard the previously loaded symbol file and add it once +again with the relocation address like this: + +.. code-block:: console + + (gdb) symbol-file + Discard symbol table from `/home/adahl/build/u-boot/v2024.04.x/u-boot'? (y or n) y + No symbol file now. + (gdb) add-symbol-file u-boot 0x27f7a000 + add symbol table from file "u-boot" at + .text_addr = 0x27f7a000 + (y or n) y + Reading symbols from u-boot... + (gdb) + +You can now use GDB as usual, setting breakpoints, printing backtraces, +inspecting variables, stepping through the code, etc. diff --git a/doc/develop/index.rst b/doc/develop/index.rst index f82e148b101..f9c4bf839ee 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -60,6 +60,7 @@ Debugging :maxdepth: 1 crash_dumps + gdb trace Packaging