summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-07-01 13:17:56 -0600
committerTom Rini <trini@konsulko.com>2024-07-01 15:00:56 -0600
commit65fbdab27224ee3943a89496b21862db83c34da2 (patch)
tree775a0a54066c2e9a6bbba201676e3d896b5cb0e2 /lib
parent3f772959501c99fbe5aa0b22a36efe3478d1ae1c (diff)
parentb4cbd1a257d4027038b4f997d73bdb0a066db045 (diff)
downloadu-boot-65fbdab27224ee3943a89496b21862db83c34da2.tar.gz
u-boot-65fbdab27224ee3943a89496b21862db83c34da2.tar.bz2
u-boot-65fbdab27224ee3943a89496b21862db83c34da2.zip
Merge branch 'next'
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig4
-rw-r--r--lib/Makefile2
-rw-r--r--lib/display_options.c1
-rw-r--r--lib/efi_loader/Kconfig2
-rw-r--r--lib/efi_loader/Makefile1
-rw-r--r--lib/efi_loader/efi_bootbin.c2
-rw-r--r--lib/efi_loader/efi_bootmgr.c81
-rw-r--r--lib/efi_loader/efi_boottime.c3
-rw-r--r--lib/efi_loader/efi_capsule.c14
-rw-r--r--lib/efi_loader/efi_device_path.c40
-rw-r--r--lib/efi_loader/efi_device_path_utilities.c2
-rw-r--r--lib/efi_loader/efi_fdt.c117
-rw-r--r--lib/efi_loader/efi_helper.c44
-rw-r--r--lib/efi_loader/efi_load_initrd.c2
-rw-r--r--lib/efi_loader/efi_signature.c1
-rw-r--r--lib/efi_loader/efi_tcg2.c6
-rw-r--r--lib/efi_loader/initrddump.c2
-rw-r--r--lib/efi_selftest/efi_selftest_fdt.c7
-rw-r--r--lib/elf.c54
-rw-r--r--lib/fwu_updates/Kconfig14
-rw-r--r--lib/fwu_updates/Makefile2
-rw-r--r--lib/fwu_updates/fwu.c204
-rw-r--r--lib/fwu_updates/fwu_mtd.c36
-rw-r--r--lib/fwu_updates/fwu_v1.c167
-rw-r--r--lib/fwu_updates/fwu_v2.c260
-rw-r--r--lib/hexdump.c2
-rw-r--r--lib/md5.c10
-rw-r--r--lib/smbios.c44
-rw-r--r--lib/tpm-v2.c767
-rw-r--r--lib/tpm_tcg2.c731
-rw-r--r--lib/vsprintf.c1
31 files changed, 1774 insertions, 849 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 568892fce4..b3baa4b85b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -438,6 +438,7 @@ config TPM
bool "Trusted Platform Module (TPM) Support"
depends on DM
imply DM_RNG
+ select SHA1
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
@@ -445,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/Makefile b/lib/Makefile
index 2a76acf100..e389ad014f 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/display_options.c b/lib/display_options.c
index d6b93553dc..d5df53ab15 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -12,6 +12,7 @@
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <asm/io.h>
+#include <stdio.h>
#include <vsprintf.h>
char *display_options_get_banner_priv(bool newlines, const char *build_tag,
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 430bb7f0f7..ee71f41714 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -10,9 +10,9 @@ config EFI_LOADER
depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
- depends on BLK
depends on !EFI_APP
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
+ select BLK
select CHARSET
# We need to send DM events, dynamically, in the EFI block driver
select DM_EVENT
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 034e366967..2af6f2066b 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -59,6 +59,7 @@ obj-y += efi_device_path.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o
obj-y += efi_dt_fixup.o
+obj-y += efi_fdt.o
obj-y += efi_file.o
obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
obj-y += efi_image_loader.o
diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c
index b7910f78fb..a87006b3c0 100644
--- a/lib/efi_loader/efi_bootbin.c
+++ b/lib/efi_loader/efi_bootbin.c
@@ -150,7 +150,7 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
msg_path = file_path;
} else {
file_path = efi_dp_concat(bootefi_device_path,
- bootefi_image_path, false);
+ bootefi_image_path, 0);
msg_path = bootefi_image_path;
log_debug("Loaded from disk\n");
}
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 7da3139f91..304ed43595 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -130,7 +130,7 @@ static efi_status_t try_load_from_file_path(efi_handle_t *fs_handles,
if (!dp)
continue;
- dp = efi_dp_concat(dp, fp, false);
+ dp = efi_dp_concat(dp, fp, 0);
if (!dp)
continue;
@@ -1186,6 +1186,59 @@ out:
}
/**
+ * load_fdt_from_load_option - load device-tree from load option
+ *
+ * @fdt: pointer to loaded device-tree or NULL
+ * Return: status code
+ */
+static efi_status_t load_fdt_from_load_option(void **fdt)
+{
+ struct efi_device_path *dp = NULL;
+ struct efi_file_handle *f = NULL;
+ efi_uintn_t filesize;
+ efi_status_t ret;
+
+ *fdt = NULL;
+
+ dp = efi_get_dp_from_boot(&efi_guid_fdt);
+ if (!dp)
+ return EFI_SUCCESS;
+
+ /* Open file */
+ f = efi_file_from_path(dp);
+ if (!f) {
+ log_err("Can't find %pD specified in Boot####\n", dp);
+ ret = EFI_NOT_FOUND;
+ goto out;
+ }
+
+ /* Get file size */
+ ret = efi_file_size(f, &filesize);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ *fdt = calloc(1, filesize);
+ if (!*fdt) {
+ log_err("Out of memory\n");
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ ret = EFI_CALL(f->read(f, &filesize, *fdt));
+ if (ret != EFI_SUCCESS) {
+ log_err("Can't read fdt\n");
+ free(*fdt);
+ *fdt = NULL;
+ }
+
+out:
+ efi_free_pool(dp);
+ if (f)
+ EFI_CALL(f->close(f));
+
+ return ret;
+}
+
+/**
* efi_bootmgr_run() - execute EFI boot manager
* @fdt: Flat device tree
*
@@ -1200,6 +1253,8 @@ efi_status_t efi_bootmgr_run(void *fdt)
efi_handle_t handle;
void *load_options;
efi_status_t ret;
+ void *fdt_lo, *fdt_distro = NULL;
+ efi_uintn_t fdt_size;
/* Initialize EFI drivers */
ret = efi_init_obj_list();
@@ -1215,7 +1270,31 @@ efi_status_t efi_bootmgr_run(void *fdt)
return ret;
}
+ if (!IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
+ ret = load_fdt_from_load_option(&fdt_lo);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ if (fdt_lo)
+ fdt = fdt_lo;
+ if (!fdt) {
+ efi_load_distro_fdt(&fdt_distro, &fdt_size);
+ fdt = fdt_distro;
+ }
+ }
+
+ /*
+ * Needed in ACPI case to create reservations based on
+ * control device-tree.
+ */
ret = efi_install_fdt(fdt);
+
+ if (!IS_ENABLED(CONFIG_GENERATE_ACPI_TABLE)) {
+ free(fdt_lo);
+ if (fdt_distro)
+ efi_free_pages((uintptr_t)fdt_distro,
+ efi_size_in_pages(fdt_size));
+ }
+
if (ret != EFI_SUCCESS) {
if (EFI_CALL(efi_unload_image(handle)) == EFI_SUCCESS)
free(load_options);
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 1951291747..eedc5f3954 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1816,7 +1816,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
if (device_path) {
info->device_handle = efi_dp_find_obj(device_path, NULL, NULL);
- dp = efi_dp_concat(device_path, file_path, false);
+ dp = efi_dp_concat(device_path, file_path, 0);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto failure;
@@ -1996,7 +1996,6 @@ error:
* @size: size of the loaded image
* Return: status code
*/
-static
efi_status_t efi_load_image_from_path(bool boot_policy,
struct efi_device_path *file_path,
void **buffer, efi_uintn_t *size)
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index de0d49ebeb..0937800e58 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -480,6 +480,11 @@ static __maybe_unused efi_status_t fwu_empty_capsule_process(
if (ret != EFI_SUCCESS)
log_err("Unable to set the Accept bit for the image %pUs\n",
image_guid);
+
+ status = fwu_state_machine_updates(0, active_idx);
+ if (status < 0)
+ ret = EFI_DEVICE_ERROR;
+
}
return ret;
@@ -521,11 +526,10 @@ static __maybe_unused efi_status_t fwu_post_update_process(bool fw_accept_os)
log_err("Failed to update FWU metadata index values\n");
} else {
log_debug("Successfully updated the active_index\n");
- if (fw_accept_os) {
- status = fwu_trial_state_ctr_start();
- if (status < 0)
- ret = EFI_DEVICE_ERROR;
- }
+ status = fwu_state_machine_updates(fw_accept_os ? 1 : 0,
+ update_index);
+ if (status < 0)
+ ret = EFI_DEVICE_ERROR;
}
return ret;
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index aec224d846..0f684590f2 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -276,10 +276,11 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
*
* @dp1: First device path
* @dp2: Second device path
- * @split_end_node: If true the two device paths will be concatenated and
- * separated by an end node (DEVICE_PATH_SUB_TYPE_END).
- * If false the second device path will be concatenated to the
- * first one as-is.
+ * @split_end_node:
+ * * 0 to concatenate
+ * * 1 to concatenate with end node added as separator
+ * * size of dp1 excluding last end node to concatenate with end node as
+ * separator in case dp1 contains an end node
*
* Return:
* concatenated device path or NULL. Caller must free the returned value
@@ -287,7 +288,7 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
struct
efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
const struct efi_device_path *dp2,
- bool split_end_node)
+ size_t split_end_node)
{
struct efi_device_path *ret;
size_t end_size;
@@ -301,10 +302,15 @@ efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
ret = efi_dp_dup(dp1);
} else {
/* both dp1 and dp2 are non-null */
- unsigned sz1 = efi_dp_size(dp1);
- unsigned sz2 = efi_dp_size(dp2);
+ size_t sz1;
+ size_t sz2 = efi_dp_size(dp2);
void *p;
+ if (split_end_node < sizeof(struct efi_device_path))
+ sz1 = efi_dp_size(dp1);
+ else
+ sz1 = split_end_node;
+
if (split_end_node)
end_size = 2 * sizeof(END);
else
@@ -1127,17 +1133,18 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp,
}
/**
- * efi_dp_from_lo() - Get the instance of a VenMedia node in a
- * multi-instance device path that matches
- * a specific GUID. This kind of device paths
- * is found in Boot#### options describing an
- * initrd location
+ * efi_dp_from_lo() - get device-path from load option
*
- * @lo: EFI_LOAD_OPTION containing a valid device path
- * @guid: guid to search for
+ * The load options in U-Boot may contain multiple concatenated device-paths.
+ * The first device-path indicates the EFI binary to execute. Subsequent
+ * device-paths start with a VenMedia node where the GUID identifies the
+ * function (initrd or fdt).
+ *
+ * @lo: EFI load option containing a valid device path
+ * @guid: GUID identifying device-path or NULL for the EFI binary
*
* Return:
- * device path including the VenMedia node or NULL.
+ * device path excluding the matched VenMedia node or NULL.
* Caller must free the returned value.
*/
struct
@@ -1148,6 +1155,9 @@ efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
struct efi_device_path_vendor *vendor;
int lo_len = lo->file_path_length;
+ if (!guid)
+ return efi_dp_dup(fp);
+
for (; lo_len >= sizeof(struct efi_device_path);
lo_len -= fp->length, fp = (void *)fp + fp->length) {
if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c
index c95dbfa9b5..ac250bbfcc 100644
--- a/lib/efi_loader/efi_device_path_utilities.c
+++ b/lib/efi_loader/efi_device_path_utilities.c
@@ -76,7 +76,7 @@ static struct efi_device_path * EFIAPI append_device_path(
const struct efi_device_path *src2)
{
EFI_ENTRY("%pD, %pD", src1, src2);
- return EFI_EXIT(efi_dp_concat(src1, src2, false));
+ return EFI_EXIT(efi_dp_concat(src1, src2, 0));
}
/*
diff --git a/lib/efi_loader/efi_fdt.c b/lib/efi_loader/efi_fdt.c
new file mode 100644
index 0000000000..86ba00c2bd
--- /dev/null
+++ b/lib/efi_loader/efi_fdt.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Bootmethod for distro boot via EFI
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <efi_loader.h>
+#include <env.h>
+#include <errno.h>
+#include <log.h>
+#include <string.h>
+#include <vsprintf.h>
+
+/**
+ * distro_efi_get_fdt_name() - get the filename for reading the .dtb file
+ *
+ * @fname: buffer for filename
+ * @size: buffer size
+ * @seq: sequence number, to cycle through options (0=first)
+ *
+ * Returns:
+ * 0 on success,
+ * -ENOENT if the "fdtfile" env var does not exist,
+ * -EINVAL if there are no more options,
+ * -EALREADY if the control FDT should be used
+ */
+int efi_get_distro_fdt_name(char *fname, int size, int seq)
+{
+ const char *fdt_fname;
+ const char *prefix;
+
+ /* select the prefix */
+ switch (seq) {
+ case 0:
+ /* this is the default */
+ prefix = "/dtb";
+ break;
+ case 1:
+ prefix = "";
+ break;
+ case 2:
+ prefix = "/dtb/current";
+ break;
+ default:
+ return log_msg_ret("pref", -EINVAL);
+ }
+
+ fdt_fname = env_get("fdtfile");
+ if (fdt_fname) {
+ snprintf(fname, size, "%s/%s", prefix, fdt_fname);
+ log_debug("Using device tree: %s\n", fname);
+ } else if (IS_ENABLED(CONFIG_OF_HAS_PRIOR_STAGE)) {
+ strcpy(fname, "<prior>");
+ return log_msg_ret("pref", -EALREADY);
+ /* Use this fallback only for 32-bit ARM */
+ } else if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_ARM64)) {
+ const char *soc = env_get("soc");
+ const char *board = env_get("board");
+ const char *boardver = env_get("boardver");
+
+ /* cf the code in label_boot() which seems very complex */
+ snprintf(fname, size, "%s/%s%s%s%s.dtb", prefix,
+ soc ? soc : "", soc ? "-" : "", board ? board : "",
+ boardver ? boardver : "");
+ log_debug("Using default device tree: %s\n", fname);
+ } else {
+ return log_msg_ret("env", -ENOENT);
+ }
+
+ return 0;
+}
+
+/**
+ * efi_load_distro_fdt() - load distro device-tree
+ *
+ * @fdt: on return device-tree, must be freed via efi_free_pages()
+ * @fdt_size: buffer size
+ */
+void efi_load_distro_fdt(void **fdt, efi_uintn_t *fdt_size)
+{
+ struct efi_device_path *rem, *dp;
+ efi_status_t ret;
+ efi_handle_t device;
+
+ *fdt = NULL;
+
+ dp = efi_get_dp_from_boot(NULL);
+ if (!dp)
+ return;
+ device = efi_dp_find_obj(dp, NULL, &rem);
+ ret = efi_search_protocol(device, &efi_simple_file_system_protocol_guid,
+ NULL);
+ if (ret != EFI_SUCCESS)
+ goto err;
+ memcpy(rem, &END, sizeof(END));
+
+ /* try the various available names */
+ for (int seq = 0; ; ++seq) {
+ struct efi_device_path *file;
+ char buf[255];
+
+ if (efi_get_distro_fdt_name(buf, sizeof(buf), seq))
+ break;
+ file = efi_dp_from_file(dp, buf);
+ if (!file)
+ break;
+ ret = efi_load_image_from_path(true, file, fdt, fdt_size);
+ efi_free_pool(file);
+ if (ret == EFI_SUCCESS)
+ break;
+ }
+
+err:
+ efi_free_pool(dp);
+}
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 73d0279e84..348612c3da 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -99,6 +99,50 @@ err:
return NULL;
}
+/**
+ * efi_load_option_dp_join() - join device-paths for load option
+ *
+ * @dp: in: binary device-path, out: joined device-path
+ * @dp_size: size of joined device-path
+ * @initrd_dp: initrd device-path or NULL
+ * @fdt_dp: device-tree device-path or NULL
+ * Return: status_code
+ */
+efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
+ size_t *dp_size,
+ struct efi_device_path *initrd_dp,
+ struct efi_device_path *fdt_dp)
+{
+ if (!dp)
+ return EFI_INVALID_PARAMETER;
+
+ *dp_size = efi_dp_size(*dp);
+
+ if (initrd_dp) {
+ struct efi_device_path *tmp_dp = *dp;
+
+ *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size);
+ efi_free_pool(tmp_dp);
+ if (!*dp)
+ return EFI_OUT_OF_RESOURCES;
+ *dp_size += efi_dp_size(initrd_dp) + sizeof(END);
+ }
+
+ if (fdt_dp) {
+ struct efi_device_path *tmp_dp = *dp;
+
+ *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
+ efi_free_pool(tmp_dp);
+ if (!dp)
+ return EFI_OUT_OF_RESOURCES;
+ *dp_size += efi_dp_size(fdt_dp) + sizeof(END);
+ }
+
+ *dp_size += sizeof(END);
+
+ return EFI_SUCCESS;
+}
+
const struct guid_to_hash_map {
efi_guid_t guid;
const char algo[32];
diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c
index d91135436c..23508431c8 100644
--- a/lib/efi_loader/efi_load_initrd.c
+++ b/lib/efi_loader/efi_load_initrd.c
@@ -24,7 +24,7 @@ static const struct efi_load_file_protocol efi_lf2_protocol = {
* Device path defined by Linux to identify the handle providing the
* EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
*/
-static const struct efi_initrd_dp dp_lf2_handle = {
+static const struct efi_lo_dp_prefix dp_lf2_handle = {
.vendor = {
{
DEVICE_PATH_TYPE_MEDIA_DEVICE,
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index f338e73275..184eac8cdd 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -17,7 +17,6 @@
#include <linux/oid_registry.h>
#include <u-boot/hash-checksum.h>
#include <u-boot/rsa.h>
-#include <u-boot/sha256.h>
const efi_guid_t efi_guid_sha256 = EFI_CERT_SHA256_GUID;
const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID;
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index b4915cab6b..45f451ef6b 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -16,12 +16,8 @@
#include <malloc.h>
#include <smbios.h>
#include <version_string.h>
-#include <tpm-v2.h>
#include <tpm_api.h>
#include <u-boot/hash-checksum.h>
-#include <u-boot/sha1.h>
-#include <u-boot/sha256.h>
-#include <u-boot/sha512.h>
#include <linux/unaligned/be_byteshift.h>
#include <linux/unaligned/le_byteshift.h>
#include <linux/unaligned/generic.h>
@@ -280,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/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c
index 0004b6b042..615119043d 100644
--- a/lib/efi_loader/initrddump.c
+++ b/lib/efi_loader/initrddump.c
@@ -33,7 +33,7 @@ static bool nocolor;
* Device path defined by Linux to identify the handle providing the
* EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
*/
-static const struct efi_initrd_dp initrd_dp = {
+static const struct efi_lo_dp_prefix initrd_dp = {
.vendor = {
{
DEVICE_PATH_TYPE_MEDIA_DEVICE,
diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c
index aa3b13ae3a..a4b0cef20e 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;
diff --git a/lib/elf.c b/lib/elf.c
index 9a794f9cba..dc13935e10 100644
--- a/lib/elf.c
+++ b/lib/elf.c
@@ -7,6 +7,7 @@
#include <cpu_func.h>
#include <elf.h>
#include <env.h>
+#include <errno.h>
#include <net.h>
#include <vxworks.h>
#ifdef CONFIG_X86
@@ -15,6 +16,59 @@
#include <linux/linkage.h>
#endif
+/**
+ * bootelf_exec() - start the ELF image execution.
+ *
+ * @entry: address of entry point of ELF.
+ *
+ * May by used to allow ports to override the default behavior.
+ */
+unsigned long bootelf_exec(ulong (*entry)(int, char * const[]),
+ int argc, char *const argv[])
+{
+ return entry(argc, argv);
+}
+
+/**
+ * bootelf() - Boot ELF from memory.
+ *
+ * @addr: Loading address of ELF in memory.
+ * @flags: Bits like ELF_PHDR to control boot details.
+ * @argc: May be used to pass command line arguments (maybe unused).
+ * Necessary for backward compatibility with the CLI command.
+ * If unused, must be 0.
+ * @argv: see @argc. If unused, must be NULL.
+ * Return: Number returned by ELF application.
+ *
+ * Sets errno = ENOEXEC if the ELF image is not valid.
+ */
+unsigned long bootelf(unsigned long addr, Bootelf_flags flags,
+ int argc, char *const argv[])
+{
+ unsigned long entry_addr;
+ char *args[] = {"", NULL};
+
+ errno = 0;
+
+ if (!valid_elf_image(addr)) {
+ errno = ENOEXEC;
+ return 1;
+ }
+
+ entry_addr = flags.phdr ? load_elf_image_phdr(addr)
+ : load_elf_image_shdr(addr);
+
+ if (!flags.autostart)
+ return 0;
+
+ if (!argc && !argv) {
+ argc = 1;
+ argv = args;
+ }
+
+ return bootelf_exec((void *)entry_addr, argc, argv);
+}
+
/*
* A very simple ELF64 loader, assumes the image is valid, returns the
* entry point address.
diff --git a/lib/fwu_updates/Kconfig b/lib/fwu_updates/Kconfig
index d35247d0e5..51b7fbbefd 100644
--- a/lib/fwu_updates/Kconfig
+++ b/lib/fwu_updates/Kconfig
@@ -31,4 +31,18 @@ config FWU_TRIAL_STATE_CNT
the platform is allowed to boot in Trial State after an
update.
+config FWU_MDATA_V1
+ bool "Enable support FWU Metadata version 1"
+ help
+ The FWU specification supports two versions of the
+ metadata structure. This option enables support for FWU
+ Metadata version 1 access.
+
+config FWU_MDATA_V2
+ bool "Enable support FWU Metadata version 2"
+ help
+ The FWU specification supports two versions of the
+ metadata structure. This option enables support for FWU
+ Metadata version 2 access.
+
endif
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
index c9e3c06b48..3681bef46c 100644
--- a/lib/fwu_updates/Makefile
+++ b/lib/fwu_updates/Makefile
@@ -6,3 +6,5 @@
obj-$(CONFIG_FWU_MULTI_BANK_UPDATE) += fwu.o
obj-$(CONFIG_FWU_MDATA_GPT_BLK) += fwu_gpt.o
obj-$(CONFIG_FWU_MDATA_MTD) += fwu_mtd.o
+obj-$(CONFIG_FWU_MDATA_V1) += fwu_v1.o
+obj-$(CONFIG_FWU_MDATA_V2) += fwu_v2.o
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 86518108c2..5dfea2a4d8 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -10,6 +10,7 @@
#include <event.h>
#include <fwu.h>
#include <fwu_mdata.h>
+#include <log.h>
#include <malloc.h>
#include <linux/errno.h>
@@ -17,7 +18,7 @@
#include <u-boot/crc.h>
-static struct fwu_mdata g_mdata; /* = {0} makes uninit crc32 always invalid */
+struct fwu_data g_fwu_data;
static struct udevice *g_dev;
static u8 in_trial;
static u8 boottime_check;
@@ -27,12 +28,6 @@ enum {
IMAGE_ACCEPT_CLEAR,
};
-enum {
- PRIMARY_PART = 1,
- SECONDARY_PART,
- BOTH_PARTS,
-};
-
static int trial_counter_update(u16 *trial_state_ctr)
{
bool delete;
@@ -106,23 +101,9 @@ out:
return ret;
}
-static int in_trial_state(struct fwu_mdata *mdata)
+static u32 in_trial_state(void)
{
- u32 i, active_bank;
- struct fwu_image_entry *img_entry;
- struct fwu_image_bank_info *img_bank_info;
-
- active_bank = mdata->active_index;
- img_entry = &mdata->img_entry[0];
- for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- img_bank_info = &img_entry[i].img_bank_info[active_bank];
- if (!img_bank_info->accepted) {
- log_info("System booting in Trial State\n");
- return 1;
- }
- }
-
- return 0;
+ return g_fwu_data.trial_state;
}
static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id)
@@ -141,17 +122,70 @@ static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id)
return -ENOENT;
}
+static int mdata_crc_check(struct fwu_mdata *mdata)
+{
+ int ret;
+ u32 calc_crc32;
+ uint32_t mdata_size;
+ void *buf = &mdata->version;
+
+ ret = fwu_get_mdata_size(&mdata_size);
+ if (ret)
+ return ret;
+
+ calc_crc32 = crc32(0, buf, mdata_size - sizeof(u32));
+ return calc_crc32 == mdata->crc32 ? 0 : -EINVAL;
+}
+
+static void fwu_data_crc_update(uint32_t crc32)
+{
+ g_fwu_data.crc32 = crc32;
+}
+
+/**
+ * fwu_get_data() - Return the version agnostic FWU structure
+ *
+ * Return the pointer to the version agnostic FWU structure.
+ *
+ * Return: Pointer to the FWU data structure
+ */
+struct fwu_data *fwu_get_data(void)
+{
+ return &g_fwu_data;
+}
+
+static void fwu_populate_mdata_bank_index(struct fwu_data *fwu_data)
+{
+ struct fwu_mdata *mdata = fwu_data->fwu_mdata;
+
+ mdata->active_index = fwu_data->active_index;
+ mdata->previous_active_index = fwu_data->previous_active_index;
+}
+
+/**
+ * fwu_get_dev() - Return the FWU metadata device
+ *
+ * Return the pointer to the FWU metadata device.
+ *
+ * Return: Pointer to the FWU metadata dev
+ */
+struct udevice *fwu_get_dev(void)
+{
+ return g_dev;
+}
+
/**
* fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided
- * @mdata: FWU metadata structure
+ * @data: FWU Data structure
* @part: Bitmask of FWU metadata partitions to be written to
*
* Return: 0 if OK, -ve on error
*/
-static int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
+int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
{
- void *buf = &mdata->version;
int err;
+ uint mdata_size;
+ void *buf = &mdata->version;
if (part == BOTH_PARTS) {
err = fwu_sync_mdata(mdata, SECONDARY_PART);
@@ -160,32 +194,53 @@ static int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
part = PRIMARY_PART;
}
+ err = fwu_get_mdata_size(&mdata_size);
+ if (err)
+ return err;
+
/*
* Calculate the crc32 for the updated FWU metadata
* and put the updated value in the FWU metadata crc32
* field
*/
- mdata->crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+ mdata->crc32 = crc32(0, buf, mdata_size - sizeof(u32));
+ fwu_data_crc_update(mdata->crc32);
- err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART);
+ err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART, mdata_size);
if (err) {
log_err("Unable to write %s mdata\n",
part == PRIMARY_PART ? "primary" : "secondary");
return err;
}
- /* update the cached copy of meta-data */
- memcpy(&g_mdata, mdata, sizeof(struct fwu_mdata));
-
return 0;
}
-static inline int mdata_crc_check(struct fwu_mdata *mdata)
+/**
+ * fwu_mdata_copies_allocate() - Allocate memory for metadata
+ * @mdata_size: Size of the metadata structure
+ *
+ * Allocate memory for storing both the copies of the FWU metadata. The
+ * copies are then used as a cache for storing FWU metadata contents.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_mdata_copies_allocate(u32 mdata_size)
{
- void *buf = &mdata->version;
- u32 calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+ if (g_fwu_data.fwu_mdata)
+ return 0;
- return calc_crc32 == mdata->crc32 ? 0 : -EINVAL;
+ /*
+ * Allocate the total memory that would be needed for both
+ * the copies.
+ */
+ g_fwu_data.fwu_mdata = calloc(2, mdata_size);
+ if (!g_fwu_data.fwu_mdata) {
+ log_err("Unable to allocate space for FWU metadata\n");
+ return -ENOMEM;
+ }
+
+ return 0;
}
/**
@@ -201,21 +256,33 @@ static inline int mdata_crc_check(struct fwu_mdata *mdata)
int fwu_get_mdata(struct fwu_mdata *mdata)
{
int err;
+ uint32_t mdata_size;
bool parts_ok[2] = { false };
- struct fwu_mdata s, *parts_mdata[2];
+ struct fwu_mdata *parts_mdata[2];
- parts_mdata[0] = &g_mdata;
- parts_mdata[1] = &s;
+ err = fwu_get_mdata_size(&mdata_size);
+ if (err)
+ return err;
+
+ parts_mdata[0] = g_fwu_data.fwu_mdata;
+ if (!parts_mdata[0]) {
+ log_err("Memory not allocated for the FWU Metadata copies\n");
+ return -ENOMEM;
+ }
+
+ parts_mdata[1] = (struct fwu_mdata *)((char *)parts_mdata[0] +
+ mdata_size);
/* if mdata already read and ready */
err = mdata_crc_check(parts_mdata[0]);
if (!err)
goto ret_mdata;
- /* else read, verify and, if needed, fix mdata */
+
+ /* else read, verify and, if needed, fix mdata */
for (int i = 0; i < 2; i++) {
parts_ok[i] = false;
- err = fwu_read_mdata(g_dev, parts_mdata[i], !i);
+ err = fwu_read_mdata(g_dev, parts_mdata[i], !i, mdata_size);
if (!err) {
err = mdata_crc_check(parts_mdata[i]);
if (!err)
@@ -230,7 +297,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
* Before returning, check that both the
* FWU metadata copies are the same.
*/
- err = memcmp(parts_mdata[0], parts_mdata[1], sizeof(struct fwu_mdata));
+ err = memcmp(parts_mdata[0], parts_mdata[1], mdata_size);
if (!err)
goto ret_mdata;
@@ -247,7 +314,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
if (parts_ok[i])
continue;
- memcpy(parts_mdata[i], parts_mdata[1 - i], sizeof(struct fwu_mdata));
+ memcpy(parts_mdata[i], parts_mdata[1 - i], mdata_size);
err = fwu_sync_mdata(parts_mdata[i], i ? SECONDARY_PART : PRIMARY_PART);
if (err) {
log_debug("mdata : %s write failed\n", i ? "secondary" : "primary");
@@ -257,7 +324,7 @@ int fwu_get_mdata(struct fwu_mdata *mdata)
ret_mdata:
if (!err && mdata)
- memcpy(mdata, parts_mdata[0], sizeof(struct fwu_mdata));
+ memcpy(mdata, parts_mdata[0], mdata_size);
return err;
}
@@ -275,13 +342,13 @@ ret_mdata:
int fwu_get_active_index(uint *active_idx)
{
int ret = 0;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
- *active_idx = mdata->active_index;
+ *active_idx = data->active_index;
if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Active index value read is incorrect\n");
ret = -EINVAL;
@@ -302,7 +369,7 @@ int fwu_get_active_index(uint *active_idx)
int fwu_set_active_index(uint active_idx)
{
int ret;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
if (active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Invalid active index value\n");
@@ -313,14 +380,16 @@ int fwu_set_active_index(uint active_idx)
* Update the active index and previous_active_index fields
* in the FWU metadata
*/
- mdata->previous_active_index = mdata->active_index;
- mdata->active_index = active_idx;
+ data->previous_active_index = data->active_index;
+ data->active_index = active_idx;
+
+ fwu_populate_mdata_bank_index(data);
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -346,7 +415,7 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num)
int ret, i;
uint update_bank;
efi_guid_t *image_guid, image_type_id;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
@@ -365,15 +434,15 @@ int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num)
ret = -EINVAL;
/*
- * The FWU metadata has been read. Now get the image_uuid for the
+ * The FWU metadata has been read. Now get the image_guid for the
* image with the update_bank.
*/
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
if (!guidcmp(&image_type_id,
- &mdata->img_entry[i].image_type_uuid)) {
- img_entry = &mdata->img_entry[i];
+ &data->fwu_images[i].image_type_guid)) {
+ img_entry = &data->fwu_images[i];
img_bank_info = &img_entry->img_bank_info[update_bank];
- image_guid = &img_bank_info->image_uuid;
+ image_guid = &img_bank_info->image_guid;
ret = fwu_plat_get_alt_num(g_dev, image_guid, alt_num);
if (ret)
log_debug("alt_num not found for partition with GUID %pUs\n",
@@ -407,21 +476,23 @@ int fwu_revert_boot_index(void)
{
int ret;
u32 cur_active_index;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
/*
* Swap the active index and previous_active_index fields
* in the FWU metadata
*/
- cur_active_index = mdata->active_index;
- mdata->active_index = mdata->previous_active_index;
- mdata->previous_active_index = cur_active_index;
+ cur_active_index = data->active_index;
+ data->active_index = data->previous_active_index;
+ data->previous_active_index = cur_active_index;
+
+ fwu_populate_mdata_bank_index(data);
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -448,20 +519,21 @@ int fwu_revert_boot_index(void)
static int fwu_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
{
int ret, i;
- struct fwu_mdata *mdata = &g_mdata;
+ struct fwu_data *data = &g_fwu_data;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
- img_entry = &mdata->img_entry[0];
+ img_entry = &data->fwu_images[0];
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
+ if (!guidcmp(&img_entry[i].image_type_guid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
if (action == IMAGE_ACCEPT_SET)
img_bank_info->accepted |= FWU_IMAGE_ACCEPTED;
else
img_bank_info->accepted = 0;
- ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ fwu_populate_mdata_image_info(data);
+ ret = fwu_sync_mdata(data->fwu_mdata, BOTH_PARTS);
goto out;
}
}
@@ -627,9 +699,9 @@ static int fwu_boottime_checks(void)
return 0;
}
- ret = fwu_get_mdata(NULL);
+ ret = fwu_init();
if (ret) {
- log_debug("Unable to read meta-data\n");
+ log_debug("fwu_init() failed\n");
return ret;
}
@@ -665,7 +737,7 @@ static int fwu_boottime_checks(void)
if (efi_init_obj_list() != EFI_SUCCESS)
return 0;
- in_trial = in_trial_state(&g_mdata);
+ in_trial = in_trial_state();
if (!in_trial || (ret = fwu_trial_count_update()) > 0)
ret = trial_counter_update(NULL);
diff --git a/lib/fwu_updates/fwu_mtd.c b/lib/fwu_updates/fwu_mtd.c
index 69cd3d7001..ccaba3f311 100644
--- a/lib/fwu_updates/fwu_mtd.c
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -11,20 +11,25 @@
#include <malloc.h>
#include <mtd.h>
#include <uuid.h>
-#include <vsprintf.h>
+#include <stdio.h>
#include <dm/ofnode.h>
-struct fwu_mtd_image_info
-fwu_mtd_images[CONFIG_FWU_NUM_BANKS * CONFIG_FWU_NUM_IMAGES_PER_BANK];
-
static struct fwu_mtd_image_info *mtd_img_by_uuid(const char *uuidbuf)
{
- int num_images = ARRAY_SIZE(fwu_mtd_images);
+ int num_images;
+ struct fwu_mdata_mtd_priv *mtd_priv = dev_get_priv(fwu_get_dev());
+ struct fwu_mtd_image_info *image_info = mtd_priv->fwu_mtd_images;
+
+ if (!image_info)
+ return NULL;
+
+ num_images = CONFIG_FWU_NUM_BANKS *
+ CONFIG_FWU_NUM_IMAGES_PER_BANK;
for (int i = 0; i < num_images; i++)
- if (!strcmp(uuidbuf, fwu_mtd_images[i].uuidbuf))
- return &fwu_mtd_images[i];
+ if (!strcmp(uuidbuf, image_info[i].uuidbuf))
+ return &image_info[i];
return NULL;
}
@@ -107,7 +112,7 @@ __weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_id,
return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
}
-static int gen_image_alt_info(char *buf, size_t len, int sidx,
+static int gen_image_alt_info(char *buf, size_t len,
struct fwu_image_entry *img, struct mtd_info *mtd)
{
char *p = buf, *end = buf + len;
@@ -131,7 +136,7 @@ static int gen_image_alt_info(char *buf, size_t len, int sidx,
/* Query a partition by image UUID */
bank = &img->img_bank_info[i];
- uuid_bin_to_str(bank->image_uuid.b, uuidbuf, UUID_STR_FORMAT_STD);
+ uuid_bin_to_str(bank->image_guid.b, uuidbuf, UUID_STR_FORMAT_STD);
mtd_img_info = mtd_img_by_uuid(uuidbuf);
if (!mtd_img_info) {
@@ -158,18 +163,13 @@ static int gen_image_alt_info(char *buf, size_t len, int sidx,
int fwu_gen_alt_info_from_mtd(char *buf, size_t len, struct mtd_info *mtd)
{
- struct fwu_mdata mdata;
int i, l, ret;
-
- ret = fwu_get_mdata(&mdata);
- if (ret < 0) {
- log_err("Failed to get the FWU mdata.\n");
- return ret;
- }
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_image_entry *img_entry;
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
- ret = gen_image_alt_info(buf, len, i * CONFIG_FWU_NUM_BANKS,
- &mdata.img_entry[i], mtd);
+ img_entry = &data->fwu_images[i];
+ ret = gen_image_alt_info(buf, len, img_entry, mtd);
if (ret)
break;
diff --git a/lib/fwu_updates/fwu_v1.c b/lib/fwu_updates/fwu_v1.c
new file mode 100644
index 0000000000..efb8d51500
--- /dev/null
+++ b/lib/fwu_updates/fwu_v1.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#include <fwu.h>
+#include <fwu_mdata.h>
+
+#include <linux/types.h>
+
+#define FWU_MDATA_VERSION 0x1U
+
+static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank)
+{
+ u32 i;
+ struct fwu_image_entry *img_entry;
+ struct fwu_image_bank_info *img_bank_info;
+
+ img_entry = &mdata->img_entry[0];
+ for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
+ img_bank_info = &img_entry[i].img_bank_info[bank];
+ if (!img_bank_info->accepted) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void fwu_data_init(void)
+{
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ data->crc32 = mdata->crc32;
+ data->version = mdata->version;
+ data->active_index = mdata->active_index;
+ data->previous_active_index = mdata->previous_active_index;
+
+ data->metadata_size = sizeof(struct fwu_mdata);
+ data->num_banks = CONFIG_FWU_NUM_BANKS;
+ data->num_images = CONFIG_FWU_NUM_IMAGES_PER_BANK;
+ fwu_plat_get_bootidx(&data->boot_index);
+ data->trial_state = fwu_check_trial_state(mdata, data->boot_index);
+
+ src_img_info = &mdata->img_entry[0];
+ dst_img_info = &data->fwu_images[0];
+ image_info_size = sizeof(data->fwu_images);
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+static int fwu_trial_state_update(bool trial_state)
+{
+ int ret;
+ struct fwu_data *data = fwu_get_data();
+
+ if (trial_state) {
+ ret = fwu_trial_state_ctr_start();
+ if (ret)
+ return ret;
+ }
+
+ data->trial_state = trial_state;
+
+ return 0;
+}
+
+/**
+ * fwu_populate_mdata_image_info() - Populate the image information
+ * of the metadata
+ * @data: Version agnostic FWU metadata information
+ *
+ * Populate the image information in the FWU metadata by copying it
+ * from the version agnostic structure. This is done before the
+ * metadata gets written to the storage media.
+ *
+ * Return: None
+ */
+void fwu_populate_mdata_image_info(struct fwu_data *data)
+{
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ image_info_size = sizeof(data->fwu_images);
+ dst_img_info = &mdata->img_entry[0];
+ src_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+/**
+ * fwu_state_machine_updates() - Update FWU state of the platform
+ * @trial_state: Is platform transitioning into Trial State
+ * @update_index: Bank number to which images have been updated
+ *
+ * On successful completion of updates, transition the platform to
+ * either Trial State or Regular State.
+ *
+ * To transition the platform to Trial State, start the
+ * TrialStateCtr counter, followed by setting the value of bank_state
+ * field of the metadata to Valid state(applicable only in version 2
+ * of metadata).
+ *
+ * In case, the platform is to transition directly to Regular State,
+ * update the bank_state field of the metadata to Accepted
+ * state(applicable only in version 2 of metadata).
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_state_machine_updates(bool trial_state,
+ __maybe_unused uint32_t update_index)
+{
+ return fwu_trial_state_update(trial_state);
+}
+
+/**
+ * fwu_get_mdata_size() - Get the FWU metadata size
+ * @mdata_size: Size of the metadata structure
+ *
+ * Get the size of the FWU metadata.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_get_mdata_size(uint32_t *mdata_size)
+{
+ *mdata_size = sizeof(struct fwu_mdata);
+
+ return 0;
+}
+
+/**
+ * fwu_init() - FWU specific initialisations
+ *
+ * Carry out some FWU specific initialisations including allocation
+ * of memory for the metadata copies, and reading the FWU metadata
+ * copies into the allocated memory. The metadata fields are then
+ * copied into a version agnostic structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_init(void)
+{
+ int ret;
+ uint32_t mdata_size;
+
+ fwu_get_mdata_size(&mdata_size);
+
+ ret = fwu_mdata_copies_allocate(mdata_size);
+ if (ret)
+ return ret;
+
+ /*
+ * Now read the entire structure, both copies, and
+ * validate that the copies.
+ */
+ ret = fwu_get_mdata(NULL);
+ if (ret)
+ return ret;
+
+ fwu_data_init();
+
+ return 0;
+}
diff --git a/lib/fwu_updates/fwu_v2.c b/lib/fwu_updates/fwu_v2.c
new file mode 100644
index 0000000000..108bc9bb4a
--- /dev/null
+++ b/lib/fwu_updates/fwu_v2.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+
+#include <linux/types.h>
+
+#define FWU_MDATA_VERSION 0x2U
+
+static inline struct fwu_fw_store_desc *fwu_get_fw_desc(struct fwu_mdata *mdata)
+{
+ return (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata));
+}
+
+static uint32_t fwu_check_trial_state(struct fwu_mdata *mdata, uint32_t bank)
+{
+ return mdata->bank_state[bank] == FWU_BANK_VALID ? 1 : 0;
+}
+
+static void fwu_data_init(void)
+{
+ int i;
+ size_t image_info_size;
+ void *dst_img_info, *src_img_info;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ data->crc32 = mdata->crc32;
+ data->version = mdata->version;
+ data->active_index = mdata->active_index;
+ data->previous_active_index = mdata->previous_active_index;
+ data->metadata_size = mdata->metadata_size;
+ fwu_plat_get_bootidx(&data->boot_index);
+ data->trial_state = fwu_check_trial_state(mdata, data->boot_index);
+
+ data->num_banks = fwu_get_fw_desc(mdata)->num_banks;
+ data->num_images = fwu_get_fw_desc(mdata)->num_images;
+
+ for (i = 0; i < 4; i++) {
+ data->bank_state[i] = mdata->bank_state[i];
+ }
+
+ image_info_size = sizeof(data->fwu_images);
+ src_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
+ dst_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+static int fwu_mdata_sanity_checks(void)
+{
+ uint8_t num_banks;
+ uint16_t num_images;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ if (mdata->version != FWU_MDATA_VERSION) {
+ log_err("FWU metadata version %u. Expected value of %u\n",
+ mdata->version, FWU_MDATA_VERSION);
+ return -EINVAL;
+ }
+
+ if (!mdata->desc_offset) {
+ log_err("No image information provided with the Metadata. ");
+ log_err("Image information expected in the metadata\n");
+ return -EINVAL;
+ }
+
+ if (mdata->desc_offset != 0x20) {
+ log_err("Descriptor Offset(0x%x) in the FWU Metadata not equal to 0x20\n",
+ mdata->desc_offset);
+ return -EINVAL;
+ }
+
+ num_banks = fwu_get_fw_desc(mdata)->num_banks;
+ num_images = fwu_get_fw_desc(mdata)->num_images;
+
+ if (num_banks != CONFIG_FWU_NUM_BANKS) {
+ log_err("Number of Banks(%u) in FWU Metadata different from the configured value(%d)",
+ num_banks, CONFIG_FWU_NUM_BANKS);
+ return -EINVAL;
+ }
+
+ if (num_images != CONFIG_FWU_NUM_IMAGES_PER_BANK) {
+ log_err("Number of Images(%u) in FWU Metadata different from the configured value(%d)",
+ num_images, CONFIG_FWU_NUM_IMAGES_PER_BANK);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fwu_bank_state_update(bool trial_state, uint32_t bank)
+{
+ int ret;
+ struct fwu_data *data = fwu_get_data();
+ struct fwu_mdata *mdata = data->fwu_mdata;
+
+ mdata->bank_state[bank] = data->bank_state[bank] = trial_state ?
+ FWU_BANK_VALID : FWU_BANK_ACCEPTED;
+
+ ret = fwu_sync_mdata(mdata, BOTH_PARTS);
+ if (ret)
+ log_err("Unable to set bank_state for bank %u\n", bank);
+ else
+ data->trial_state = trial_state;
+
+ return ret;
+}
+
+static int fwu_trial_state_start(uint update_index)
+{
+ int ret;
+
+ ret = fwu_trial_state_ctr_start();
+ if (ret)
+ return ret;
+
+ ret = fwu_bank_state_update(1, update_index);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * fwu_populate_mdata_image_info() - Populate the image information
+ * of the metadata
+ * @data: Version agnostic FWU metadata information
+ *
+ * Populate the image information in the FWU metadata by copying it
+ * from the version agnostic structure. This is done before the
+ * metadata gets written to the storage media.
+ *
+ * Return: None
+ */
+void fwu_populate_mdata_image_info(struct fwu_data *data)
+{
+ size_t image_info_size;
+ struct fwu_mdata *mdata = data->fwu_mdata;
+ void *dst_img_info, *src_img_info;
+
+ image_info_size = sizeof(data->fwu_images);
+ dst_img_info = &fwu_get_fw_desc(mdata)->img_entry[0];
+ src_img_info = &data->fwu_images[0];
+
+ memcpy(dst_img_info, src_img_info, image_info_size);
+}
+
+/**
+ * fwu_state_machine_updates() - Update FWU state of the platform
+ * @trial_state: Is platform transitioning into Trial State
+ * @update_index: Bank number to which images have been updated
+ *
+ * On successful completion of updates, transition the platform to
+ * either Trial State or Regular State.
+ *
+ * To transition the platform to Trial State, start the
+ * TrialStateCtr counter, followed by setting the value of bank_state
+ * field of the metadata to Valid state(applicable only in version 2
+ * of metadata).
+ *
+ * In case, the platform is to transition directly to Regular State,
+ * update the bank_state field of the metadata to Accepted
+ * state(applicable only in version 2 of metadata).
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_state_machine_updates(bool trial_state, uint32_t update_index)
+{
+ return trial_state ? fwu_trial_state_start(update_index) :
+ fwu_bank_state_update(0, update_index);
+}
+
+/**
+ * fwu_get_mdata_size() - Get the FWU metadata size
+ * @mdata_size: Size of the metadata structure
+ *
+ * Get the size of the FWU metadata from the structure. This is later used
+ * to allocate memory for the structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_get_mdata_size(uint32_t *mdata_size)
+{
+ int ret = 0;
+ struct fwu_mdata mdata = { 0 };
+ struct fwu_data *data = fwu_get_data();
+ struct udevice *fwu_dev = fwu_get_dev();
+
+ if (data->metadata_size) {
+ *mdata_size = data->metadata_size;
+ return 0;
+ }
+
+ ret = fwu_read_mdata(fwu_dev, &mdata, 1,
+ sizeof(struct fwu_mdata));
+ if (ret) {
+ log_err("FWU metadata read failed\n");
+ return ret;
+ }
+
+ *mdata_size = mdata.metadata_size;
+ if (!*mdata_size)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * fwu_init() - FWU specific initialisations
+ *
+ * Carry out some FWU specific initialisations including allocation
+ * of memory for the metadata copies, and reading the FWU metadata
+ * copies into the allocated memory. The metadata fields are then
+ * copied into a version agnostic structure.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int fwu_init(void)
+{
+ int ret;
+ struct fwu_mdata mdata = { 0 };
+ struct udevice *fwu_dev = fwu_get_dev();
+
+ /*
+ * First we read only the top level structure
+ * and get the size of the complete structure.
+ */
+ ret = fwu_read_mdata(fwu_dev, &mdata, 1,
+ sizeof(struct fwu_mdata));
+ if (ret) {
+ log_err("FWU metadata read failed\n");
+ return ret;
+ }
+
+ ret = fwu_mdata_copies_allocate(mdata.metadata_size);
+ if (ret)
+ return ret;
+
+ /*
+ * Now read the entire structure, both copies, and
+ * validate that the copies.
+ */
+ ret = fwu_get_mdata(NULL);
+ if (ret)
+ return ret;
+
+ ret = fwu_mdata_sanity_checks();
+ if (ret)
+ return ret;
+
+ fwu_data_init();
+
+ return 0;
+}
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 33e3e6e518..2bc508ff50 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -10,7 +10,7 @@
#include <hexdump.h>
#include <mapmem.h>
-#include <vsprintf.h>
+#include <stdio.h>
#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/log2.h>
diff --git a/lib/md5.c b/lib/md5.c
index faf3f78ab1..34343cf8e2 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -55,7 +55,7 @@ byteReverse(unsigned char *buf, unsigned longs)
* initialization constants.
*/
void
-MD5Init(struct MD5Context *ctx)
+MD5Init(MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
@@ -71,7 +71,7 @@ MD5Init(struct MD5Context *ctx)
* of bytes.
*/
void
-MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+MD5Update(MD5Context *ctx, unsigned char const *buf, unsigned int len)
{
register __u32 t;
@@ -120,7 +120,7 @@ MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
-MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+MD5Final(unsigned char digest[16], MD5Context *ctx)
{
unsigned int count;
unsigned char *p;
@@ -269,7 +269,7 @@ MD5Transform(__u32 buf[4], __u32 const in[16])
void
md5 (unsigned char *input, int len, unsigned char output[16])
{
- struct MD5Context context;
+ MD5Context context;
MD5Init(&context);
MD5Update(&context, input, len);
@@ -286,7 +286,7 @@ void
md5_wd(const unsigned char *input, unsigned int len, unsigned char output[16],
unsigned int chunk_sz)
{
- struct MD5Context context;
+ MD5Context context;
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
const unsigned char *end, *curr;
int chunk;
diff --git a/lib/smbios.c b/lib/smbios.c
index b190b010f3..fb6eaf1d5c 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -383,8 +383,12 @@ static int smbios_write_type1(ulong *current, int handle,
memset(t, 0, sizeof(struct smbios_type1));
fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle);
smbios_set_eos(ctx, t->eos);
- t->manufacturer = smbios_add_prop(ctx, "manufacturer", NULL);
- t->product_name = smbios_add_prop(ctx, "product", NULL);
+ t->manufacturer = smbios_add_prop_si(ctx, "manufacturer",
+ SYSINFO_ID_SMBIOS_SYSTEM_MANUFACTURER,
+ NULL);
+ t->product_name = smbios_add_prop_si(ctx, "product",
+ SYSINFO_ID_SMBIOS_SYSTEM_PRODUCT,
+ NULL);
t->version = smbios_add_prop_si(ctx, "version",
SYSINFO_ID_SMBIOS_SYSTEM_VERSION,
NULL);
@@ -392,11 +396,15 @@ static int smbios_write_type1(ulong *current, int handle,
t->serial_number = smbios_add_prop(ctx, NULL, serial_str);
strncpy((char *)t->uuid, serial_str, sizeof(t->uuid));
} else {
- t->serial_number = smbios_add_prop(ctx, "serial", NULL);
+ t->serial_number = smbios_add_prop_si(ctx, "serial",
+ SYSINFO_ID_SMBIOS_SYSTEM_SERIAL,
+ NULL);
}
t->wakeup_type = SMBIOS_WAKEUP_TYPE_UNKNOWN;
- t->sku_number = smbios_add_prop(ctx, "sku", NULL);
- t->family = smbios_add_prop(ctx, "family", NULL);
+ t->sku_number = smbios_add_prop_si(ctx, "sku",
+ SYSINFO_ID_SMBIOS_SYSTEM_SKU, NULL);
+ t->family = smbios_add_prop_si(ctx, "family",
+ SYSINFO_ID_SMBIOS_SYSTEM_FAMILY, NULL);
len = t->length + smbios_string_table_len(ctx);
*current += len;
@@ -415,12 +423,22 @@ static int smbios_write_type2(ulong *current, int handle,
memset(t, 0, sizeof(struct smbios_type2));
fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle);
smbios_set_eos(ctx, t->eos);
- t->manufacturer = smbios_add_prop(ctx, "manufacturer", NULL);
- t->product_name = smbios_add_prop(ctx, "product", NULL);
+ t->manufacturer = smbios_add_prop_si(ctx, "manufacturer",
+ SYSINFO_ID_SMBIOS_BASEBOARD_MANUFACTURER,
+ NULL);
+ t->product_name = smbios_add_prop_si(ctx, "product",
+ SYSINFO_ID_SMBIOS_BASEBOARD_PRODUCT,
+ NULL);
t->version = smbios_add_prop_si(ctx, "version",
SYSINFO_ID_SMBIOS_BASEBOARD_VERSION,
NULL);
- t->asset_tag_number = smbios_add_prop(ctx, "asset-tag", NULL);
+
+ t->serial_number = smbios_add_prop_si(ctx, "serial",
+ SYSINFO_ID_SMBIOS_BASEBOARD_SERIAL,
+ NULL);
+ t->asset_tag_number = smbios_add_prop_si(ctx, "asset-tag",
+ SYSINFO_ID_SMBIOS_BASEBOARD_ASSET_TAG,
+ NULL);
t->feature_flags = SMBIOS_BOARD_FEATURE_HOSTING;
t->board_type = SMBIOS_BOARD_MOTHERBOARD;
t->chassis_handle = handle + 1;
@@ -571,10 +589,16 @@ ulong write_smbios_table(ulong addr)
int i;
ctx.node = ofnode_null();
- if (IS_ENABLED(CONFIG_OF_CONTROL)) {
+ if (IS_ENABLED(CONFIG_OF_CONTROL) && CONFIG_IS_ENABLED(SYSINFO)) {
uclass_first_device(UCLASS_SYSINFO, &ctx.dev);
- if (ctx.dev)
+ if (ctx.dev) {
+ int ret;
+
parent_node = dev_read_subnode(ctx.dev, "smbios");
+ ret = sysinfo_detect(ctx.dev);
+ if (ret)
+ return ret;
+ }
} else {
ctx.dev = NULL;
}
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 91526af33a..59e6cbafaf 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -10,6 +10,7 @@
#include <tpm_api.h>
#include <tpm-common.h>
#include <tpm-v2.h>
+#include <tpm_tcg2.h>
#include <u-boot/sha1.h>
#include <u-boot/sha256.h>
#include <u-boot/sha512.h>
@@ -22,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] = {
@@ -857,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
@@ -1056,48 +400,25 @@ 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
+ * 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) {
- printf("%s: too many pcrs: %u\n", __func__, pcrs.count);
+ if (pcrs->count > 4 || pcrs->count < 1) {
+ printf("%s: too many pcrs: %u\n", __func__, pcrs->count);
return -EMSGSIZE;
}
@@ -1105,7 +426,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
@@ -1125,35 +446,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 = tpm2_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;
}
@@ -1541,6 +847,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;
@@ -1566,14 +884,33 @@ const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
return "";
}
-u32 tpm2_algorithm_to_mask(enum tpm2_algorithms algo)
+u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo)
{
size_t i;
- for (i = 0; i < ARRAY_SIZE(hash_algo_list); 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 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;
+}
diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c
new file mode 100644
index 0000000000..7f868cc883
--- /dev/null
+++ b/lib/tpm_tcg2.c
@@ -0,0 +1,731 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Linaro Limited
+ */
+
+#include <dm.h>
+#include <dm/of_access.h>
+#include <tpm_api.h>
+#include <tpm-common.h>
+#include <tpm-v2.h>
+#include <tpm_tcg2.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
+#include <version_string.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
+#include <linux/unaligned/le_byteshift.h>
+#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;
+ u32 pcr_banks = 0;
+ u32 active = 0;
+ int rc;
+
+ rc = tcg2_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) {}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 27ea9c907a..cfd1f1914e 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -19,6 +19,7 @@
#include <hexdump.h>
#include <stdarg.h>
#include <uuid.h>
+#include <stdio.h>
#include <vsprintf.h>
#include <linux/ctype.h>
#include <linux/err.h>