aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig12
-rw-r--r--lib/acpi/acpi_table.c15
-rw-r--r--lib/ecdsa/ecdsa-libcrypto.c16
-rw-r--r--lib/efi_driver/efi_block_device.c6
-rw-r--r--lib/efi_driver/efi_uclass.c12
-rw-r--r--lib/efi_loader/Kconfig44
-rw-r--r--lib/efi_loader/Makefile3
-rw-r--r--lib/efi_loader/efi_acpi.c33
-rw-r--r--lib/efi_loader/efi_bootmgr.c385
-rw-r--r--lib/efi_loader/efi_boottime.c76
-rw-r--r--lib/efi_loader/efi_capsule.c20
-rw-r--r--lib/efi_loader/efi_device_path.c203
-rw-r--r--lib/efi_loader/efi_disk.c22
-rw-r--r--lib/efi_loader/efi_file.c14
-rw-r--r--lib/efi_loader/efi_firmware.c280
-rw-r--r--lib/efi_loader/efi_helper.c25
-rw-r--r--lib/efi_loader/efi_image_loader.c5
-rw-r--r--lib/efi_loader/efi_load_options.c2
-rw-r--r--lib/efi_loader/efi_memory.c19
-rw-r--r--lib/efi_loader/efi_tcg2.c14
-rw-r--r--lib/efi_loader/efi_var_mem.c4
-rw-r--r--lib/efi_loader/efi_variable_tee.c270
-rw-r--r--lib/efi_selftest/efi_selftest_controllers.c44
-rw-r--r--lib/efi_selftest/efi_selftest_hii.c11
-rw-r--r--lib/fwu_updates/Makefile1
-rw-r--r--lib/fwu_updates/fwu.c322
-rw-r--r--lib/fwu_updates/fwu_mtd.c187
-rw-r--r--lib/image-sparse.c3
-rw-r--r--lib/lzma/LzmaDec.c18
-rw-r--r--lib/of_live.c11
-rw-r--r--lib/uuid.c50
-rw-r--r--lib/vsprintf.c5
-rw-r--r--lib/zlib/inflate.c5
33 files changed, 1648 insertions, 489 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index c8b3ec1ec9..07e61de5b6 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -508,6 +508,7 @@ config SHA256
config SHA512
bool "Enable SHA512 support"
+ default y if TI_SECURE_DEVICE && FIT_SIGNATURE
help
This option enables support of hashing using SHA512 algorithm.
The hash is calculated in software.
@@ -533,6 +534,17 @@ config SHA_HW_ACCEL
if SPL
+config SPL_CRC32
+ bool "Enable CRC32 support in SPL"
+ default y if SPL_LEGACY_IMAGE_SUPPORT || SPL_EFI_PARTITION
+ default y if SPL_ENV_SUPPORT || TPL_BLOBLIST
+ help
+ This option enables support of hashing using CRC32 algorithm.
+ The CRC32 algorithm produces 32-bit checksum value. For FIT
+ images, this is the least secure type of checksum, suitable for
+ detected accidental image corruption. For secure applications you
+ should consider SHA256 or SHA384.
+
config SPL_SHA1
bool "Enable SHA1 support in SPL"
default y if SHA1
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c
index 7c4189e243..a8d4b47000 100644
--- a/lib/acpi/acpi_table.c
+++ b/lib/acpi/acpi_table.c
@@ -11,8 +11,7 @@
#include <log.h>
#include <mapmem.h>
#include <tables_csum.h>
-#include <timestamp.h>
-#include <version.h>
+#include <version_string.h>
#include <acpi/acpi_table.h>
#include <asm/global_data.h>
#include <dm/acpi.h>
@@ -25,12 +24,12 @@
* to have valid date. So for U-Boot version 2021.04 OEM_REVISION is set to
* value 0x20210401.
*/
-#define OEM_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 28) | \
- (((U_BOOT_VERSION_NUM / 100) % 10) << 24) | \
- (((U_BOOT_VERSION_NUM / 10) % 10) << 20) | \
- ((U_BOOT_VERSION_NUM % 10) << 16) | \
- (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 12) | \
- ((U_BOOT_VERSION_NUM_PATCH % 10) << 8) | \
+#define OEM_REVISION ((((version_num / 1000) % 10) << 28) | \
+ (((version_num / 100) % 10) << 24) | \
+ (((version_num / 10) % 10) << 20) | \
+ ((version_num % 10) << 16) | \
+ (((version_num_patch / 10) % 10) << 12) | \
+ ((version_num_patch % 10) << 8) | \
0x01)
int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
index d5939af2c5..5fa9be10b4 100644
--- a/lib/ecdsa/ecdsa-libcrypto.c
+++ b/lib/ecdsa/ecdsa-libcrypto.c
@@ -111,16 +111,30 @@ static size_t ecdsa_key_size_bytes(const EC_KEY *key)
return EC_GROUP_order_bits(group) / 8;
}
+static int default_password(char *buf, int size, int rwflag, void *u)
+{
+ strncpy(buf, (char *)u, size);
+ buf[size - 1] = '\0';
+ return strlen(buf);
+}
+
static int read_key(struct signer *ctx, const char *key_name)
{
FILE *f = fopen(key_name, "r");
+ const char *key_pass;
if (!f) {
fprintf(stderr, "Can not get key file '%s'\n", key_name);
return -ENOENT;
}
- ctx->evp_key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ key_pass = getenv("MKIMAGE_SIGN_PASSWORD");
+ if (key_pass) {
+ ctx->evp_key = PEM_read_PrivateKey(f, NULL, default_password, (void *)key_pass);
+
+ } else {
+ ctx->evp_key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ }
fclose(f);
if (!ctx->evp_key) {
fprintf(stderr, "Can not read key from '%s'\n", key_name);
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index add00eeebb..e3abd90275 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -124,10 +124,8 @@ efi_bl_create_block_device(efi_handle_t handle, void *interface)
struct efi_block_io *io = interface;
struct efi_blk_plat *plat;
- devnum = blk_find_max_devnum(UCLASS_EFI_LOADER);
- if (devnum == -ENODEV)
- devnum = 0;
- else if (devnum < 0)
+ devnum = blk_next_free_devnum(UCLASS_EFI_LOADER);
+ if (devnum < 0)
return EFI_OUT_OF_RESOURCES;
name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */
diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
index 45f9351988..66a45e156d 100644
--- a/lib/efi_driver/efi_uclass.c
+++ b/lib/efi_driver/efi_uclass.c
@@ -285,10 +285,8 @@ static efi_status_t efi_add_driver(struct driver *drv)
bp->ops = ops;
ret = efi_create_handle(&bp->bp.driver_binding_handle);
- if (ret != EFI_SUCCESS) {
- free(bp);
- goto out;
- }
+ if (ret != EFI_SUCCESS)
+ goto err;
bp->bp.image_handle = bp->bp.driver_binding_handle;
ret = efi_add_protocol(bp->bp.driver_binding_handle,
&efi_guid_driver_binding_protocol, bp);
@@ -299,11 +297,11 @@ static efi_status_t efi_add_driver(struct driver *drv)
if (ret != EFI_SUCCESS)
goto err;
}
-out:
- return ret;
+ return ret;
err:
- efi_delete_handle(bp->bp.driver_binding_handle);
+ if (bp->bp.driver_binding_handle)
+ efi_delete_handle(bp->bp.driver_binding_handle);
free(bp);
return ret;
}
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index c5835e6ef6..9989e3f384 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -55,13 +55,50 @@ config EFI_VARIABLE_FILE_STORE
stored as file /ubootefi.var on the EFI system partition.
config EFI_MM_COMM_TEE
- bool "UEFI variables storage service via OP-TEE"
+ bool "UEFI variables storage service via the trusted world"
depends on OPTEE
help
+ Allowing access to the MM SP services (SPs such as StandAlonneMM, smm-gateway).
+ When using the u-boot OP-TEE driver, StandAlonneMM is supported.
+ When using the u-boot FF-A driver any MM SP is supported.
+
If OP-TEE is present and running StandAloneMM, dispatch all UEFI
variable related operations to that. The application will verify,
authenticate and store the variables on an RPMB.
+ When ARM_FFA_TRANSPORT is used, dispatch all UEFI variable related
+ operations to the MM SP running in the secure world.
+ A door bell mechanism is used to notify the SP when there is data in the shared
+ MM buffer. The data is copied by u-boot to the shared buffer before issuing
+ the door bell event.
+
+config FFA_SHARED_MM_BUF_SIZE
+ int "Memory size of the shared MM communication buffer"
+ depends on EFI_MM_COMM_TEE && ARM_FFA_TRANSPORT
+ help
+ This defines the size in bytes of the memory area reserved for the shared
+ buffer used for communication between the MM feature in U-Boot and
+ the MM SP in secure world.
+ The size of the memory region must be a multiple of the size of the maximum
+ translation granule size that is specified in the ID_AA64MMFR0_EL1 System register.
+ It is assumed that the MM SP knows the size of the shared MM communication buffer.
+
+config FFA_SHARED_MM_BUF_OFFSET
+ int "Data offset in the shared MM communication buffer"
+ depends on EFI_MM_COMM_TEE && ARM_FFA_TRANSPORT
+ help
+ This defines the offset in bytes of the data read or written to in the shared
+ buffer by the MM SP.
+
+config FFA_SHARED_MM_BUF_ADDR
+ hex "Define the address of the shared MM communication buffer"
+ depends on EFI_MM_COMM_TEE && ARM_FFA_TRANSPORT
+ help
+ This defines the address of the shared MM communication buffer
+ used for communication between the MM feature in U-Boot and
+ the MM SP in secure world.
+ It is assumed that the MM SP knows the address of the shared MM communication buffer.
+
config EFI_VARIABLE_NO_STORE
bool "Don't persist non-volatile UEFI variables"
help
@@ -96,7 +133,8 @@ endif
config EFI_VAR_BUF_SIZE
int "Memory size of the UEFI variable store"
- default 16384
+ default 16384 if EFI_MM_COMM_TEE
+ default 65536
range 4096 2147483647
help
This defines the size in bytes of the memory area reserved for keeping
@@ -106,7 +144,7 @@ config EFI_VAR_BUF_SIZE
match the value of PcdFlashNvStorageVariableSize used to compile the
StandAloneMM module.
- Minimum 4096, default 16384.
+ Minimum 4096, default 65536, or 16384 when using StandAloneMM.
config EFI_GET_TIME
bool "GetTime() runtime service"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 13a35eae6c..1a8c8d7cab 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -23,6 +23,7 @@ CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI)
ifdef CONFIG_RISCV
always += boothart.efi
+targets += boothart.o
endif
ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),)
@@ -32,10 +33,12 @@ endif
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
always += dtbdump.efi
+targets += dtbdump.o
endif
ifdef CONFIG_EFI_LOAD_FILE2_INITRD
always += initrddump.efi
+targets += initrddump.o
endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c
index 2ddc3502b5..f755af76f8 100644
--- a/lib/efi_loader/efi_acpi.c
+++ b/lib/efi_loader/efi_acpi.c
@@ -10,6 +10,9 @@
#include <log.h>
#include <mapmem.h>
#include <acpi/acpi_table.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
@@ -20,26 +23,28 @@ static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
*/
efi_status_t efi_acpi_register(void)
{
- /* Map within the low 32 bits, to allow for 32bit ACPI tables */
- u64 acpi = U32_MAX;
+ ulong addr, start, end;
efi_status_t ret;
- ulong addr;
- /* Reserve 64kiB page for ACPI */
- ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
- EFI_ACPI_RECLAIM_MEMORY, 16, &acpi);
+ /* Mark space used for tables */
+ start = ALIGN_DOWN(gd->arch.table_start, EFI_PAGE_MASK);
+ end = ALIGN(gd->arch.table_end, EFI_PAGE_MASK);
+ ret = efi_add_memory_map(start, end - start, EFI_ACPI_RECLAIM_MEMORY);
if (ret != EFI_SUCCESS)
return ret;
+ if (gd->arch.table_start_high) {
+ start = ALIGN_DOWN(gd->arch.table_start_high, EFI_PAGE_MASK);
+ end = ALIGN(gd->arch.table_end_high, EFI_PAGE_MASK);
+ ret = efi_add_memory_map(start, end - start,
+ EFI_ACPI_RECLAIM_MEMORY);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ }
- /*
- * Generate ACPI tables - we know that efi_allocate_pages() returns
- * a 4k-aligned address, so it is safe to assume that
- * write_acpi_tables() will write the table at that address.
- */
- addr = map_to_sysmem((void *)(ulong)acpi);
- write_acpi_tables(addr);
+ addr = gd_acpi_start();
+ printf("EFI using ACPI tables at %lx\n", addr);
/* And expose them to our EFI payload */
return efi_install_configuration_table(&acpi_guid,
- (void *)(uintptr_t)acpi);
+ (void *)(ulong)addr);
}
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 7ac5f89f76..a40762c74c 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -344,3 +344,388 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle, void **load_options)
error:
return ret;
}
+
+/**
+ * efi_bootmgr_enumerate_boot_option() - enumerate the possible bootable media
+ *
+ * @opt: pointer to the media boot option structure
+ * @volume_handles: pointer to the efi handles
+ * @count: number of efi handle
+ * Return: status code
+ */
+static efi_status_t efi_bootmgr_enumerate_boot_option(struct eficonfig_media_boot_option *opt,
+ efi_handle_t *volume_handles,
+ efi_status_t count)
+{
+ u32 i;
+ struct efi_handler *handler;
+ efi_status_t ret = EFI_SUCCESS;
+
+ for (i = 0; i < count; i++) {
+ u16 *p;
+ u16 dev_name[BOOTMENU_DEVICE_NAME_MAX];
+ char *optional_data;
+ struct efi_load_option lo;
+ char buf[BOOTMENU_DEVICE_NAME_MAX];
+ struct efi_device_path *device_path;
+ struct efi_device_path *short_dp;
+
+ ret = efi_search_protocol(volume_handles[i], &efi_guid_device_path, &handler);
+ if (ret != EFI_SUCCESS)
+ continue;
+ ret = efi_protocol_open(handler, (void **)&device_path,
+ efi_root, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS)
+ continue;
+
+ ret = efi_disk_get_device_name(volume_handles[i], buf, BOOTMENU_DEVICE_NAME_MAX);
+ if (ret != EFI_SUCCESS)
+ continue;
+
+ p = dev_name;
+ utf8_utf16_strncpy(&p, buf, strlen(buf));
+
+ /* prefer to short form device path */
+ short_dp = efi_dp_shorten(device_path);
+ if (short_dp)
+ device_path = short_dp;
+
+ lo.label = dev_name;
+ lo.attributes = LOAD_OPTION_ACTIVE;
+ lo.file_path = device_path;
+ lo.file_path_length = efi_dp_size(device_path) + sizeof(END);
+ /*
+ * Set the dedicated guid to optional_data, it is used to identify
+ * the boot option that automatically generated by the bootmenu.
+ * efi_serialize_load_option() expects optional_data is null-terminated
+ * utf8 string, so set the "1234567" string to allocate enough space
+ * to store guid, instead of realloc the load_option.
+ */
+ lo.optional_data = "1234567";
+ opt[i].size = efi_serialize_load_option(&lo, (u8 **)&opt[i].lo);
+ if (!opt[i].size) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ /* set the guid */
+ optional_data = (char *)opt[i].lo + (opt[i].size - u16_strsize(u"1234567"));
+ memcpy(optional_data, &efi_guid_bootmenu_auto_generated, sizeof(efi_guid_t));
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * efi_bootmgr_delete_invalid_boot_option() - delete non-existing boot option
+ *
+ * @opt: pointer to the media boot option structure
+ * @count: number of media boot option structure
+ * Return: status code
+ */
+static efi_status_t efi_bootmgr_delete_invalid_boot_option(struct eficonfig_media_boot_option *opt,
+ efi_status_t count)
+{
+ efi_uintn_t size;
+ void *load_option;
+ u32 i, list_size = 0;
+ struct efi_load_option lo;
+ u16 *var_name16 = NULL;
+ u16 varname[] = u"Boot####";
+ efi_status_t ret = EFI_SUCCESS;
+ u16 *delete_index_list = NULL, *p;
+ efi_uintn_t buf_size;
+
+ buf_size = 128;
+ var_name16 = malloc(buf_size);
+ if (!var_name16)
+ return EFI_OUT_OF_RESOURCES;
+
+ var_name16[0] = 0;
+ for (;;) {
+ int index;
+ efi_guid_t guid;
+ efi_uintn_t tmp;
+
+ ret = efi_next_variable_name(&buf_size, &var_name16, &guid);
+ if (ret == EFI_NOT_FOUND) {
+ /*
+ * EFI_NOT_FOUND indicates we retrieved all EFI variables.
+ * This should be treated as success.
+ */
+ ret = EFI_SUCCESS;
+ break;
+ }
+
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ if (!efi_varname_is_load_option(var_name16, &index))
+ continue;
+
+ efi_create_indexed_name(varname, sizeof(varname), "Boot", index);
+ load_option = efi_get_var(varname, &efi_global_variable_guid, &size);
+ if (!load_option)
+ continue;
+
+ tmp = size;
+ ret = efi_deserialize_load_option(&lo, load_option, &size);
+ if (ret != EFI_SUCCESS)
+ goto next;
+
+ if (size >= sizeof(efi_guid_bootmenu_auto_generated) &&
+ !guidcmp(lo.optional_data, &efi_guid_bootmenu_auto_generated)) {
+ for (i = 0; i < count; i++) {
+ if (opt[i].size == tmp &&
+ memcmp(opt[i].lo, load_option, tmp) == 0) {
+ opt[i].exist = true;
+ break;
+ }
+ }
+
+ /*
+ * The entire list of variables must be retrieved by
+ * efi_get_next_variable_name_int() before deleting the invalid
+ * boot option, just save the index here.
+ */
+ if (i == count) {
+ p = realloc(delete_index_list, sizeof(u32) *
+ (list_size + 1));
+ if (!p) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ delete_index_list = p;
+ delete_index_list[list_size++] = index;
+ }
+ }
+next:
+ free(load_option);
+ }
+
+ /* delete all invalid boot options */
+ for (i = 0; i < list_size; i++) {
+ ret = efi_bootmgr_delete_boot_option(delete_index_list[i]);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
+out:
+ free(var_name16);
+ free(delete_index_list);
+
+ return ret;
+}
+
+/**
+ * efi_bootmgr_get_unused_bootoption() - get unused "Boot####" index
+ *
+ * @buf: pointer to the buffer to store boot option variable name
+ * @buf_size: buffer size
+ * @index: pointer to store the index in the BootOrder variable
+ * Return: status code
+ */
+efi_status_t efi_bootmgr_get_unused_bootoption(u16 *buf, efi_uintn_t buf_size,
+ unsigned int *index)
+{
+ u32 i;
+ efi_status_t ret;
+ efi_uintn_t size;
+
+ if (buf_size < u16_strsize(u"Boot####"))
+ return EFI_BUFFER_TOO_SMALL;
+
+ for (i = 0; i <= 0xFFFF; i++) {
+ size = 0;
+ efi_create_indexed_name(buf, buf_size, "Boot", i);
+ ret = efi_get_variable_int(buf, &efi_global_variable_guid,
+ NULL, &size, NULL, NULL);
+ if (ret == EFI_BUFFER_TOO_SMALL)
+ continue;
+ else
+ break;
+ }
+
+ if (i > 0xFFFF)
+ return EFI_OUT_OF_RESOURCES;
+
+ *index = i;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_bootmgr_append_bootorder() - append new boot option in BootOrder variable
+ *
+ * @index: "Boot####" index to append to BootOrder variable
+ * Return: status code
+ */
+efi_status_t efi_bootmgr_append_bootorder(u16 index)
+{
+ u16 *bootorder;
+ efi_status_t ret;
+ u16 *new_bootorder = NULL;
+ efi_uintn_t last, size, new_size;
+
+ /* append new boot option */
+ bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+ last = size / sizeof(u16);
+ new_size = size + sizeof(u16);
+ new_bootorder = calloc(1, new_size);
+ if (!new_bootorder) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ memcpy(new_bootorder, bootorder, size);
+ new_bootorder[last] = index;
+
+ ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ new_size, new_bootorder, false);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+out:
+ free(bootorder);
+ free(new_bootorder);
+
+ return ret;
+}
+
+/**
+ * efi_bootmgr_delete_boot_option() - delete selected boot option
+ *
+ * @boot_index: boot option index to delete
+ * Return: status code
+ */
+efi_status_t efi_bootmgr_delete_boot_option(u16 boot_index)
+{
+ u16 *bootorder;
+ u16 varname[9];
+ efi_status_t ret;
+ unsigned int index;
+ efi_uintn_t num, size;
+
+ efi_create_indexed_name(varname, sizeof(varname),
+ "Boot", boot_index);
+ ret = efi_set_variable_int(varname, &efi_global_variable_guid,
+ 0, 0, NULL, false);
+ if (ret != EFI_SUCCESS) {
+ log_err("delete boot option(%ls) failed\n", varname);
+ return ret;
+ }
+
+ /* update BootOrder if necessary */
+ bootorder = efi_get_var(u"BootOrder", &efi_global_variable_guid, &size);
+ if (!bootorder)
+ return EFI_SUCCESS;
+
+ num = size / sizeof(u16);
+ if (!efi_search_bootorder(bootorder, num, boot_index, &index))
+ return EFI_SUCCESS;
+
+ memmove(&bootorder[index], &bootorder[index + 1],
+ (num - index - 1) * sizeof(u16));
+ size -= sizeof(u16);
+ ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ size, bootorder, false);
+
+ return ret;
+}
+
+/**
+ * efi_bootmgr_update_media_device_boot_option() - generate the media device boot option
+ *
+ * This function enumerates all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
+ * and generate the bootmenu entries.
+ * This function also provide the BOOT#### variable maintenance for
+ * the media device entries.
+ * - Automatically create the BOOT#### variable for the newly detected device,
+ * this BOOT#### variable is distinguished by the special GUID
+ * stored in the EFI_LOAD_OPTION.optional_data
+ * - If the device is not attached to the system, the associated BOOT#### variable
+ * is automatically deleted.
+ *
+ * Return: status code
+ */
+efi_status_t efi_bootmgr_update_media_device_boot_option(void)
+{
+ u32 i;
+ efi_status_t ret;
+ efi_uintn_t count;
+ efi_handle_t *volume_handles = NULL;
+ struct eficonfig_media_boot_option *opt = NULL;
+
+ ret = efi_locate_handle_buffer_int(BY_PROTOCOL,
+ &efi_simple_file_system_protocol_guid,
+ NULL, &count,
+ (efi_handle_t **)&volume_handles);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ opt = calloc(count, sizeof(struct eficonfig_media_boot_option));
+ if (!opt) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ /* enumerate all devices supporting EFI_SIMPLE_FILE_SYSTEM_PROTOCOL */
+ ret = efi_bootmgr_enumerate_boot_option(opt, volume_handles, count);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * System hardware configuration may vary depending on the user setup.
+ * The boot option is automatically added by the bootmenu.
+ * If the device is not attached to the system, the boot option needs
+ * to be deleted.
+ */
+ ret = efi_bootmgr_delete_invalid_boot_option(opt, count);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /* add non-existent boot option */
+ for (i = 0; i < count; i++) {
+ u32 boot_index;
+ u16 var_name[9];
+
+ if (!opt[i].exist) {
+ ret = efi_bootmgr_get_unused_bootoption(var_name, sizeof(var_name),
+ &boot_index);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = efi_set_variable_int(var_name, &efi_global_variable_guid,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ opt[i].size, opt[i].lo, false);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = efi_bootmgr_append_bootorder(boot_index);
+ if (ret != EFI_SUCCESS) {
+ efi_set_variable_int(var_name, &efi_global_variable_guid,
+ 0, 0, NULL, false);
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (opt) {
+ for (i = 0; i < count; i++)
+ free(opt[i].lo);
+ }
+ free(opt);
+ efi_free_pool(volume_handles);
+
+ if (ret == EFI_NOT_FOUND)
+ return EFI_SUCCESS;
+ return ret;
+}
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index d5065f296a..0e89c8505b 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -59,6 +59,10 @@ static efi_handle_t current_image;
static volatile gd_t *efi_gd, *app_gd;
#endif
+static efi_status_t efi_uninstall_protocol
+ (efi_handle_t handle, const efi_guid_t *protocol,
+ void *protocol_interface);
+
/* 1 if inside U-Boot code, 0 if inside EFI payload code */
static int entry_count = 1;
static int nesting_level;
@@ -97,6 +101,12 @@ static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t driver_image_handle,
efi_handle_t child_handle);
+static
+efi_status_t EFIAPI efi_connect_controller(efi_handle_t controller_handle,
+ efi_handle_t *driver_image_handle,
+ struct efi_device_path *remain_device_path,
+ bool recursive);
+
/* Called on every callback entry */
int __efi_entry_check(void)
{
@@ -569,9 +579,9 @@ efi_status_t efi_search_protocol(const efi_handle_t handle,
*
* Return: status code
*/
-efi_status_t efi_remove_protocol(const efi_handle_t handle,
- const efi_guid_t *protocol,
- void *protocol_interface)
+static efi_status_t efi_remove_protocol(const efi_handle_t handle,
+ const efi_guid_t *protocol,
+ void *protocol_interface)
{
struct efi_handler *handler;
efi_status_t ret;
@@ -604,8 +614,8 @@ static efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) {
efi_status_t ret;
- ret = efi_remove_protocol(handle, &protocol->guid,
- protocol->protocol_interface);
+ ret = efi_uninstall_protocol(handle, &protocol->guid,
+ protocol->protocol_interface);
if (ret != EFI_SUCCESS)
return ret;
}
@@ -616,19 +626,23 @@ static efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
* efi_delete_handle() - delete handle
*
* @handle: handle to delete
+ *
+ * Return: status code
*/
-void efi_delete_handle(efi_handle_t handle)
+efi_status_t efi_delete_handle(efi_handle_t handle)
{
efi_status_t ret;
ret = efi_remove_all_protocols(handle);
- if (ret == EFI_INVALID_PARAMETER) {
- log_err("Can't remove invalid handle %p\n", handle);
- return;
+ if (ret != EFI_SUCCESS) {
+ log_err("Handle %p has protocols installed. Unable to delete\n", handle);
+ return ret;
}
list_del(&handle->link);
free(handle);
+
+ return ret;
}
/**
@@ -1298,7 +1312,7 @@ static efi_status_t efi_disconnect_all_drivers
const efi_guid_t *protocol,
efi_handle_t child_handle)
{
- efi_uintn_t number_of_drivers;
+ efi_uintn_t number_of_drivers, tmp;
efi_handle_t *driver_handle_buffer;
efi_status_t r, ret;
@@ -1308,15 +1322,30 @@ static efi_status_t efi_disconnect_all_drivers
return ret;
if (!number_of_drivers)
return EFI_SUCCESS;
- ret = EFI_NOT_FOUND;
+
+ tmp = number_of_drivers;
while (number_of_drivers) {
- r = EFI_CALL(efi_disconnect_controller(
+ ret = EFI_CALL(efi_disconnect_controller(
handle,
driver_handle_buffer[--number_of_drivers],
child_handle));
- if (r == EFI_SUCCESS)
- ret = r;
+ if (ret != EFI_SUCCESS)
+ goto reconnect;
}
+
+ free(driver_handle_buffer);
+ return ret;
+
+reconnect:
+ /* Reconnect all disconnected drivers */
+ for (; number_of_drivers < tmp; number_of_drivers++) {
+ r = EFI_CALL(efi_connect_controller(handle,
+ &driver_handle_buffer[number_of_drivers],
+ NULL, true));
+ if (r != EFI_SUCCESS)
+ EFI_PRINT("Failed to reconnect controller\n");
+ }
+
free(driver_handle_buffer);
return ret;
}
@@ -1336,34 +1365,35 @@ static efi_status_t efi_uninstall_protocol
(efi_handle_t handle, const efi_guid_t *protocol,
void *protocol_interface)
{
- struct efi_object *efiobj;
struct efi_handler *handler;
struct efi_open_protocol_info_item *item;
struct efi_open_protocol_info_item *pos;
efi_status_t r;
- /* Check handle */
- efiobj = efi_search_obj(handle);
- if (!efiobj) {
- r = EFI_INVALID_PARAMETER;
- goto out;
- }
/* Find the protocol on the handle */
r = efi_search_protocol(handle, protocol, &handler);
if (r != EFI_SUCCESS)
goto out;
+ if (handler->protocol_interface != protocol_interface)
+ return EFI_NOT_FOUND;
/* Disconnect controllers */
- efi_disconnect_all_drivers(efiobj, protocol, NULL);
+ r = efi_disconnect_all_drivers(handle, protocol, NULL);
+ if (r != EFI_SUCCESS) {
+ r = EFI_ACCESS_DENIED;
+ goto out;
+ }
/* Close protocol */
list_for_each_entry_safe(item, pos, &handler->open_infos, link) {
if (item->info.attributes ==
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL ||
item->info.attributes == EFI_OPEN_PROTOCOL_GET_PROTOCOL ||
item->info.attributes == EFI_OPEN_PROTOCOL_TEST_PROTOCOL)
- list_del(&item->link);
+ efi_delete_open_info(item);
}
+ /* if agents didn't close the protocols properly */
if (!list_empty(&handler->open_infos)) {
r = EFI_ACCESS_DENIED;
+ EFI_CALL(efi_connect_controller(handle, NULL, NULL, true));
goto out;
}
r = efi_remove_protocol(handle, protocol, protocol_interface);
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 7a6f195cbc..af8a2ee940 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -368,9 +368,8 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
auth_hdr->auth_info.hdr.dwLength
- sizeof(auth_hdr->auth_info),
&buf);
- if (IS_ERR(capsule_sig)) {
+ if (!capsule_sig) {
debug("Parsing variable's pkcs7 header failed\n");
- capsule_sig = NULL;
goto out;
}
@@ -581,6 +580,13 @@ static efi_status_t efi_capsule_update_firmware(
fw_accept_os = capsule_data->flags & FW_ACCEPT_OS ? 0x1 : 0x0;
}
+ if (guidcmp(&capsule_data->capsule_guid,
+ &efi_guid_firmware_management_capsule_id)) {
+ log_err("Unsupported capsule type: %pUs\n",
+ &capsule_data->capsule_guid);
+ return EFI_UNSUPPORTED;
+ }
+
/* sanity check */
if (capsule_data->header_size < sizeof(*capsule) ||
capsule_data->header_size >= capsule_data->capsule_image_size)
@@ -751,15 +757,7 @@ efi_status_t EFIAPI efi_update_capsule(
log_debug("Capsule[%d] (guid:%pUs)\n",
i, &capsule->capsule_guid);
- if (!guidcmp(&capsule->capsule_guid,
- &efi_guid_firmware_management_capsule_id)) {
- ret = efi_capsule_update_firmware(capsule);
- } else {
- log_err("Unsupported capsule type: %pUs\n",
- &capsule->capsule_guid);
- ret = EFI_UNSUPPORTED;
- }
-
+ ret = efi_capsule_update_firmware(capsule);
if (ret != EFI_SUCCESS)
goto out;
}
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 04ebb449ca..ed7214f3a3 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <blk.h>
#include <dm.h>
+#include <dm/root.h>
#include <log.h>
#include <net.h>
#include <usb.h>
@@ -21,16 +22,6 @@
#include <asm-generic/unaligned.h>
#include <linux/compat.h> /* U16_MAX */
-#ifdef CONFIG_BLKMAP
-const efi_guid_t efi_guid_blkmap_dev = U_BOOT_BLKMAP_DEV_GUID;
-#endif
-#ifdef CONFIG_SANDBOX
-const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
-#endif
-#ifdef CONFIG_VIRTIO_BLK
-const efi_guid_t efi_guid_virtio_dev = U_BOOT_VIRTIO_DEV_GUID;
-#endif
-
/* template END node: */
const struct efi_device_path END = {
.type = DEVICE_PATH_TYPE_END,
@@ -38,16 +29,6 @@ const struct efi_device_path END = {
.length = sizeof(END),
};
-/* template ROOT node: */
-static const struct efi_device_path_vendor ROOT = {
- .dp = {
- .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
- .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
- .length = sizeof(ROOT),
- },
- .guid = U_BOOT_GUID,
-};
-
#if defined(CONFIG_MMC)
/*
* Determine if an MMC device is an SD card.
@@ -497,13 +478,12 @@ bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
__maybe_unused static unsigned int dp_size(struct udevice *dev)
{
if (!dev || !dev->driver)
- return sizeof(ROOT);
+ return sizeof(struct efi_device_path_udevice);
switch (device_get_uclass_id(dev)) {
case UCLASS_ROOT:
- case UCLASS_SIMPLE_BUS:
/* stop traversing parents at this point: */
- return sizeof(ROOT);
+ return sizeof(struct efi_device_path_udevice);
case UCLASS_ETH:
return dp_size(dev->parent) +
sizeof(struct efi_device_path_mac_addr);
@@ -534,43 +514,15 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
return dp_size(dev->parent) +
sizeof(struct efi_device_path_nvme);
#endif
-#ifdef CONFIG_SANDBOX
- case UCLASS_HOST:
- /*
- * Sandbox's host device will be represented
- * as vendor device with extra one byte for
- * device number
- */
- return dp_size(dev->parent)
- + sizeof(struct efi_device_path_vendor) + 1;
-#endif
#ifdef CONFIG_USB
case UCLASS_MASS_STORAGE:
return dp_size(dev->parent)
+ sizeof(struct efi_device_path_controller);
#endif
-#ifdef CONFIG_VIRTIO_BLK
- case UCLASS_VIRTIO:
- /*
- * Virtio devices will be represented as a vendor
- * device node with an extra byte for the device
- * number.
- */
- return dp_size(dev->parent)
- + sizeof(struct efi_device_path_vendor) + 1;
-#endif
-#ifdef CONFIG_BLKMAP
- case UCLASS_BLKMAP:
- /*
- * blkmap devices will be represented as a vendor
- * device node with an extra byte for the device
- * number.
- */
- return dp_size(dev->parent)
- + sizeof(struct efi_device_path_vendor) + 1;
-#endif
default:
- return dp_size(dev->parent);
+ /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
+ return dp_size(dev->parent) +
+ sizeof(struct efi_device_path_udevice);
}
#if defined(CONFIG_MMC)
case UCLASS_MMC:
@@ -582,8 +534,8 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
return dp_size(dev->parent) +
sizeof(struct efi_device_path_usb);
default:
- /* just skip over unknown classes: */
- return dp_size(dev->parent);
+ return dp_size(dev->parent) +
+ sizeof(struct efi_device_path_udevice);
}
}
@@ -596,21 +548,19 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
*/
__maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
{
+ enum uclass_id uclass_id;
+
if (!dev || !dev->driver)
return buf;
- switch (device_get_uclass_id(dev)) {
- case UCLASS_ROOT:
- case UCLASS_SIMPLE_BUS: {
- /* stop traversing parents at this point: */
- struct efi_device_path_vendor *vdp = buf;
- *vdp = ROOT;
- return &vdp[1];
- }
+ uclass_id = device_get_uclass_id(dev);
+ if (uclass_id != UCLASS_ROOT)
+ buf = dp_fill(buf, dev->parent);
+
+ switch (uclass_id) {
#ifdef CONFIG_NETDEVICES
case UCLASS_ETH: {
- struct efi_device_path_mac_addr *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_mac_addr *dp = buf;
struct eth_pdata *pdata = dev_get_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -625,63 +575,10 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
}
#endif
case UCLASS_BLK:
- switch (dev->parent->uclass->uc_drv->id) {
-#ifdef CONFIG_BLKMAP
- case UCLASS_BLKMAP: {
- struct efi_device_path_vendor *dp;
- struct blk_desc *desc = dev_get_uclass_plat(dev);
-
- dp_fill(buf, dev->parent);
- dp = buf;
- ++dp;
- dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
- dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
- dp->dp.length = sizeof(*dp) + 1;
- memcpy(&dp->guid, &efi_guid_blkmap_dev,
- sizeof(efi_guid_t));
- dp->vendor_data[0] = desc->devnum;
- return &dp->vendor_data[1];
- }
-#endif
-#ifdef CONFIG_SANDBOX
- case UCLASS_HOST: {
- /* stop traversing parents at this point: */
- struct efi_device_path_vendor *dp;
- struct blk_desc *desc = dev_get_uclass_plat(dev);
-
- dp_fill(buf, dev->parent);
- dp = buf;
- ++dp;
- dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
- dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
- dp->dp.length = sizeof(*dp) + 1;
- memcpy(&dp->guid, &efi_guid_host_dev,
- sizeof(efi_guid_t));
- dp->vendor_data[0] = desc->devnum;
- return &dp->vendor_data[1];
- }
-#endif
-#ifdef CONFIG_VIRTIO_BLK
- case UCLASS_VIRTIO: {
- struct efi_device_path_vendor *dp;
- struct blk_desc *desc = dev_get_uclass_plat(dev);
-
- dp_fill(buf, dev->parent);
- dp = buf;
- ++dp;
- dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
- dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
- dp->dp.length = sizeof(*dp) + 1;
- memcpy(&dp->guid, &efi_guid_virtio_dev,
- sizeof(efi_guid_t));
- dp->vendor_data[0] = desc->devnum;
- return &dp->vendor_data[1];
- }
-#endif
+ switch (device_get_uclass_id(dev->parent)) {
#ifdef CONFIG_IDE
case UCLASS_IDE: {
- struct efi_device_path_atapi *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_atapi *dp = buf;
struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -697,8 +594,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#endif
#if defined(CONFIG_SCSI)
case UCLASS_SCSI: {
- struct efi_device_path_scsi *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_scsi *dp = buf;
struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -711,8 +607,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#endif
#if defined(CONFIG_MMC)
case UCLASS_MMC: {
- struct efi_device_path_sd_mmc_path *sddp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_sd_mmc_path *sddp = buf;
struct blk_desc *desc = dev_get_uclass_plat(dev);
sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -726,8 +621,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#endif
#if defined(CONFIG_AHCI) || defined(CONFIG_SATA)
case UCLASS_AHCI: {
- struct efi_device_path_sata *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_sata *dp = buf;
struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -742,8 +636,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#endif
#if defined(CONFIG_NVME)
case UCLASS_NVME: {
- struct efi_device_path_nvme *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_nvme *dp = buf;
u32 ns_id;
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
@@ -757,8 +650,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#if defined(CONFIG_USB)
case UCLASS_MASS_STORAGE: {
struct blk_desc *desc = dev_get_uclass_plat(dev);
- struct efi_device_path_controller *dp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_controller *dp = buf;
dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
@@ -767,16 +659,26 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
return &dp[1];
}
#endif
- default:
- debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
- __FILE__, __LINE__, __func__,
- dev->name, dev->parent->uclass->uc_drv->id);
- return dp_fill(buf, dev->parent);
+ default: {
+ /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
+ struct efi_device_path_udevice *dp = buf;
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+ dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+ dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+ dp->dp.length = sizeof(*dp);
+ memcpy(&dp->guid, &efi_u_boot_guid,
+ sizeof(efi_guid_t));
+ dp->uclass_id = (UCLASS_BLK & 0xffff) |
+ (desc->uclass_id << 16);
+ dp->dev_number = desc->devnum;
+
+ return &dp[1];
}
+ }
#if defined(CONFIG_MMC)
case UCLASS_MMC: {
- struct efi_device_path_sd_mmc_path *sddp =
- dp_fill(buf, dev->parent);
+ struct efi_device_path_sd_mmc_path *sddp = buf;
struct mmc *mmc = mmc_get_mmc_dev(dev);
struct blk_desc *desc = mmc_get_blk_desc(mmc);
@@ -792,7 +694,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#endif
case UCLASS_MASS_STORAGE:
case UCLASS_USB_HUB: {
- struct efi_device_path_usb *udp = dp_fill(buf, dev->parent);
+ struct efi_device_path_usb *udp = buf;
switch (device_get_uclass_id(dev->parent)) {
case UCLASS_USB_HUB: {
@@ -811,11 +713,18 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
return &udp[1];
}
- default:
- /* If the uclass driver is missing, this will show NULL */
- log_debug("unhandled device class: %s (%s)\n", dev->name,
- dev_get_uclass_name(dev));
- return dp_fill(buf, dev->parent);
+ default: {
+ struct efi_device_path_udevice *vdp = buf;
+
+ vdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+ vdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+ vdp->dp.length = sizeof(*vdp);
+ memcpy(&vdp->guid, &efi_u_boot_guid, sizeof(efi_guid_t));
+ vdp->uclass_id = uclass_id;
+ vdp->dev_number = dev->seq_;
+
+ return &vdp[1];
+ }
}
}
@@ -1052,14 +961,12 @@ struct efi_device_path *efi_dp_from_uart(void)
{
void *buf, *pos;
struct efi_device_path_uart *uart;
- size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END);
+ size_t dpsize = dp_size(dm_root()) + sizeof(*uart) + sizeof(END);
buf = efi_alloc(dpsize);
if (!buf)
return NULL;
- pos = buf;
- memcpy(pos, &ROOT, sizeof(ROOT));
- pos += sizeof(ROOT);
+ pos = dp_fill(buf, dm_root());
uart = pos;
uart->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
uart->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_UART;
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 28c8cdf710..f0d76113b0 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -487,15 +487,16 @@ static efi_status_t efi_disk_add_dev(
*/
if ((part || desc->part_type == PART_TYPE_UNKNOWN) &&
efi_fs_exists(desc, part)) {
- diskobj->volume = efi_simple_file_system(desc, part,
- diskobj->dp);
+ ret = efi_create_simple_file_system(desc, part, diskobj->dp,
+ &diskobj->volume);
+ if (ret != EFI_SUCCESS)
+ goto error;
+
ret = efi_add_protocol(&diskobj->header,
&efi_simple_file_system_protocol_guid,
diskobj->volume);
- if (ret != EFI_SUCCESS) {
- log_debug("simple FS failed\n");
- return ret;
- }
+ if (ret != EFI_SUCCESS)
+ goto error;
}
diskobj->ops = block_io_disk_template;
diskobj->dev_index = dev_index;
@@ -538,6 +539,8 @@ static efi_status_t efi_disk_add_dev(
return EFI_SUCCESS;
error:
efi_delete_handle(&diskobj->header);
+ free(diskobj->volume);
+ free(diskobj);
return ret;
}
@@ -708,6 +711,7 @@ int efi_disk_remove(void *ctx, struct event *event)
efi_handle_t handle;
struct blk_desc *desc;
struct efi_disk_obj *diskobj = NULL;
+ efi_status_t ret;
if (dev_tag_get_ptr(dev, DM_TAG_EFI, (void **)&handle))
return 0;
@@ -727,10 +731,14 @@ int efi_disk_remove(void *ctx, struct event *event)
return 0;
}
+ ret = efi_delete_handle(handle);
+ /* Do not delete DM device if there are still EFI drivers attached. */
+ if (ret != EFI_SUCCESS)
+ return -1;
+
if (diskobj)
efi_free_pool(diskobj->dp);
- efi_delete_handle(handle);
dev_tag_del(dev, DM_TAG_EFI);
return 0;
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index 520c730220..3c56cebf96 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -195,6 +195,8 @@ static struct efi_file_handle *file_open(struct file_system *fs,
/* +2 is for null and '/' */
fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
+ if (!fh)
+ return NULL;
fh->open_mode = open_mode;
fh->base = efi_file_handle_protocol;
@@ -1192,18 +1194,22 @@ efi_open_volume(struct efi_simple_file_system_protocol *this,
return EFI_EXIT(efi_open_volume_int(this, root));
}
-struct efi_simple_file_system_protocol *
-efi_simple_file_system(struct blk_desc *desc, int part,
- struct efi_device_path *dp)
+efi_status_t
+efi_create_simple_file_system(struct blk_desc *desc, int part,
+ struct efi_device_path *dp,
+ struct efi_simple_file_system_protocol **fsp)
{
struct file_system *fs;
fs = calloc(1, sizeof(*fs));
+ if (!fs)
+ return EFI_OUT_OF_RESOURCES;
fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
fs->base.open_volume = efi_open_volume;
fs->desc = desc;
fs->part = part;
fs->dp = dp;
+ *fsp = &fs->base;
- return &fs->base;
+ return EFI_SUCCESS;
}
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 93e2b01c07..9abb29f1df 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -10,6 +10,7 @@
#include <charset.h>
#include <dfu.h>
#include <efi_loader.h>
+#include <efi_variable.h>
#include <fwu.h>
#include <image.h>
#include <signatures.h>
@@ -36,11 +37,52 @@ struct fmp_payload_header {
u32 lowest_supported_version;
};
+/**
+ * struct fmp_state - fmp firmware update state
+ *
+ * This structure describes the state of the firmware update
+ * through FMP protocol.
+ *
+ * @fw_version: Firmware versions used
+ * @lowest_supported_version: Lowest supported version
+ * @last_attempt_version: Last attempt version
+ * @last_attempt_status: Last attempt status
+ */
+struct fmp_state {
+ u32 fw_version;
+ u32 lowest_supported_version; /* not used */
+ u32 last_attempt_version; /* not used */
+ u32 last_attempt_status; /* not used */
+};
+
__weak void set_dfu_alt_info(char *interface, char *devstr)
{
env_set("dfu_alt_info", update_info.dfu_string);
}
+/**
+ * efi_firmware_get_image_type_id - get image_type_id
+ * @image_index: image index
+ *
+ * Return the image_type_id identified by the image index.
+ *
+ * Return: pointer to the image_type_id, NULL if image_index is invalid
+ */
+static
+efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
+{
+ int i;
+ struct efi_fw_image *fw_array;
+
+ fw_array = update_info.images;
+ for (i = 0; i < update_info.num_images; i++) {
+ if (fw_array[i].image_index == image_index)
+ return &fw_array[i].image_type_id;
+ }
+
+ return NULL;
+}
+
/* Place holder; not supported */
static
efi_status_t EFIAPI efi_firmware_get_image_unsupported(
@@ -103,6 +145,91 @@ efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
}
/**
+ * efi_firmware_get_lsv_from_dtb - get lowest supported version from dtb
+ * @image_index: Image index
+ * @image_type_id: Image type id
+ * @lsv: Pointer to store the lowest supported version
+ *
+ * Read the firmware version information from dtb.
+ */
+static void efi_firmware_get_lsv_from_dtb(u8 image_index,
+ efi_guid_t *image_type_id, u32 *lsv)
+{
+ const void *fdt = gd->fdt_blob;
+ const fdt32_t *val;
+ const char *guid_str;
+ int len, offset, index;
+ int parent, ret;
+
+ *lsv = 0;
+
+ parent = fdt_subnode_offset(fdt, 0, "firmware-version");
+ if (parent < 0)
+ return;
+
+ fdt_for_each_subnode(offset, fdt, parent) {
+ efi_guid_t guid;
+
+ guid_str = fdt_getprop(fdt, offset, "image-type-id", &len);
+ if (!guid_str)
+ continue;
+ ret = uuid_str_to_bin(guid_str, guid.b, UUID_STR_FORMAT_GUID);
+ if (ret < 0) {
+ log_warning("Wrong image-type-id format.\n");
+ continue;
+ }
+
+ val = fdt_getprop(fdt, offset, "image-index", &len);
+ if (!val)
+ continue;
+ index = fdt32_to_cpu(*val);
+
+ if (!guidcmp(&guid, image_type_id) && index == image_index) {
+ val = fdt_getprop(fdt, offset,
+ "lowest-supported-version", &len);
+ if (val)
+ *lsv = fdt32_to_cpu(*val);
+ }
+ }
+}
+
+/**
+ * efi_firmware_fill_version_info - fill the version information
+ * @image_info: Image information
+ * @fw_array: Pointer to size of new image
+ *
+ * Fill the version information into image_info strucrure.
+ *
+ */
+static
+void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_info,
+ struct efi_fw_image *fw_array)
+{
+ u16 varname[13]; /* u"FmpStateXXXX" */
+ efi_status_t ret;
+ efi_uintn_t size;
+ struct fmp_state var_state = { 0 };
+
+ efi_create_indexed_name(varname, sizeof(varname), "FmpState",
+ fw_array->image_index);
+ size = sizeof(var_state);
+ ret = efi_get_variable_int(varname, &fw_array->image_type_id,
+ NULL, &size, &var_state, NULL);
+ if (ret == EFI_SUCCESS)
+ image_info->version = var_state.fw_version;
+ else
+ image_info->version = 0;
+
+ efi_firmware_get_lsv_from_dtb(fw_array->image_index,
+ &fw_array->image_type_id,
+ &image_info->lowest_supported_image_version);
+
+ image_info->version_name = NULL; /* not supported */
+ image_info->last_attempt_version = 0;
+ image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
+}
+
+/**
* efi_fill_image_desc_array - populate image descriptor array
* @image_info_size: Size of @image_info
* @image_info: Image information
@@ -131,7 +258,7 @@ static efi_status_t efi_fill_image_desc_array(
struct efi_fw_image *fw_array;
int i;
- total_size = sizeof(*image_info) * num_image_type_guids;
+ total_size = sizeof(*image_info) * update_info.num_images;
if (*image_info_size < total_size) {
*image_info_size = total_size;
@@ -141,21 +268,20 @@ static efi_status_t efi_fill_image_desc_array(
*image_info_size = total_size;
fw_array = update_info.images;
- *descriptor_count = num_image_type_guids;
+ *descriptor_count = update_info.num_images;
*descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
*descriptor_size = sizeof(*image_info);
*package_version = 0xffffffff; /* not supported */
*package_version_name = NULL; /* not supported */
- for (i = 0; i < num_image_type_guids; i++) {
+ for (i = 0; i < update_info.num_images; i++) {
image_info[i].image_index = fw_array[i].image_index;
image_info[i].image_type_id = fw_array[i].image_type_id;
image_info[i].image_id = fw_array[i].image_index;
-
image_info[i].image_id_name = fw_array[i].fw_name;
- image_info[i].version = 0; /* not supported */
- image_info[i].version_name = NULL; /* not supported */
+ efi_firmware_fill_version_info(&image_info[i], &fw_array[i]);
+
image_info[i].size = 0;
image_info[i].attributes_supported =
IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
@@ -168,9 +294,6 @@ static efi_status_t efi_fill_image_desc_array(
image_info[0].attributes_setting |=
IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
- image_info[i].lowest_supported_image_version = 0;
- image_info[i].last_attempt_version = 0;
- image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
image_info[i].hardware_instance = 1;
image_info[i].dependencies = NULL;
}
@@ -194,8 +317,6 @@ efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
{
const void *image = *p_image;
efi_uintn_t image_size = *p_image_size;
- u32 fmp_hdr_signature;
- struct fmp_payload_header *header;
void *capsule_payload;
efi_status_t status;
efi_uintn_t capsule_payload_size;
@@ -222,27 +343,122 @@ efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
debug("Updating capsule without authenticating.\n");
}
- fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
- header = (void *)image;
-
- if (!memcmp(&header->signature, &fmp_hdr_signature,
- sizeof(fmp_hdr_signature))) {
- /*
- * When building the capsule with the scripts in
- * edk2, a FMP header is inserted above the capsule
- * payload. Compensate for this header to get the
- * actual payload that is to be updated.
- */
- image += header->header_size;
- image_size -= header->header_size;
- }
-
*p_image = image;
*p_image_size = image_size;
return EFI_SUCCESS;
}
/**
+ * efi_firmware_set_fmp_state_var - set FmpStateXXXX variable
+ * @state: Pointer to fmp state
+ * @image_index: image index
+ *
+ * Update the FmpStateXXXX variable with the firmware update state.
+ *
+ * Return: status code
+ */
+static
+efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_index)
+{
+ u16 varname[13]; /* u"FmpStateXXXX" */
+ efi_status_t ret;
+ efi_guid_t *image_type_id;
+ struct fmp_state var_state = { 0 };
+
+ image_type_id = efi_firmware_get_image_type_id(image_index);
+ if (!image_type_id)
+ return EFI_INVALID_PARAMETER;
+
+ efi_create_indexed_name(varname, sizeof(varname), "FmpState",
+ image_index);
+
+ /*
+ * Only the fw_version is set here.
+ * lowest_supported_version in FmpState variable is ignored since
+ * it can be tampered if the file based EFI variable storage is used.
+ */
+ var_state.fw_version = state->fw_version;
+
+ ret = efi_set_variable_int(varname, image_type_id,
+ EFI_VARIABLE_READ_ONLY |
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(var_state), &var_state, false);
+
+ return ret;
+}
+
+/**
+ * efi_firmware_get_fw_version - get fw_version from FMP payload header
+ * @p_image: Pointer to new image
+ * @p_image_size: Pointer to size of new image
+ * @state: Pointer to fmp state
+ *
+ * Parse the FMP payload header and fill the fmp_state structure.
+ * If no FMP payload header is found, fmp_state structure is not updated.
+ *
+ */
+static void efi_firmware_get_fw_version(const void **p_image,
+ efi_uintn_t *p_image_size,
+ struct fmp_state *state)
+{
+ const struct fmp_payload_header *header;
+ u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
+
+ header = *p_image;
+ if (header->signature == fmp_hdr_signature) {
+ /* FMP header is inserted above the capsule payload */
+ state->fw_version = header->fw_version;
+
+ *p_image += header->header_size;
+ *p_image_size -= header->header_size;
+ }
+}
+
+/**
+ * efi_firmware_verify_image - verify image
+ * @p_image: Pointer to new image
+ * @p_image_size: Pointer to size of new image
+ * @image_index: Image index
+ * @state: Pointer to fmp state
+ *
+ * Verify the capsule authentication and check if the fw_version
+ * is equal or greater than the lowest supported version.
+ *
+ * Return: status code
+ */
+static
+efi_status_t efi_firmware_verify_image(const void **p_image,
+ efi_uintn_t *p_image_size,
+ u8 image_index,
+ struct fmp_state *state)
+{
+ u32 lsv;
+ efi_status_t ret;
+ efi_guid_t *image_type_id;
+
+ ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ efi_firmware_get_fw_version(p_image, p_image_size, state);
+
+ image_type_id = efi_firmware_get_image_type_id(image_index);
+ if (!image_type_id)
+ return EFI_INVALID_PARAMETER;
+
+ efi_firmware_get_lsv_from_dtb(image_index, image_type_id, &lsv);
+ if (state->fw_version < lsv) {
+ log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
+ state->fw_version, lsv);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return ret;
+}
+
+/**
* efi_firmware_get_image_info - return information about the current
* firmware image
* @this: Protocol instance
@@ -331,6 +547,7 @@ efi_status_t EFIAPI efi_firmware_fit_set_image(
u16 **abort_reason)
{
efi_status_t status;
+ struct fmp_state state = { 0 };
EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
image_size, vendor_code, progress, abort_reason);
@@ -338,13 +555,16 @@ efi_status_t EFIAPI efi_firmware_fit_set_image(
if (!image || image_index != 1)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- status = efi_firmware_capsule_authenticate(&image, &image_size);
+ status = efi_firmware_verify_image(&image, &image_size, image_index,
+ &state);
if (status != EFI_SUCCESS)
return EFI_EXIT(status);
if (fit_update(image))
return EFI_EXIT(EFI_DEVICE_ERROR);
+ efi_firmware_set_fmp_state_var(&state, image_index);
+
return EFI_EXIT(EFI_SUCCESS);
}
@@ -392,6 +612,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
{
int ret;
efi_status_t status;
+ struct fmp_state state = { 0 };
EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image,
image_size, vendor_code, progress, abort_reason);
@@ -399,7 +620,8 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
if (!image)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- status = efi_firmware_capsule_authenticate(&image, &image_size);
+ status = efi_firmware_verify_image(&image, &image_size, image_index,
+ &state);
if (status != EFI_SUCCESS)
return EFI_EXIT(status);
@@ -419,6 +641,8 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
NULL, NULL))
return EFI_EXIT(EFI_DEVICE_ERROR);
+ efi_firmware_set_fmp_state_var(&state, image_index);
+
return EFI_EXIT(EFI_SUCCESS);
}
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 1f4ab2b419..cdfd16ea77 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -257,3 +257,28 @@ efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, efi_guid_t *gu
return ret;
}
+
+/**
+ * efi_search_bootorder() - search the boot option index in BootOrder
+ *
+ * @bootorder: pointer to the BootOrder variable
+ * @num: number of BootOrder entry
+ * @target: target boot option index to search
+ * @index: pointer to store the index of BootOrder variable
+ * Return: true if exists, false otherwise
+ */
+bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
+{
+ u32 i;
+
+ for (i = 0; i < num; i++) {
+ if (target == bootorder[i]) {
+ if (index)
+ *index = i;
+
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index 26df0da16c..97547571ce 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -592,6 +592,7 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
struct efi_signature_store *db = NULL, *dbx = NULL;
void *new_efi = NULL;
u8 *auth, *wincerts_end;
+ u64 new_efi_size = efi_size;
size_t auth_size;
bool ret = false;
@@ -600,11 +601,11 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
if (!efi_secure_boot_enabled())
return true;
- new_efi = efi_prepare_aligned_image(efi, (u64 *)&efi_size);
+ new_efi = efi_prepare_aligned_image(efi, &new_efi_size);
if (!new_efi)
return false;
- if (!efi_image_parse(new_efi, efi_size, &regs, &wincerts,
+ if (!efi_image_parse(new_efi, new_efi_size, &regs, &wincerts,
&wincerts_len)) {
log_err("Parsing PE executable image failed\n");
goto out;
diff --git a/lib/efi_loader/efi_load_options.c b/lib/efi_loader/efi_load_options.c
index 3cfddee014..5f62184da1 100644
--- a/lib/efi_loader/efi_load_options.c
+++ b/lib/efi_loader/efi_load_options.c
@@ -31,10 +31,10 @@ efi_status_t efi_set_load_options(efi_handle_t handle,
efi_status_t ret;
ret = efi_search_protocol(handle, &efi_guid_loaded_image, &handler);
- loaded_image_info = handler->protocol_interface;
if (ret != EFI_SUCCESS)
return EFI_INVALID_PARAMETER;
+ loaded_image_info = handler->protocol_interface;
loaded_image_info->load_options = load_options;
loaded_image_info->load_options_size = load_options_size;
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index e2ca78d935..f752703b43 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -34,6 +34,7 @@ struct efi_mem_list {
#define EFI_CARVE_NO_OVERLAP -1
#define EFI_CARVE_LOOP_AGAIN -2
#define EFI_CARVE_OVERLAPS_NONRAM -3
+#define EFI_CARVE_OUT_OF_RESOURCES -4
/* This list contains all memory map items */
static LIST_HEAD(efi_mem);
@@ -239,6 +240,8 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
/* Create a new map from [ carve_start ... map_end ] */
newmap = calloc(1, sizeof(*newmap));
+ if (!newmap)
+ return EFI_CARVE_OUT_OF_RESOURCES;
newmap->desc = map->desc;
newmap->desc.physical_start = carve_start;
newmap->desc.virtual_start = carve_start;
@@ -282,6 +285,8 @@ static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
++efi_memory_map_key;
newlist = calloc(1, sizeof(*newlist));
+ if (!newlist)
+ return EFI_OUT_OF_RESOURCES;
newlist->desc.type = memory_type;
newlist->desc.physical_start = start;
newlist->desc.virtual_start = start;
@@ -311,11 +316,15 @@ static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
r = efi_mem_carve_out(lmem, &newlist->desc,
overlap_only_ram);
switch (r) {
+ case EFI_CARVE_OUT_OF_RESOURCES:
+ free(newlist);
+ return EFI_OUT_OF_RESOURCES;
case EFI_CARVE_OVERLAPS_NONRAM:
/*
* The user requested to only have RAM overlaps,
* but we hit a non-RAM region. Error out.
*/
+ free(newlist);
return EFI_NO_MAPPING;
case EFI_CARVE_NO_OVERLAP:
/* Just ignore this list entry */
@@ -346,6 +355,7 @@ static efi_status_t efi_add_memory_map_pg(u64 start, u64 pages,
* The payload wanted to have RAM overlaps, but we overlapped
* with an unallocated region. Error out.
*/
+ free(newlist);
return EFI_NO_MAPPING;
}
@@ -487,7 +497,7 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type,
enum efi_memory_type memory_type,
efi_uintn_t pages, uint64_t *memory)
{
- u64 len = pages << EFI_PAGE_SHIFT;
+ u64 len;
efi_status_t ret;
uint64_t addr;
@@ -497,6 +507,11 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type,
return EFI_INVALID_PARAMETER;
if (!memory)
return EFI_INVALID_PARAMETER;
+ len = (u64)pages << EFI_PAGE_SHIFT;
+ /* Catch possible overflow on 64bit systems */
+ if (sizeof(efi_uintn_t) == sizeof(u64) &&
+ (len >> EFI_PAGE_SHIFT) != (u64)pages)
+ return EFI_OUT_OF_RESOURCES;
switch (type) {
case EFI_ALLOCATE_ANY_PAGES:
@@ -862,7 +877,7 @@ efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
*/
__weak void efi_add_known_memory(void)
{
- u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
+ u64 ram_top = gd->ram_top & ~EFI_PAGE_MASK;
int i;
/*
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index a83ae7a46c..7b7926a0d4 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -706,8 +706,7 @@ static efi_status_t tcg2_create_digest(const u8 *input, u32 length,
sha512_finish(&ctx_512, final);
break;
default:
- EFI_PRINT("Unsupported algorithm %x\n", hash_alg);
- return EFI_INVALID_PARAMETER;
+ continue;
}
digest_list->digests[digest_list->count].hash_alg = hash_alg;
memcpy(&digest_list->digests[digest_list->count].digest, final,
@@ -930,8 +929,7 @@ static efi_status_t tcg2_hash_pe_image(void *efi, u64 efi_size,
hash_calculate("sha512", regs->reg, regs->num, hash);
break;
default:
- EFI_PRINT("Unsupported algorithm %x\n", hash_alg);
- return EFI_INVALID_PARAMETER;
+ continue;
}
digest_list->digests[digest_list->count].hash_alg = hash_alg;
memcpy(&digest_list->digests[digest_list->count].digest, hash,
@@ -1680,8 +1678,8 @@ void tcg2_uninit(void)
if (!is_tcg2_protocol_installed())
return;
- ret = efi_remove_protocol(efi_root, &efi_guid_tcg2_protocol,
- (void *)&efi_tcg2_protocol);
+ ret = efi_uninstall_multiple_protocol_interfaces(efi_root, &efi_guid_tcg2_protocol,
+ &efi_tcg2_protocol, NULL);
if (ret != EFI_SUCCESS)
log_err("Failed to remove EFI TCG2 protocol\n");
}
@@ -2507,8 +2505,8 @@ efi_status_t efi_tcg2_register(void)
goto fail;
}
- ret = efi_add_protocol(efi_root, &efi_guid_tcg2_protocol,
- (void *)&efi_tcg2_protocol);
+ ret = efi_install_multiple_protocol_interfaces(&efi_root, &efi_guid_tcg2_protocol,
+ &efi_tcg2_protocol, NULL);
if (ret != EFI_SUCCESS) {
tcg2_uninit();
goto fail;
diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
index d6b65aed12..5fa7dcb8d3 100644
--- a/lib/efi_loader/efi_var_mem.c
+++ b/lib/efi_loader/efi_var_mem.c
@@ -177,6 +177,10 @@ efi_status_t __efi_runtime efi_var_mem_ins(
u64 __efi_runtime efi_var_mem_free(void)
{
+ if (efi_var_buf->length + sizeof(struct efi_var_entry) >=
+ EFI_VAR_BUF_SIZE)
+ return 0;
+
return EFI_VAR_BUF_SIZE - efi_var_buf->length -
sizeof(struct efi_var_entry);
}
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index dfef18435d..09d03c0eee 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -4,16 +4,38 @@
*
* Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
* Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+#include <arm_ffa.h>
+#endif
+#include <cpu_func.h>
+#include <dm.h>
#include <efi.h>
#include <efi_api.h>
#include <efi_loader.h>
#include <efi_variable.h>
-#include <tee.h>
#include <malloc.h>
+#include <mapmem.h>
#include <mm_communication.h>
+#include <tee.h>
+
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+/* MM return codes */
+#define MM_SUCCESS (0)
+#define MM_NOT_SUPPORTED (-1)
+#define MM_INVALID_PARAMETER (-2)
+#define MM_DENIED (-3)
+#define MM_NO_MEMORY (-5)
+
+static const char *mm_sp_svc_uuid = MM_SP_UUID;
+static u16 mm_sp_id;
+#endif
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
static efi_uintn_t max_buffer_size; /* comm + var + func + data */
@@ -144,12 +166,238 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
return ret;
}
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+/**
+ * ffa_notify_mm_sp() - Announce there is data in the shared buffer
+ *
+ * Notify the MM partition in the trusted world that
+ * data is available in the shared buffer.
+ * This is a blocking call during which trusted world has exclusive access
+ * to the MM shared buffer.
+ *
+ * Return:
+ *
+ * 0 on success
+ */
+static int ffa_notify_mm_sp(void)
+{
+ struct ffa_send_direct_data msg = {0};
+ int ret;
+ int sp_event_ret;
+ struct udevice *dev;
+
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
+ if (ret) {
+ log_err("EFI: Cannot find FF-A bus device, notify MM SP failure\n");
+ return ret;
+ }
+
+ msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET; /* x3 */
+
+ ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
+ if (ret)
+ return ret;
+
+ sp_event_ret = msg.data0; /* x3 */
+
+ switch (sp_event_ret) {
+ case MM_SUCCESS:
+ ret = 0;
+ break;
+ case MM_NOT_SUPPORTED:
+ ret = -EINVAL;
+ break;
+ case MM_INVALID_PARAMETER:
+ ret = -EPERM;
+ break;
+ case MM_DENIED:
+ ret = -EACCES;
+ break;
+ case MM_NO_MEMORY:
+ ret = -EBUSY;
+ break;
+ default:
+ ret = -EACCES;
+ }
+
+ return ret;
+}
+
+/**
+ * ffa_discover_mm_sp_id() - Query the MM partition ID
+ *
+ * Use the FF-A driver to get the MM partition ID.
+ * If multiple partitions are found, use the first one.
+ * This is a boot time function.
+ *
+ * Return:
+ *
+ * 0 on success
+ */
+static int ffa_discover_mm_sp_id(void)
+{
+ u32 count = 0;
+ int ret;
+ struct ffa_partition_desc *descs;
+ struct udevice *dev;
+
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
+ if (ret) {
+ log_err("EFI: Cannot find FF-A bus device, MM SP discovery failure\n");
+ return ret;
+ }
+
+ /* Ask the driver to fill the buffer with the SPs info */
+ ret = ffa_partition_info_get(dev, mm_sp_svc_uuid, &count, &descs);
+ if (ret) {
+ log_err("EFI: Failure in querying SPs info (%d), MM SP discovery failure\n", ret);
+ return ret;
+ }
+
+ /* MM SPs found , use the first one */
+
+ mm_sp_id = descs[0].info.id;
+
+ log_info("EFI: MM partition ID 0x%x\n", mm_sp_id);
+
+ return 0;
+}
+
/**
- * mm_communicate() - Adjust the cmonnucation buffer to StandAlonneMM and send
+ * ffa_mm_communicate() - Exchange EFI services data with the MM partition using FF-A
+ * @comm_buf: locally allocated communication buffer used for rx/tx
+ * @dsize: communication buffer size
+ *
+ * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
+ * that there is data to read from the shared buffer.
+ * Communication with the MM SP is performed using FF-A transport.
+ * On the event, MM SP can read the data from the buffer and
+ * update the MM shared buffer with response data.
+ * The response data is copied back to the communication buffer.
+ *
+ * Return:
+ *
+ * EFI status code
+ */
+static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
+{
+ ulong tx_data_size;
+ int ffa_ret;
+ efi_status_t efi_ret;
+ struct efi_mm_communicate_header *mm_hdr;
+ void *virt_shared_buf;
+
+ if (!comm_buf)
+ return EFI_INVALID_PARAMETER;
+
+ /* Discover MM partition ID at boot time */
+ if (!mm_sp_id && ffa_discover_mm_sp_id()) {
+ log_err("EFI: Failure to discover MM SP ID at boot time, FF-A MM comms failure\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
+ tx_data_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
+
+ if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
+ return EFI_INVALID_PARAMETER;
+
+ /* Copy the data to the shared buffer */
+
+ virt_shared_buf = map_sysmem((phys_addr_t)CONFIG_FFA_SHARED_MM_BUF_ADDR, 0);
+ memcpy(virt_shared_buf, comm_buf, tx_data_size);
+
+ /*
+ * The secure world might have cache disabled for
+ * the device region used for shared buffer (which is the case for Optee).
+ * In this case, the secure world reads the data from DRAM.
+ * Let's flush the cache so the DRAM is updated with the latest data.
+ */
+#ifdef CONFIG_ARM64
+ invalidate_dcache_all();
+#endif
+
+ /* Announce there is data in the shared buffer */
+
+ ffa_ret = ffa_notify_mm_sp();
+
+ switch (ffa_ret) {
+ case 0: {
+ ulong rx_data_size;
+ /* Copy the MM SP response from the shared buffer to the communication buffer */
+ rx_data_size = ((struct efi_mm_communicate_header *)virt_shared_buf)->message_len +
+ sizeof(efi_guid_t) +
+ sizeof(size_t);
+
+ if (rx_data_size > comm_buf_size) {
+ efi_ret = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ memcpy(comm_buf, virt_shared_buf, rx_data_size);
+ efi_ret = EFI_SUCCESS;
+ break;
+ }
+ case -EINVAL:
+ efi_ret = EFI_DEVICE_ERROR;
+ break;
+ case -EPERM:
+ efi_ret = EFI_INVALID_PARAMETER;
+ break;
+ case -EACCES:
+ efi_ret = EFI_ACCESS_DENIED;
+ break;
+ case -EBUSY:
+ efi_ret = EFI_OUT_OF_RESOURCES;
+ break;
+ default:
+ efi_ret = EFI_ACCESS_DENIED;
+ }
+
+ unmap_sysmem(virt_shared_buf);
+ return efi_ret;
+}
+
+/**
+ * get_mm_comms() - detect the available MM transport
+ *
+ * Make sure the FF-A bus is probed successfully
+ * which means FF-A communication with secure world works and ready
+ * for use.
+ *
+ * If FF-A bus is not ready, use OPTEE comms.
+ *
+ * Return:
+ *
+ * MM_COMMS_FFA or MM_COMMS_OPTEE
+ */
+static enum mm_comms_select get_mm_comms(void)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
+ if (ret) {
+ log_debug("EFI: Cannot find FF-A bus device, trying Optee comms\n");
+ return MM_COMMS_OPTEE;
+ }
+
+ return MM_COMMS_FFA;
+}
+#endif
+
+/**
+ * mm_communicate() - Adjust the communication buffer to the MM SP and send
* it to OP-TEE
*
- * @comm_buf: locally allocted communcation buffer
+ * @comm_buf: locally allocated communication buffer
* @dsize: buffer size
+ *
+ * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
+ * The comm_buf format is the same for both partitions.
+ * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
+ * When using the u-boot FF-A driver, any MM SP is supported.
+ *
* Return: status code
*/
static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
@@ -157,12 +405,24 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
efi_status_t ret;
struct efi_mm_communicate_header *mm_hdr;
struct smm_variable_communicate_header *var_hdr;
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+ enum mm_comms_select mm_comms;
+#endif
dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
- ret = optee_mm_communicate(comm_buf, dsize);
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+ mm_comms = get_mm_comms();
+ if (mm_comms == MM_COMMS_FFA)
+ ret = ffa_mm_communicate(comm_buf, dsize);
+ else
+ ret = optee_mm_communicate(comm_buf, dsize);
+#else
+ ret = optee_mm_communicate(comm_buf, dsize);
+#endif
+
if (ret != EFI_SUCCESS) {
log_err("%s failed!\n", __func__);
return ret;
@@ -697,7 +957,7 @@ void efi_variables_boot_exit_notify(void)
ret = EFI_NOT_FOUND;
if (ret != EFI_SUCCESS)
- log_err("Unable to notify StMM for ExitBootServices\n");
+ log_err("Unable to notify the MM partition for ExitBootServices\n");
free(comm_buf);
/*
diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c
index 63e674bedc..02f19574f8 100644
--- a/lib/efi_selftest/efi_selftest_controllers.c
+++ b/lib/efi_selftest/efi_selftest_controllers.c
@@ -28,6 +28,7 @@ static efi_guid_t guid_child_controller =
static efi_handle_t handle_controller;
static efi_handle_t handle_child_controller[NUMBER_OF_CHILD_CONTROLLERS];
static efi_handle_t handle_driver;
+static bool allow_removal;
/*
* Count child controllers
@@ -85,8 +86,8 @@ static efi_status_t EFIAPI supported(
controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
switch (ret) {
case EFI_ACCESS_DENIED:
- case EFI_ALREADY_STARTED:
return ret;
+ case EFI_ALREADY_STARTED:
case EFI_SUCCESS:
break;
default:
@@ -124,8 +125,8 @@ static efi_status_t EFIAPI start(
controller_handle, EFI_OPEN_PROTOCOL_BY_DRIVER);
switch (ret) {
case EFI_ACCESS_DENIED:
- case EFI_ALREADY_STARTED:
return ret;
+ case EFI_ALREADY_STARTED:
case EFI_SUCCESS:
break;
default:
@@ -238,6 +239,9 @@ static efi_status_t EFIAPI stop(
if (ret != EFI_SUCCESS)
efi_st_error("Cannot free buffer\n");
+ if (!allow_removal)
+ return EFI_DEVICE_ERROR;
+
/* Detach driver from controller */
ret = boottime->close_protocol(
controller_handle, &guid_controller,
@@ -342,6 +346,7 @@ static int execute(void)
return EFI_ST_FAILURE;
}
/* Destroy remaining child controllers and disconnect controller */
+ allow_removal = true;
ret = boottime->disconnect_controller(handle_controller, NULL, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to disconnect controller\n");
@@ -393,7 +398,40 @@ static int execute(void)
efi_st_error("Number of children %u != %u\n",
(unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
}
- /* Uninstall controller protocol */
+
+ allow_removal = false;
+ /* Try to uninstall controller protocol using the wrong interface */
+ ret = boottime->uninstall_protocol_interface(handle_controller,
+ &guid_controller,
+ &interface1);
+ if (ret != EFI_NOT_FOUND) {
+ efi_st_error("Interface not checked when uninstalling protocol\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /*
+ * Uninstall a protocol while Disconnect controller won't
+ * allow it.
+ */
+ ret = boottime->uninstall_protocol_interface(handle_controller,
+ &guid_controller,
+ &interface2);
+ if (ret != EFI_ACCESS_DENIED) {
+ efi_st_error("Uninstall protocol interface failed\n");
+ return EFI_ST_FAILURE;
+ }
+ /*
+ * Check number of child controllers and make sure children have
+ * been reconnected
+ */
+ ret = count_child_controllers(handle_controller, &guid_controller,
+ &count);
+ if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) {
+ efi_st_error("Number of children %u != %u\n",
+ (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS);
+ }
+
+ allow_removal = true;
ret = boottime->uninstall_protocol_interface(handle_controller,
&guid_controller,
&interface2);
diff --git a/lib/efi_selftest/efi_selftest_hii.c b/lib/efi_selftest/efi_selftest_hii.c
index f4b55889e2..f219c0120a 100644
--- a/lib/efi_selftest/efi_selftest_hii.c
+++ b/lib/efi_selftest/efi_selftest_hii.c
@@ -220,14 +220,12 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_BUFFER_TOO_SMALL) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size,
(void **)&handles);
if (ret != EFI_SUCCESS) {
efi_st_error("AllocatePool failed\n");
- ret = EFI_ST_FAILURE;
goto out;
}
ret = hii_database_protocol->list_package_lists(hii_database_protocol,
@@ -236,7 +234,6 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_SUCCESS) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->free_pool(handles);
@@ -254,14 +251,12 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_BUFFER_TOO_SMALL) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size,
(void **)&handles);
if (ret != EFI_SUCCESS) {
efi_st_error("AllocatePool failed\n");
- ret = EFI_ST_FAILURE;
goto out;
}
ret = hii_database_protocol->list_package_lists(hii_database_protocol,
@@ -270,13 +265,11 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_SUCCESS) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->free_pool(handles);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
- ret = EFI_ST_FAILURE;
goto out;
}
@@ -289,14 +282,12 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_BUFFER_TOO_SMALL) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->allocate_pool(EFI_LOADER_DATA, handles_size,
(void **)&handles);
if (ret != EFI_SUCCESS) {
efi_st_error("AllocatePool failed\n");
- ret = EFI_ST_FAILURE;
goto out;
}
ret = hii_database_protocol->list_package_lists(hii_database_protocol,
@@ -305,13 +296,11 @@ static int test_hii_database_list_package_lists(void)
if (ret != EFI_SUCCESS) {
efi_st_error("list_package_lists returned %u\n",
(unsigned int)ret);
- ret = EFI_ST_FAILURE;
goto out;
}
ret = boottime->free_pool(handles);
if (ret != EFI_SUCCESS) {
efi_st_error("FreePool failed\n");
- ret = EFI_ST_FAILURE;
goto out;
}
diff --git a/lib/fwu_updates/Makefile b/lib/fwu_updates/Makefile
index 1993088e5b..c9e3c06b48 100644
--- a/lib/fwu_updates/Makefile
+++ b/lib/fwu_updates/Makefile
@@ -5,3 +5,4 @@
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
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index 5313d07302..4d0c8b84b9 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -15,13 +15,13 @@
#include <linux/errno.h>
#include <linux/types.h>
+#include <u-boot/crc.h>
+
+static struct fwu_mdata g_mdata; /* = {0} makes uninit crc32 always invalid */
+static struct udevice *g_dev;
static u8 in_trial;
static u8 boottime_check;
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <u-boot/crc.h>
-
enum {
IMAGE_ACCEPT_SET = 1,
IMAGE_ACCEPT_CLEAR,
@@ -33,26 +33,6 @@ enum {
BOTH_PARTS,
};
-static int fwu_get_dev_mdata(struct udevice **dev, struct fwu_mdata *mdata)
-{
- int ret;
-
- ret = uclass_first_device_err(UCLASS_FWU_MDATA, dev);
- if (ret) {
- log_debug("Cannot find fwu device\n");
- return ret;
- }
-
- if (!mdata)
- return 0;
-
- ret = fwu_get_mdata(*dev, mdata);
- if (ret < 0)
- log_debug("Unable to get valid FWU metadata\n");
-
- return ret;
-}
-
static int trial_counter_update(u16 *trial_state_ctr)
{
bool delete;
@@ -115,6 +95,8 @@ static int fwu_trial_count_update(void)
log_err("Unable to revert active_index\n");
ret = 1;
} else {
+ log_info("Trial State count: attempt %d out of %d\n",
+ trial_state_ctr, CONFIG_FWU_TRIAL_STATE_CNT);
ret = trial_counter_update(&trial_state_ctr);
if (ret)
log_err("Unable to increment TrialStateCtr variable\n");
@@ -151,7 +133,7 @@ static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
index = *image_index;
image = update_info.images;
- for (i = 0; i < num_image_type_guids; i++) {
+ for (i = 0; i < update_info.num_images; i++) {
if (index == image[i].image_index) {
guidcpy(image_type_id, &image[i].image_type_id);
return 0;
@@ -162,133 +144,124 @@ static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
}
/**
- * fwu_verify_mdata() - Verify the FWU metadata
+ * fwu_sync_mdata() - Update given meta-data partition(s) with the copy provided
* @mdata: FWU metadata structure
- * @pri_part: FWU metadata partition is primary or secondary
- *
- * Verify the FWU metadata by computing the CRC32 for the metadata
- * structure and comparing it against the CRC32 value stored as part
- * of the structure.
+ * @part: Bitmask of FWU metadata partitions to be written to
*
* Return: 0 if OK, -ve on error
- *
*/
-int fwu_verify_mdata(struct fwu_mdata *mdata, bool pri_part)
+static int fwu_sync_mdata(struct fwu_mdata *mdata, int part)
{
- u32 calc_crc32;
- void *buf;
+ void *buf = &mdata->version;
+ int err;
+
+ if (part == BOTH_PARTS) {
+ err = fwu_sync_mdata(mdata, SECONDARY_PART);
+ if (err)
+ return err;
+ part = PRIMARY_PART;
+ }
- buf = &mdata->version;
- calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+ /*
+ * 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));
- if (calc_crc32 != mdata->crc32) {
- log_debug("crc32 check failed for %s FWU metadata partition\n",
- pri_part ? "primary" : "secondary");
- return -EINVAL;
+ err = fwu_write_mdata(g_dev, mdata, part == PRIMARY_PART);
+ 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)
+{
+ void *buf = &mdata->version;
+ u32 calc_crc32 = crc32(0, buf, sizeof(*mdata) - sizeof(u32));
+
+ return calc_crc32 == mdata->crc32 ? 0 : -EINVAL;
+}
+
/**
- * fwu_check_mdata_validity() - Check for validity of the FWU metadata copies
+ * fwu_get_mdata() - Read, verify and return the FWU metadata
+ * @mdata: Output FWU metadata read or NULL
*
* Read both the metadata copies from the storage media, verify their checksum,
* and ascertain that both copies match. If one of the copies has gone bad,
* restore it from the good copy.
*
* Return: 0 if OK, -ve on error
- *
*/
-int fwu_check_mdata_validity(void)
+int fwu_get_mdata(struct fwu_mdata *mdata)
{
- int ret;
- struct udevice *dev;
- struct fwu_mdata pri_mdata;
- struct fwu_mdata secondary_mdata;
- uint mdata_parts[2];
- uint valid_partitions, invalid_partitions;
-
- ret = fwu_get_dev_mdata(&dev, NULL);
- if (ret)
- return ret;
-
- /*
- * Check if the platform has defined its own
- * function to check the metadata partitions'
- * validity. If so, that takes precedence.
- */
- ret = fwu_mdata_check(dev);
- if (!ret || ret != -ENOSYS)
- return ret;
-
- /*
- * Two FWU metadata partitions are expected.
- * If we don't have two, user needs to create
- * them first
- */
- valid_partitions = 0;
- ret = fwu_get_mdata_part_num(dev, mdata_parts);
- if (ret < 0) {
- log_debug("Error getting the FWU metadata partitions\n");
- return -ENOENT;
- }
-
- ret = fwu_read_mdata_partition(dev, &pri_mdata, mdata_parts[0]);
- if (!ret) {
- ret = fwu_verify_mdata(&pri_mdata, 1);
- if (!ret)
- valid_partitions |= PRIMARY_PART;
- }
-
- ret = fwu_read_mdata_partition(dev, &secondary_mdata, mdata_parts[1]);
- if (!ret) {
- ret = fwu_verify_mdata(&secondary_mdata, 0);
- if (!ret)
- valid_partitions |= SECONDARY_PART;
+ int err;
+ bool parts_ok[2] = { false };
+ struct fwu_mdata s, *parts_mdata[2];
+
+ parts_mdata[0] = &g_mdata;
+ parts_mdata[1] = &s;
+
+ /* 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 */
+
+ for (int i = 0; i < 2; i++) {
+ parts_ok[i] = false;
+ err = fwu_read_mdata(g_dev, parts_mdata[i], !i);
+ if (!err) {
+ err = mdata_crc_check(parts_mdata[i]);
+ if (!err)
+ parts_ok[i] = true;
+ else
+ log_debug("mdata : %s crc32 failed\n", i ? "secondary" : "primary");
+ }
}
- if (valid_partitions == (PRIMARY_PART | SECONDARY_PART)) {
+ if (parts_ok[0] && parts_ok[1]) {
/*
* Before returning, check that both the
- * FWU metadata copies are the same. If not,
- * populate the secondary partition from the
+ * FWU metadata copies are the same.
+ */
+ err = memcmp(parts_mdata[0], parts_mdata[1], sizeof(struct fwu_mdata));
+ if (!err)
+ goto ret_mdata;
+
+ /*
+ * If not, populate the secondary partition from the
* primary partition copy.
*/
- if (!memcmp(&pri_mdata, &secondary_mdata,
- sizeof(struct fwu_mdata))) {
- ret = 0;
- } else {
- log_info("Both FWU metadata copies are valid but do not match.");
- log_info(" Restoring the secondary partition from the primary\n");
- ret = fwu_write_mdata_partition(dev, &pri_mdata,
- mdata_parts[1]);
- if (ret)
- log_debug("Restoring secondary FWU metadata partition failed\n");
- }
- goto out;
+ log_info("Both FWU metadata copies are valid but do not match.");
+ log_info(" Restoring the secondary partition from the primary\n");
+ parts_ok[1] = false;
}
- if (!(valid_partitions & BOTH_PARTS)) {
- log_info("Both FWU metadata partitions invalid\n");
- ret = -EBADMSG;
- goto out;
- }
+ for (int i = 0; i < 2; i++) {
+ if (parts_ok[i])
+ continue;
- invalid_partitions = valid_partitions ^ BOTH_PARTS;
- ret = fwu_write_mdata_partition(dev,
- (invalid_partitions == PRIMARY_PART) ?
- &secondary_mdata : &pri_mdata,
- (invalid_partitions == PRIMARY_PART) ?
- mdata_parts[0] : mdata_parts[1]);
+ memcpy(parts_mdata[i], parts_mdata[1 - i], sizeof(struct fwu_mdata));
+ err = fwu_sync_mdata(parts_mdata[i], i ? SECONDARY_PART : PRIMARY_PART);
+ if (err) {
+ log_debug("mdata : %s write failed\n", i ? "secondary" : "primary");
+ return err;
+ }
+ }
- if (ret)
- log_debug("Restoring %s FWU metadata partition failed\n",
- (invalid_partitions == PRIMARY_PART) ?
- "primary" : "secondary");
+ret_mdata:
+ if (!err && mdata)
+ memcpy(mdata, parts_mdata[0], sizeof(struct fwu_mdata));
-out:
- return ret;
+ return err;
}
/**
@@ -303,19 +276,14 @@ out:
*/
int fwu_get_active_index(uint *active_idx)
{
- int ret;
- struct udevice *dev;
- struct fwu_mdata mdata = { 0 };
-
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
+ int ret = 0;
+ struct fwu_mdata *mdata = &g_mdata;
/*
* Found the FWU metadata partition, now read the active_index
* value
*/
- *active_idx = mdata.active_index;
+ *active_idx = mdata->active_index;
if (*active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Active index value read is incorrect\n");
ret = -EINVAL;
@@ -336,30 +304,25 @@ int fwu_get_active_index(uint *active_idx)
int fwu_set_active_index(uint active_idx)
{
int ret;
- struct udevice *dev;
- struct fwu_mdata mdata = { 0 };
+ struct fwu_mdata *mdata = &g_mdata;
if (active_idx >= CONFIG_FWU_NUM_BANKS) {
log_debug("Invalid active index value\n");
return -EINVAL;
}
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
-
/*
* 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;
+ mdata->previous_active_index = mdata->active_index;
+ mdata->active_index = active_idx;
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_update_mdata(dev, &mdata);
+ ret = fwu_sync_mdata(mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -389,15 +352,10 @@ int fwu_get_image_index(u8 *image_index)
u8 alt_num;
uint update_bank;
efi_guid_t *image_guid, image_type_id;
- struct udevice *dev;
- struct fwu_mdata mdata = { 0 };
+ struct fwu_mdata *mdata = &g_mdata;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
-
ret = fwu_plat_get_update_index(&update_bank);
if (ret) {
log_debug("Failed to get the FWU update bank\n");
@@ -418,11 +376,11 @@ int fwu_get_image_index(u8 *image_index)
*/
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];
+ &mdata->img_entry[i].image_type_uuid)) {
+ img_entry = &mdata->img_entry[i];
img_bank_info = &img_entry->img_bank_info[update_bank];
image_guid = &img_bank_info->image_uuid;
- ret = fwu_plat_get_alt_num(dev, image_guid, &alt_num);
+ 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",
image_guid);
@@ -436,8 +394,8 @@ int fwu_get_image_index(u8 *image_index)
}
}
- log_debug("Partition with the image type %pUs not found\n",
- &image_type_id);
+ log_err("Partition with the image type %pUs not found\n",
+ &image_type_id);
out:
return ret;
@@ -457,26 +415,21 @@ int fwu_revert_boot_index(void)
{
int ret;
u32 cur_active_index;
- struct udevice *dev;
- struct fwu_mdata mdata = { 0 };
-
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
+ struct fwu_mdata *mdata = &g_mdata;
/*
* 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 = mdata->active_index;
+ mdata->active_index = mdata->previous_active_index;
+ mdata->previous_active_index = cur_active_index;
/*
* Now write this updated FWU metadata to both the
* FWU metadata partitions
*/
- ret = fwu_update_mdata(dev, &mdata);
+ ret = fwu_sync_mdata(mdata, BOTH_PARTS);
if (ret) {
log_debug("Failed to update FWU metadata partitions\n");
ret = -EIO;
@@ -503,16 +456,11 @@ 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 udevice *dev;
- struct fwu_mdata mdata = { 0 };
+ struct fwu_mdata *mdata = &g_mdata;
struct fwu_image_entry *img_entry;
struct fwu_image_bank_info *img_bank_info;
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
-
- img_entry = &mdata.img_entry[0];
+ img_entry = &mdata->img_entry[0];
for (i = 0; i < CONFIG_FWU_NUM_IMAGES_PER_BANK; i++) {
if (!guidcmp(&img_entry[i].image_type_uuid, img_type_id)) {
img_bank_info = &img_entry[i].img_bank_info[bank];
@@ -521,7 +469,7 @@ static int fwu_clrset_image_accept(efi_guid_t *img_type_id, u32 bank, u8 action)
else
img_bank_info->accepted = 0;
- ret = fwu_update_mdata(dev, &mdata);
+ ret = fwu_sync_mdata(mdata, BOTH_PARTS);
goto out;
}
}
@@ -600,6 +548,24 @@ __weak int fwu_plat_get_update_index(uint *update_idx)
}
/**
+ * fwu_plat_get_bootidx() - Get the value of the boot index
+ * @boot_idx: Boot index value
+ *
+ * Get the value of the bank(partition) from which the platform
+ * has booted. This value is passed to U-Boot from the earlier
+ * stage bootloader which loads and boots all the relevant
+ * firmware images
+ */
+__weak void fwu_plat_get_bootidx(uint *boot_idx)
+{
+ int ret;
+
+ ret = fwu_get_active_index(boot_idx);
+ if (ret < 0)
+ *boot_idx = 0; /* Dummy value */
+}
+
+/**
* fwu_update_checks_pass() - Check if FWU update can be done
*
* Check if the FWU update can be executed. The updates are
@@ -656,8 +622,6 @@ static int fwu_boottime_checks(void *ctx, struct event *event)
{
int ret;
u32 boot_idx, active_idx;
- struct udevice *dev;
- struct fwu_mdata mdata = { 0 };
/* Don't have boot time checks on sandbox */
if (IS_ENABLED(CONFIG_SANDBOX)) {
@@ -665,9 +629,17 @@ static int fwu_boottime_checks(void *ctx, struct event *event)
return 0;
}
- ret = fwu_check_mdata_validity();
- if (ret)
- return 0;
+ ret = uclass_first_device_err(UCLASS_FWU_MDATA, &g_dev);
+ if (ret) {
+ log_debug("Cannot find fwu device\n");
+ return ret;
+ }
+
+ ret = fwu_get_mdata(NULL);
+ if (ret) {
+ log_debug("Unable to read meta-data\n");
+ return ret;
+ }
/*
* Get the Boot Index, i.e. the bank from
@@ -696,18 +668,12 @@ static int fwu_boottime_checks(void *ctx, struct event *event)
ret = fwu_set_active_index(boot_idx);
if (!ret)
boottime_check = 1;
-
- return 0;
}
if (efi_init_obj_list() != EFI_SUCCESS)
return 0;
- ret = fwu_get_dev_mdata(&dev, &mdata);
- if (ret)
- return ret;
-
- in_trial = in_trial_state(&mdata);
+ in_trial = in_trial_state(&g_mdata);
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
new file mode 100644
index 0000000000..69cd3d7001
--- /dev/null
+++ b/lib/fwu_updates/fwu_mtd.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dm.h>
+#include <dfu.h>
+#include <fwu.h>
+#include <fwu_mdata.h>
+#include <log.h>
+#include <malloc.h>
+#include <mtd.h>
+#include <uuid.h>
+#include <vsprintf.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);
+
+ for (int i = 0; i < num_images; i++)
+ if (!strcmp(uuidbuf, fwu_mtd_images[i].uuidbuf))
+ return &fwu_mtd_images[i];
+
+ return NULL;
+}
+
+int fwu_mtd_get_alt_num(efi_guid_t *image_id, u8 *alt_num,
+ const char *mtd_dev)
+{
+ struct fwu_mtd_image_info *mtd_img_info;
+ char uuidbuf[UUID_STR_LEN + 1];
+ fdt_addr_t offset, size = 0;
+ struct dfu_entity *dfu;
+ int i, nalt, ret;
+
+ mtd_probe_devices();
+
+ uuid_bin_to_str(image_id->b, uuidbuf, UUID_STR_FORMAT_STD);
+
+ mtd_img_info = mtd_img_by_uuid(uuidbuf);
+ if (!mtd_img_info) {
+ log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
+ return -ENOENT;
+ }
+
+ offset = mtd_img_info->start;
+ size = mtd_img_info->size;
+
+ ret = dfu_init_env_entities(NULL, NULL);
+ if (ret)
+ return -ENOENT;
+
+ nalt = 0;
+ list_for_each_entry(dfu, &dfu_list, list)
+ nalt++;
+
+ if (!nalt) {
+ log_warning("No entities in dfu_alt_info\n");
+ dfu_free_entities();
+ return -ENOENT;
+ }
+
+ ret = -ENOENT;
+ for (i = 0; i < nalt; i++) {
+ dfu = dfu_get_entity(i);
+
+ /* Only MTD RAW access */
+ if (!dfu || dfu->dev_type != DFU_DEV_MTD ||
+ dfu->layout != DFU_RAW_ADDR ||
+ dfu->data.mtd.start != offset ||
+ dfu->data.mtd.size != size)
+ continue;
+
+ *alt_num = dfu->alt;
+ ret = 0;
+ break;
+ }
+
+ dfu_free_entities();
+
+ log_debug("%s: %s -> %d\n", __func__, uuidbuf, *alt_num);
+ return ret;
+}
+
+/**
+ * fwu_plat_get_alt_num() - Get the DFU Alt Num for the image from the platform
+ * @dev: FWU device
+ * @image_id: Image GUID for which DFU alt number needs to be retrieved
+ * @alt_num: Pointer to the alt_num
+ *
+ * Get the DFU alt number from the platform for the image specified by the
+ * image GUID.
+ *
+ * Note: This is a weak function and platforms can override this with
+ * their own implementation for obtaining the alt number value.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+__weak int fwu_plat_get_alt_num(struct udevice *dev, efi_guid_t *image_id,
+ u8 *alt_num)
+{
+ return fwu_mtd_get_alt_num(image_id, alt_num, "nor1");
+}
+
+static int gen_image_alt_info(char *buf, size_t len, int sidx,
+ struct fwu_image_entry *img, struct mtd_info *mtd)
+{
+ char *p = buf, *end = buf + len;
+ int i;
+
+ p += snprintf(p, end - p, "mtd %s", mtd->name);
+ if (end < p) {
+ log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
+ return -E2BIG;
+ }
+
+ /*
+ * List the image banks in the FWU mdata and search the corresponding
+ * partition based on partition's uuid.
+ */
+ for (i = 0; i < CONFIG_FWU_NUM_BANKS; i++) {
+ struct fwu_mtd_image_info *mtd_img_info;
+ struct fwu_image_bank_info *bank;
+ char uuidbuf[UUID_STR_LEN + 1];
+ u32 offset, size;
+
+ /* 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);
+
+ mtd_img_info = mtd_img_by_uuid(uuidbuf);
+ if (!mtd_img_info) {
+ log_err("%s: Not found partition for image %s\n", __func__, uuidbuf);
+ break;
+ }
+
+ offset = mtd_img_info->start;
+ size = mtd_img_info->size;
+
+ p += snprintf(p, end - p, "%sbank%d raw %x %x",
+ i == 0 ? "=" : ";", i, offset, size);
+ if (end < p) {
+ log_err("%s:%d Run out of buffer\n", __func__, __LINE__);
+ return -E2BIG;
+ }
+ }
+
+ if (i == CONFIG_FWU_NUM_BANKS)
+ return 0;
+
+ return -ENOENT;
+}
+
+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;
+ }
+
+ 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);
+ if (ret)
+ break;
+
+ l = strlen(buf);
+ /* Replace the last ';' with '&' if there is another image. */
+ if (i != CONFIG_FWU_NUM_IMAGES_PER_BANK - 1 && l) {
+ buf[l] = '&';
+ buf++;
+ }
+ len -= l;
+ buf += l;
+ }
+
+ return ret;
+}
diff --git a/lib/image-sparse.c b/lib/image-sparse.c
index 5ec0f94ab3..8f8a67e158 100644
--- a/lib/image-sparse.c
+++ b/lib/image-sparse.c
@@ -55,7 +55,8 @@ static lbaint_t write_sparse_chunk_raw(struct sparse_storage *info,
void *data,
char *response)
{
- lbaint_t n = blkcnt, write_blks, blks = 0, aligned_buf_blks = 100;
+ lbaint_t n = blkcnt, write_blks, blks = 0;
+ lbaint_t aligned_buf_blks = FASTBOOT_MAX_BLK_WRITE;
uint32_t *aligned_buf = NULL;
if (CONFIG_IS_ENABLED(SYS_DCACHE_OFF)) {
diff --git a/lib/lzma/LzmaDec.c b/lib/lzma/LzmaDec.c
index 341149f766..a90b35c6a9 100644
--- a/lib/lzma/LzmaDec.c
+++ b/lib/lzma/LzmaDec.c
@@ -152,8 +152,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
const Byte *buf = p->buf;
UInt32 range = p->range;
UInt32 code = p->code;
-
- schedule();
+ unsigned int loop = 0;
do
{
@@ -162,6 +161,9 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
unsigned ttt;
unsigned posState = processedPos & pbMask;
+ if (!(loop++ & 1023))
+ schedule();
+
prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
IF_BIT_0(prob)
{
@@ -177,8 +179,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
state -= (state < 4) ? state : 3;
symbol = 1;
- schedule();
-
do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
}
else
@@ -188,8 +188,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
state -= (state < 10) ? 3 : 6;
symbol = 1;
- schedule();
-
do
{
unsigned bit;
@@ -321,8 +319,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
UInt32 mask = 1;
unsigned i = 1;
- schedule();
-
do
{
GET_BIT2(prob + i, i, ; , distance |= mask);
@@ -335,8 +331,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
{
numDirectBits -= kNumAlignBits;
- schedule();
-
do
{
NORMALIZE
@@ -409,8 +403,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
const Byte *lim = dest + curLen;
dicPos += curLen;
- schedule();
-
do
*(dest) = (Byte)*(dest + src);
while (++dest != lim);
@@ -418,8 +410,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte
else
{
- schedule();
-
do
{
dic[dicPos++] = dic[pos];
diff --git a/lib/of_live.c b/lib/of_live.c
index 1b5964d09a..25f7af6106 100644
--- a/lib/of_live.c
+++ b/lib/of_live.c
@@ -287,9 +287,12 @@ int unflatten_device_tree(const void *blob, struct device_node **mynodes)
debug(" size is %lx, allocating...\n", size);
/* Allocate memory for the expanded device tree */
- mem = malloc(size + 4);
+ mem = memalign(__alignof__(struct device_node), size + 4);
memset(mem, '\0', size);
+ /* Set up value for dm_test_livetree_align() */
+ *(u32 *)mem = BAD_OF_ROOT;
+
*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
debug(" unflattening %p...\n", mem);
@@ -327,3 +330,9 @@ int of_live_build(const void *fdt_blob, struct device_node **rootp)
return ret;
}
+
+void of_live_free(struct device_node *root)
+{
+ /* the tree is stored as a contiguous block of memory */
+ free(root);
+}
diff --git a/lib/uuid.c b/lib/uuid.c
index 96e1af3c8b..d0187007d0 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2011 Calxeda, Inc.
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
@@ -255,7 +259,7 @@ static const struct {
EFI_CERT_TYPE_PKCS7_GUID,
},
#endif
-#ifdef CONFIG_EFI
+#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI)
{ "EFI_LZMA_COMPRESSED", EFI_LZMA_COMPRESSED },
{ "EFI_DXE_SERVICES", EFI_DXE_SERVICES },
{ "EFI_HOB_LIST", EFI_HOB_LIST },
@@ -354,6 +358,50 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
return 0;
}
+/**
+ * uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
+ * @uuid_str: pointer to UUID string
+ * @uuid_bin: pointer to allocated array for little endian output [16B]
+ *
+ * UUID string is 36 characters (36 bytes):
+ *
+ * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ *
+ * where x is a hexadecimal character. Fields are separated by '-'s.
+ * When converting to a little endian binary UUID, the string fields are reversed.
+ *
+ * Return:
+ *
+ * uuid_bin filled with little endian UUID data
+ * On success 0 is returned. Otherwise, failure code.
+ */
+int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin)
+{
+ u16 tmp16;
+ u32 tmp32;
+ u64 tmp64;
+
+ if (!uuid_str_valid(uuid_str) || !uuid_bin)
+ return -EINVAL;
+
+ tmp32 = cpu_to_le32(hextoul(uuid_str, NULL));
+ memcpy(uuid_bin, &tmp32, 4);
+
+ tmp16 = cpu_to_le16(hextoul(uuid_str + 9, NULL));
+ memcpy(uuid_bin + 4, &tmp16, 2);
+
+ tmp16 = cpu_to_le16(hextoul(uuid_str + 14, NULL));
+ memcpy(uuid_bin + 6, &tmp16, 2);
+
+ tmp16 = cpu_to_le16(hextoul(uuid_str + 19, NULL));
+ memcpy(uuid_bin + 8, &tmp16, 2);
+
+ tmp64 = cpu_to_le64(simple_strtoull(uuid_str + 24, NULL, 16));
+ memcpy(uuid_bin + 10, &tmp64, 6);
+
+ return 0;
+}
+
/*
* uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
*
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e87503e41a..e14c6ca9f9 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -680,8 +680,10 @@ repeat:
break;
case 'd':
- if (fmt[1] == 'E')
+ if (fmt[1] == 'E') {
flags |= ERRSTR;
+ fmt++;
+ }
/* fallthrough */
case 'i':
flags |= SIGN;
@@ -725,7 +727,6 @@ repeat:
ADDCH(str, ' ');
for (p = errno_str(num); *p; p++)
ADDCH(str, *p);
- fmt++;
}
}
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
index 30dfe15599..8f767b7b9d 100644
--- a/lib/zlib/inflate.c
+++ b/lib/zlib/inflate.c
@@ -455,8 +455,9 @@ int ZEXPORT inflate(z_streamp strm, int flush)
if (copy > have) copy = have;
if (copy) {
if (state->head != Z_NULL &&
- state->head->extra != Z_NULL) {
- len = state->head->extra_len - state->length;
+ state->head->extra != Z_NULL &&
+ (len = state->head->extra_len - state->length) <
+ state->head->extra_max) {
zmemcpy(state->head->extra + len, next,
len + copy > state->head->extra_max ?
state->head->extra_max - len : copy);