aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/efi/Makefile2
-rw-r--r--lib/efi/efi_app.c187
-rw-r--r--lib/efi/efi_app_init.c205
-rw-r--r--lib/efi_loader/Kconfig11
-rw-r--r--lib/efi_loader/Makefile10
-rw-r--r--lib/efi_loader/efi_bootbin.c211
-rw-r--r--lib/efi_loader/efi_bootmgr.c490
-rw-r--r--lib/efi_loader/efi_boottime.c2
-rw-r--r--lib/efi_loader/efi_device_path.c73
-rw-r--r--lib/efi_loader/efi_device_path_utilities.c2
-rw-r--r--lib/efi_loader/efi_disk.c15
-rw-r--r--lib/efi_loader/efi_esrt.c18
-rw-r--r--lib/efi_loader/efi_firmware.c86
-rw-r--r--lib/efi_loader/efi_helper.c286
-rw-r--r--lib/efi_loader/efi_smbios.c7
-rw-r--r--lib/efi_loader/smbiosdump.c622
-rw-r--r--lib/fwu_updates/fwu.c32
-rw-r--r--lib/membuff.c4
-rw-r--r--lib/rsa/rsa-sign.c46
-rw-r--r--lib/smbios-parser.c32
-rw-r--r--lib/smbios.c57
-rw-r--r--lib/tables_csum.c4
22 files changed, 1549 insertions, 853 deletions
diff --git a/lib/efi/Makefile b/lib/efi/Makefile
index a790d2d554..232fa68436 100644
--- a/lib/efi/Makefile
+++ b/lib/efi/Makefile
@@ -2,7 +2,7 @@
#
# (C) Copyright 2015 Google, Inc
-obj-$(CONFIG_EFI_APP) += efi_app.o efi.o
+obj-$(CONFIG_EFI_APP) += efi_app.o efi.o efi_app_init.o
obj-$(CONFIG_EFI_STUB) += efi_info.o
CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index 119db6602c..88332c3c91 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -67,49 +67,6 @@ int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp,
return 0;
}
-/**
- * efi_bind_block() - bind a new block device to an EFI device
- *
- * Binds a new top-level EFI_MEDIA device as well as a child block device so
- * that the block device can be accessed in U-Boot.
- *
- * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- * for example, just like any other interface type.
- *
- * @handle: handle of the controller on which this driver is installed
- * @blkio: block io protocol proxied by this driver
- * @device_path: EFI device path structure for this
- * @len: Length of @device_path in bytes
- * @devp: Returns the bound device
- * Return: 0 if OK, -ve on error
- */
-int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
- struct efi_device_path *device_path, int len,
- struct udevice **devp)
-{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
-
- plat.handle = handle;
- plat.blkio = blkio;
- plat.device_path = malloc(device_path->length);
- if (!plat.device_path)
- return log_msg_ret("path", -ENOMEM);
- memcpy(plat.device_path, device_path, device_path->length);
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
- &plat, ofnode_null(), &dev);
- if (ret)
- return log_msg_ret("bind", ret);
-
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- *devp = dev;
-
- return 0;
-}
-
static efi_status_t setup_memory(struct efi_priv *priv)
{
struct efi_boot_services *boot = priv->boot;
@@ -178,150 +135,6 @@ static void free_memory(struct efi_priv *priv)
global_data_ptr = NULL;
}
-/**
- * devpath_is_partition() - Figure out if a device path is a partition
- *
- * Checks if a device path refers to a partition on some media device. This
- * works by checking for a valid partition number in a hard-driver media device
- * as the final component of the device path.
- *
- * @path: device path
- * Return: true if a partition, false if not
- * (e.g. it might be media which contains partitions)
- */
-static bool devpath_is_partition(const struct efi_device_path *path)
-{
- const struct efi_device_path *p;
- bool was_part = false;
-
- for (p = path; p->type != DEVICE_PATH_TYPE_END;
- p = (void *)p + p->length) {
- was_part = false;
- if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
- p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
- struct efi_device_path_hard_drive_path *hd =
- (void *)path;
-
- if (hd->partition_number)
- was_part = true;
- }
- }
-
- return was_part;
-}
-
-/**
- * setup_block() - Find all block devices and setup EFI devices for them
- *
- * Partitions are ignored, since U-Boot has partition handling. Errors with
- * particular devices produce a warning but execution continues to try to
- * find others.
- *
- * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
- * if a required protocol is not supported
- */
-static int setup_block(void)
-{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
- efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_device_path_utilities_protocol *util;
- struct efi_device_path_to_text_protocol *text;
- struct efi_device_path *path;
- struct efi_block_io *blkio;
- efi_uintn_t num_handles;
- efi_handle_t *handle;
- int ret, i;
-
- if (!boot)
- return log_msg_ret("sys", -ENOSYS);
-
- /* Find all devices which support the block I/O protocol */
- ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
- &num_handles, &handle);
- if (ret)
- return log_msg_ret("loc", -ENOTSUPP);
- log_debug("Found %d handles:\n", (int)num_handles);
-
- /* We need to look up the path size and convert it to text */
- ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
- if (ret)
- return log_msg_ret("util", -ENOTSUPP);
- ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
- if (ret)
- return log_msg_ret("text", -ENOTSUPP);
-
- for (i = 0; i < num_handles; i++) {
- struct udevice *dev;
- const u16 *name;
- bool is_part;
- int len;
-
- ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
- (void **)&path);
- if (ret) {
- log_warning("- devpath %d failed (ret=%d)\n", i, ret);
- continue;
- }
-
- ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
- (void **)&blkio);
- if (ret) {
- log_warning("- blkio %d failed (ret=%d)\n", i, ret);
- continue;
- }
-
- name = text->convert_device_path_to_text(path, true, false);
- is_part = devpath_is_partition(path);
-
- if (!is_part) {
- len = util->get_device_path_size(path);
- ret = efi_bind_block(handle[i], blkio, path, len, &dev);
- if (ret) {
- log_warning("- blkio bind %d failed (ret=%d)\n",
- i, ret);
- continue;
- }
- } else {
- dev = NULL;
- }
-
- /*
- * Show the device name if we created one. Otherwise indicate
- * that it is a partition.
- */
- printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
- name);
- }
- boot->free_pool(handle);
-
- return 0;
-}
-
-/**
- * dm_scan_other() - Scan for UEFI devices that should be available to U-Boot
- *
- * This sets up block devices within U-Boot for those found in UEFI. With this,
- * U-Boot can access those devices
- *
- * @pre_reloc_only: true to only bind pre-relocation devices (ignored)
- * Returns: 0 on success, -ve on error
- */
-int dm_scan_other(bool pre_reloc_only)
-{
- if (gd->flags & GD_FLG_RELOC) {
- int ret;
-
- ret = setup_block();
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static void scan_tables(struct efi_system_table *sys_table)
{
efi_guid_t acpi = EFI_ACPI_TABLE_GUID;
diff --git a/lib/efi/efi_app_init.c b/lib/efi/efi_app_init.c
new file mode 100644
index 0000000000..c5e4192fe0
--- /dev/null
+++ b/lib/efi/efi_app_init.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI-app board implementation
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <dm.h>
+#include <efi.h>
+#include <efi_api.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+#include <linux/types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * efi_bind_block() - bind a new block device to an EFI device
+ *
+ * Binds a new top-level EFI_MEDIA device as well as a child block device so
+ * that the block device can be accessed in U-Boot.
+ *
+ * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
+ * for example, just like any other interface type.
+ *
+ * @handle: handle of the controller on which this driver is installed
+ * @blkio: block io protocol proxied by this driver
+ * @device_path: EFI device path structure for this
+ * @len: Length of @device_path in bytes
+ * @devp: Returns the bound device
+ * Return: 0 if OK, -ve on error
+ */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
+ struct efi_device_path *device_path, int len,
+ struct udevice **devp)
+{
+ struct efi_media_plat plat;
+ struct udevice *dev;
+ char name[18];
+ int ret;
+
+ plat.handle = handle;
+ plat.blkio = blkio;
+ plat.device_path = malloc(device_path->length);
+ if (!plat.device_path)
+ return log_msg_ret("path", -ENOMEM);
+ memcpy(plat.device_path, device_path, device_path->length);
+ ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
+ &plat, ofnode_null(), &dev);
+ if (ret)
+ return log_msg_ret("bind", ret);
+
+ snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
+ device_set_name(dev, name);
+ *devp = dev;
+
+ return 0;
+}
+
+/**
+ * devpath_is_partition() - Figure out if a device path is a partition
+ *
+ * Checks if a device path refers to a partition on some media device. This
+ * works by checking for a valid partition number in a hard-driver media device
+ * as the final component of the device path.
+ *
+ * @path: device path
+ * Return: true if a partition, false if not
+ * (e.g. it might be media which contains partitions)
+ */
+static bool devpath_is_partition(const struct efi_device_path *path)
+{
+ const struct efi_device_path *p;
+ bool was_part = false;
+
+ for (p = path; p->type != DEVICE_PATH_TYPE_END;
+ p = (void *)p + p->length) {
+ was_part = false;
+ if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
+ p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
+ struct efi_device_path_hard_drive_path *hd =
+ (void *)path;
+
+ if (hd->partition_number)
+ was_part = true;
+ }
+ }
+
+ return was_part;
+}
+
+/**
+ * setup_block() - Find all block devices and setup EFI devices for them
+ *
+ * Partitions are ignored, since U-Boot has partition handling. Errors with
+ * particular devices produce a warning but execution continues to try to
+ * find others.
+ *
+ * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
+ * if a required protocol is not supported
+ */
+static int setup_block(void)
+{
+ efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
+ efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
+ efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
+ efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+ struct efi_boot_services *boot = efi_get_boot();
+ struct efi_device_path_utilities_protocol *util;
+ struct efi_device_path_to_text_protocol *text;
+ struct efi_device_path *path;
+ struct efi_block_io *blkio;
+ efi_uintn_t num_handles;
+ efi_handle_t *handle;
+ int ret, i;
+
+ if (!boot)
+ return log_msg_ret("sys", -ENOSYS);
+
+ /* Find all devices which support the block I/O protocol */
+ ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
+ &num_handles, &handle);
+ if (ret)
+ return log_msg_ret("loc", -ENOTSUPP);
+ log_debug("Found %d handles:\n", (int)num_handles);
+
+ /* We need to look up the path size and convert it to text */
+ ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
+ if (ret)
+ return log_msg_ret("util", -ENOTSUPP);
+ ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
+ if (ret)
+ return log_msg_ret("text", -ENOTSUPP);
+
+ for (i = 0; i < num_handles; i++) {
+ struct udevice *dev;
+ const u16 *name;
+ bool is_part;
+ int len;
+
+ ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
+ (void **)&path);
+ if (ret) {
+ log_warning("- devpath %d failed (ret=%d)\n", i, ret);
+ continue;
+ }
+
+ ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
+ (void **)&blkio);
+ if (ret) {
+ log_warning("- blkio %d failed (ret=%d)\n", i, ret);
+ continue;
+ }
+
+ name = text->convert_device_path_to_text(path, true, false);
+ is_part = devpath_is_partition(path);
+
+ if (!is_part) {
+ len = util->get_device_path_size(path);
+ ret = efi_bind_block(handle[i], blkio, path, len, &dev);
+ if (ret) {
+ log_warning("- blkio bind %d failed (ret=%d)\n",
+ i, ret);
+ continue;
+ }
+ } else {
+ dev = NULL;
+ }
+
+ /*
+ * Show the device name if we created one. Otherwise indicate
+ * that it is a partition.
+ */
+ printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
+ name);
+ }
+ boot->free_pool(handle);
+
+ return 0;
+}
+
+/**
+ * board_early_init_r() - Scan for UEFI devices that should be available
+ *
+ * This sets up block devices within U-Boot for those found in UEFI. With this,
+ * U-Boot can access those devices
+ *
+ * Returns: 0 on success, -ve on error
+ */
+int board_early_init_r(void)
+{
+ if (gd->flags & GD_FLG_RELOC) {
+ int ret;
+
+ ret = setup_block();
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index ea807342f0..db5571de1d 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -32,7 +32,16 @@ config EFI_LOADER
if EFI_LOADER
-config BOOTEFI_BOOTMGR
+config EFI_BINARY_EXEC
+ bool "Execute UEFI binary"
+ default y
+ help
+ Select this option if you want to execute the UEFI binary after
+ loading it with U-Boot load commands or other methods.
+ You may enable CMD_BOOTEFI_BINARY so that you can use bootefi
+ command to do that.
+
+config EFI_BOOTMGR
bool "UEFI Boot Manager"
default y
select BOOTMETH_GLOBAL if BOOTSTD
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 24d33d5409..fcb0af7e7d 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,6 +16,8 @@ CFLAGS_boothart.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_boothart.o := $(CFLAGS_NON_EFI)
CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI)
+CFLAGS_smbiosdump.o := $(CFLAGS_EFI) -Os -ffreestanding
+CFLAGS_REMOVE_smbiosdump.o := $(CFLAGS_NON_EFI)
CFLAGS_dtbdump.o := $(CFLAGS_EFI) -Os -ffreestanding
CFLAGS_REMOVE_dtbdump.o := $(CFLAGS_NON_EFI)
CFLAGS_initrddump.o := $(CFLAGS_EFI) -Os -ffreestanding
@@ -31,6 +33,11 @@ always += helloworld.efi
targets += helloworld.o
endif
+ifneq ($(CONFIG_GENERATE_SMBIOS_TABLE),)
+always += smbiosdump.efi
+targets += smbiosdump.o
+endif
+
ifeq ($(CONFIG_GENERATE_ACPI_TABLE),)
always += dtbdump.efi
targets += dtbdump.o
@@ -42,7 +49,8 @@ targets += initrddump.o
endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
-obj-$(CONFIG_BOOTEFI_BOOTMGR) += efi_bootmgr.o
+obj-$(CONFIG_EFI_BOOTMGR) += efi_bootmgr.o
+obj-$(CONFIG_EFI_BINARY_EXEC) += efi_bootbin.o
obj-y += efi_boottime.o
obj-y += efi_helper.o
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c
new file mode 100644
index 0000000000..733cc1a61b
--- /dev/null
+++ b/lib/efi_loader/efi_bootbin.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * For the code moved from cmd/bootefi.c
+ * Copyright (c) 2016 Alexander Graf
+ */
+
+#define LOG_CATEGORY LOGC_EFI
+
+#include <charset.h>
+#include <efi.h>
+#include <efi_loader.h>
+#include <env.h>
+#include <image.h>
+#include <log.h>
+#include <malloc.h>
+
+static struct efi_device_path *bootefi_image_path;
+static struct efi_device_path *bootefi_device_path;
+static void *image_addr;
+static size_t image_size;
+
+/**
+ * efi_get_image_parameters() - return image parameters
+ *
+ * @img_addr: address of loaded image in memory
+ * @img_size: size of loaded image
+ */
+void efi_get_image_parameters(void **img_addr, size_t *img_size)
+{
+ *img_addr = image_addr;
+ *img_size = image_size;
+}
+
+/**
+ * efi_clear_bootdev() - clear boot device
+ */
+void efi_clear_bootdev(void)
+{
+ efi_free_pool(bootefi_device_path);
+ efi_free_pool(bootefi_image_path);
+ bootefi_device_path = NULL;
+ bootefi_image_path = NULL;
+ image_addr = NULL;
+ image_size = 0;
+}
+
+/**
+ * efi_set_bootdev() - set boot device
+ *
+ * This function is called when a file is loaded, e.g. via the 'load' command.
+ * We use the path to this file to inform the UEFI binary about the boot device.
+ *
+ * @dev: device, e.g. "MMC"
+ * @devnr: number of the device, e.g. "1:2"
+ * @path: path to file loaded
+ * @buffer: buffer with file loaded
+ * @buffer_size: size of file loaded
+ */
+void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
+ void *buffer, size_t buffer_size)
+{
+ struct efi_device_path *device, *image;
+ efi_status_t ret;
+
+ log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
+ devnr, path, buffer, buffer_size);
+
+ /* Forget overwritten image */
+ if (buffer + buffer_size >= image_addr &&
+ image_addr + image_size >= buffer)
+ efi_clear_bootdev();
+
+ /* Remember only PE-COFF and FIT images */
+ if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
+ if (IS_ENABLED(CONFIG_FIT) &&
+ !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
+ /*
+ * FIT images of type EFI_OS are started via command
+ * bootm. We should not use their boot device with the
+ * bootefi command.
+ */
+ buffer = 0;
+ buffer_size = 0;
+ } else {
+ log_debug("- not remembering image\n");
+ return;
+ }
+ }
+
+ /* efi_set_bootdev() is typically called repeatedly, recover memory */
+ efi_clear_bootdev();
+
+ image_addr = buffer;
+ image_size = buffer_size;
+
+ ret = efi_dp_from_name(dev, devnr, path, &device, &image);
+ if (ret == EFI_SUCCESS) {
+ bootefi_device_path = device;
+ if (image) {
+ /* FIXME: image should not contain device */
+ struct efi_device_path *image_tmp = image;
+
+ efi_dp_split_file_path(image, &device, &image);
+ efi_free_pool(image_tmp);
+ }
+ bootefi_image_path = image;
+ log_debug("- boot device %pD\n", device);
+ if (image)
+ log_debug("- image %pD\n", image);
+ } else {
+ log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
+ efi_clear_bootdev();
+ }
+}
+
+/**
+ * efi_run_image() - run loaded UEFI image
+ *
+ * @source_buffer: memory address of the UEFI image
+ * @source_size: size of the UEFI image
+ * Return: status code
+ */
+efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
+{
+ efi_handle_t mem_handle = NULL, handle;
+ struct efi_device_path *file_path = NULL;
+ struct efi_device_path *msg_path;
+ efi_status_t ret, ret2;
+ u16 *load_options;
+
+ if (!bootefi_device_path || !bootefi_image_path) {
+ log_debug("Not loaded from disk\n");
+ /*
+ * Special case for efi payload not loaded from disk,
+ * such as 'bootefi hello' or for example payload
+ * loaded directly into memory via JTAG, etc:
+ */
+ file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
+ (uintptr_t)source_buffer,
+ source_size);
+ /*
+ * Make sure that device for device_path exist
+ * in load_image(). Otherwise, shell and grub will fail.
+ */
+ ret = efi_install_multiple_protocol_interfaces(&mem_handle,
+ &efi_guid_device_path,
+ file_path, NULL);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ msg_path = file_path;
+ } else {
+ file_path = efi_dp_concat(bootefi_device_path,
+ bootefi_image_path, false);
+ msg_path = bootefi_image_path;
+ log_debug("Loaded from disk\n");
+ }
+
+ log_info("Booting %pD\n", msg_path);
+
+ ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
+ source_size, &handle));
+ if (ret != EFI_SUCCESS) {
+ log_err("Loading image failed\n");
+ goto out;
+ }
+
+ /* Transfer environment variable as load options */
+ ret = efi_env_set_load_options(handle, "bootargs", &load_options);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = do_bootefi_exec(handle, load_options);
+
+out:
+ ret2 = efi_uninstall_multiple_protocol_interfaces(mem_handle,
+ &efi_guid_device_path,
+ file_path, NULL);
+ efi_free_pool(file_path);
+ return (ret != EFI_SUCCESS) ? ret : ret2;
+}
+
+/**
+ * efi_binary_run() - run loaded UEFI image
+ *
+ * @image: memory address of the UEFI image
+ * @size: size of the UEFI image
+ * @fdt: device-tree
+ *
+ * Execute an EFI binary image loaded at @image.
+ * @size may be zero if the binary is loaded with U-Boot load command.
+ *
+ * Return: status code
+ */
+efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
+{
+ efi_status_t ret;
+
+ /* Initialize EFI drivers */
+ ret = efi_init_obj_list();
+ if (ret != EFI_SUCCESS) {
+ log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
+ ret & ~EFI_ERROR_MASK);
+ return -1;
+ }
+
+ ret = efi_install_fdt(fdt);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ return efi_run_image(image, size);
+}
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index a032d3ae04..68d7db5ea3 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -3,8 +3,6 @@
* EFI boot manager
*
* Copyright (c) 2017 Rob Clark
- * For the code moved from cmd/bootefi.c
- * Copyright (c) 2016 Alexander Graf
*/
#define LOG_CATEGORY LOGC_EFI
@@ -21,17 +19,6 @@
#include <efi_variable.h>
#include <asm/unaligned.h>
-/* TODO: temporarily added here; clean up later */
-#include <bootm.h>
-#include <efi_selftest.h>
-#include <env.h>
-#include <mapmem.h>
-#include <asm/global_data.h>
-#include <linux/libfdt.h>
-#include <linux/libfdt_env.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
static const struct efi_boot_services *bs;
static const struct efi_runtime_services *rs;
@@ -143,7 +130,7 @@ static efi_status_t try_load_from_file_path(efi_handle_t *fs_handles,
if (!dp)
continue;
- dp = efi_dp_append(dp, fp);
+ dp = efi_dp_concat(dp, fp, false);
if (!dp)
continue;
@@ -1128,384 +1115,6 @@ out:
return ret;
}
-static struct efi_device_path *bootefi_image_path;
-static struct efi_device_path *bootefi_device_path;
-static void *image_addr;
-static size_t image_size;
-
-/**
- * efi_get_image_parameters() - return image parameters
- *
- * @img_addr: address of loaded image in memory
- * @img_size: size of loaded image
- */
-void efi_get_image_parameters(void **img_addr, size_t *img_size)
-{
- *img_addr = image_addr;
- *img_size = image_size;
-}
-
-/**
- * efi_clear_bootdev() - clear boot device
- */
-void efi_clear_bootdev(void)
-{
- efi_free_pool(bootefi_device_path);
- efi_free_pool(bootefi_image_path);
- bootefi_device_path = NULL;
- bootefi_image_path = NULL;
- image_addr = NULL;
- image_size = 0;
-}
-
-/**
- * efi_set_bootdev() - set boot device
- *
- * This function is called when a file is loaded, e.g. via the 'load' command.
- * We use the path to this file to inform the UEFI binary about the boot device.
- *
- * @dev: device, e.g. "MMC"
- * @devnr: number of the device, e.g. "1:2"
- * @path: path to file loaded
- * @buffer: buffer with file loaded
- * @buffer_size: size of file loaded
- */
-void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
- void *buffer, size_t buffer_size)
-{
- struct efi_device_path *device, *image;
- efi_status_t ret;
-
- log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
- devnr, path, buffer, buffer_size);
-
- /* Forget overwritten image */
- if (buffer + buffer_size >= image_addr &&
- image_addr + image_size >= buffer)
- efi_clear_bootdev();
-
- /* Remember only PE-COFF and FIT images */
- if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
- if (IS_ENABLED(CONFIG_FIT) &&
- !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
- /*
- * FIT images of type EFI_OS are started via command
- * bootm. We should not use their boot device with the
- * bootefi command.
- */
- buffer = 0;
- buffer_size = 0;
- } else {
- log_debug("- not remembering image\n");
- return;
- }
- }
-
- /* efi_set_bootdev() is typically called repeatedly, recover memory */
- efi_clear_bootdev();
-
- image_addr = buffer;
- image_size = buffer_size;
-
- ret = efi_dp_from_name(dev, devnr, path, &device, &image);
- if (ret == EFI_SUCCESS) {
- bootefi_device_path = device;
- if (image) {
- /* FIXME: image should not contain device */
- struct efi_device_path *image_tmp = image;
-
- efi_dp_split_file_path(image, &device, &image);
- efi_free_pool(image_tmp);
- }
- bootefi_image_path = image;
- log_debug("- boot device %pD\n", device);
- if (image)
- log_debug("- image %pD\n", image);
- } else {
- log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
- efi_clear_bootdev();
- }
-}
-
-/**
- * efi_env_set_load_options() - set load options from environment variable
- *
- * @handle: the image handle
- * @env_var: name of the environment variable
- * @load_options: pointer to load options (output)
- * Return: status code
- */
-efi_status_t efi_env_set_load_options(efi_handle_t handle,
- const char *env_var,
- u16 **load_options)
-{
- const char *env = env_get(env_var);
- size_t size;
- u16 *pos;
- efi_status_t ret;
-
- *load_options = NULL;
- if (!env)
- return EFI_SUCCESS;
- size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
- pos = calloc(size, 1);
- if (!pos)
- return EFI_OUT_OF_RESOURCES;
- *load_options = pos;
- utf8_utf16_strcpy(&pos, env);
- ret = efi_set_load_options(handle, size, *load_options);
- if (ret != EFI_SUCCESS) {
- free(*load_options);
- *load_options = NULL;
- }
- return ret;
-}
-
-/**
- * copy_fdt() - Copy the device tree to a new location available to EFI
- *
- * The FDT is copied to a suitable location within the EFI memory map.
- * Additional 12 KiB are added to the space in case the device tree needs to be
- * expanded later with fdt_open_into().
- *
- * @fdtp: On entry a pointer to the flattened device tree.
- * On exit a pointer to the copy of the flattened device tree.
- * FDT start
- * Return: status code
- */
-static efi_status_t copy_fdt(void **fdtp)
-{
- unsigned long fdt_ram_start = -1L, fdt_pages;
- efi_status_t ret = 0;
- void *fdt, *new_fdt;
- u64 new_fdt_addr;
- uint fdt_size;
- int i;
-
- for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
- u64 ram_start = gd->bd->bi_dram[i].start;
- u64 ram_size = gd->bd->bi_dram[i].size;
-
- if (!ram_size)
- continue;
-
- if (ram_start < fdt_ram_start)
- fdt_ram_start = ram_start;
- }
-
- /*
- * Give us at least 12 KiB of breathing room in case the device tree
- * needs to be expanded later.
- */
- fdt = *fdtp;
- fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
- fdt_size = fdt_pages << EFI_PAGE_SHIFT;
-
- ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
- EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
- &new_fdt_addr);
- if (ret != EFI_SUCCESS) {
- log_err("ERROR: Failed to reserve space for FDT\n");
- goto done;
- }
- new_fdt = (void *)(uintptr_t)new_fdt_addr;
- memcpy(new_fdt, fdt, fdt_totalsize(fdt));
- fdt_set_totalsize(new_fdt, fdt_size);
-
- *fdtp = (void *)(uintptr_t)new_fdt_addr;
-done:
- return ret;
-}
-
-/**
- * get_config_table() - get configuration table
- *
- * @guid: GUID of the configuration table
- * Return: pointer to configuration table or NULL
- */
-static void *get_config_table(const efi_guid_t *guid)
-{
- size_t i;
-
- for (i = 0; i < systab.nr_tables; i++) {
- if (!guidcmp(guid, &systab.tables[i].guid))
- return systab.tables[i].table;
- }
- return NULL;
-}
-
-/**
- * efi_install_fdt() - install device tree
- *
- * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
- * address will be installed as configuration table, otherwise the device
- * tree located at the address indicated by environment variable fdt_addr or as
- * fallback fdtcontroladdr will be used.
- *
- * On architectures using ACPI tables device trees shall not be installed as
- * configuration table.
- *
- * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
- * the hardware device tree as indicated by environment variable
- * fdt_addr or as fallback the internal device tree as indicated by
- * the environment variable fdtcontroladdr
- * Return: status code
- */
-efi_status_t efi_install_fdt(void *fdt)
-{
- struct bootm_headers img = { 0 };
- efi_status_t ret;
-
- /*
- * The EBBR spec requires that we have either an FDT or an ACPI table
- * but not both.
- */
- if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
- log_warning("WARNING: Can't have ACPI table and device tree - ignoring DT.\n");
-
- if (fdt == EFI_FDT_USE_INTERNAL) {
- const char *fdt_opt;
- uintptr_t fdt_addr;
-
- /* Look for device tree that is already installed */
- if (get_config_table(&efi_guid_fdt))
- return EFI_SUCCESS;
- /* Check if there is a hardware device tree */
- fdt_opt = env_get("fdt_addr");
- /* Use our own device tree as fallback */
- if (!fdt_opt) {
- fdt_opt = env_get("fdtcontroladdr");
- if (!fdt_opt) {
- log_err("ERROR: need device tree\n");
- return EFI_NOT_FOUND;
- }
- }
- fdt_addr = hextoul(fdt_opt, NULL);
- if (!fdt_addr) {
- log_err("ERROR: invalid $fdt_addr or $fdtcontroladdr\n");
- return EFI_LOAD_ERROR;
- }
- fdt = map_sysmem(fdt_addr, 0);
- }
-
- /* Install device tree */
- if (fdt_check_header(fdt)) {
- log_err("ERROR: invalid device tree\n");
- return EFI_LOAD_ERROR;
- }
-
- /* Create memory reservations as indicated by the device tree */
- efi_carve_out_dt_rsv(fdt);
-
- if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE))
- return EFI_SUCCESS;
-
- /* Prepare device tree for payload */
- ret = copy_fdt(&fdt);
- if (ret) {
- log_err("ERROR: out of memory\n");
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (image_setup_libfdt(&img, fdt, NULL)) {
- log_err("ERROR: failed to process device tree\n");
- return EFI_LOAD_ERROR;
- }
-
- efi_try_purge_kaslr_seed(fdt);
-
- if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
- ret = efi_tcg2_measure_dtb(fdt);
- if (ret == EFI_SECURITY_VIOLATION) {
- log_err("ERROR: failed to measure DTB\n");
- return ret;
- }
- }
-
- /* Install device tree as UEFI table */
- ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
- if (ret != EFI_SUCCESS) {
- log_err("ERROR: failed to install device tree\n");
- return ret;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- * do_bootefi_exec() - execute EFI binary
- *
- * The image indicated by @handle is started. When it returns the allocated
- * memory for the @load_options is freed.
- *
- * @handle: handle of loaded image
- * @load_options: load options
- * Return: status code
- *
- * Load the EFI binary into a newly assigned memory unwinding the relocation
- * information, install the loaded image protocol, and call the binary.
- */
-static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
-{
- efi_status_t ret;
- efi_uintn_t exit_data_size = 0;
- u16 *exit_data = NULL;
- struct efi_event *evt;
-
- /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
- switch_to_non_secure_mode();
-
- /*
- * The UEFI standard requires that the watchdog timer is set to five
- * minutes when invoking an EFI boot option.
- *
- * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
- * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
- */
- ret = efi_set_watchdog(300);
- if (ret != EFI_SUCCESS) {
- log_err("ERROR: Failed to set watchdog timer\n");
- goto out;
- }
-
- /* Call our payload! */
- ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
- if (ret != EFI_SUCCESS) {
- log_err("## Application failed, r = %lu\n",
- ret & ~EFI_ERROR_MASK);
- if (exit_data) {
- log_err("## %ls\n", exit_data);
- efi_free_pool(exit_data);
- }
- }
-
- efi_restore_gd();
-
-out:
- free(load_options);
-
- if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
- if (efi_initrd_deregister() != EFI_SUCCESS)
- log_err("Failed to remove loadfile2 for initrd\n");
- }
-
- /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
- list_for_each_entry(evt, &efi_events, link) {
- if (evt->group &&
- !guidcmp(evt->group,
- &efi_guid_event_group_return_to_efibootmgr)) {
- efi_signal_event(evt);
- EFI_CALL(systab.boottime->close_event(evt));
- break;
- }
- }
-
- /* Control is returned to U-Boot, disable EFI watchdog */
- efi_set_watchdog(0);
-
- return ret;
-}
-
/**
* efi_bootmgr_run() - execute EFI boot manager
* @fdt: Flat device tree
@@ -1542,100 +1151,3 @@ efi_status_t efi_bootmgr_run(void *fdt)
return do_bootefi_exec(handle, load_options);
}
-
-/**
- * efi_run_image() - run loaded UEFI image
- *
- * @source_buffer: memory address of the UEFI image
- * @source_size: size of the UEFI image
- * Return: status code
- */
-efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
-{
- efi_handle_t mem_handle = NULL, handle;
- struct efi_device_path *file_path = NULL;
- struct efi_device_path *msg_path;
- efi_status_t ret, ret2;
- u16 *load_options;
-
- if (!bootefi_device_path || !bootefi_image_path) {
- log_debug("Not loaded from disk\n");
- /*
- * Special case for efi payload not loaded from disk,
- * such as 'bootefi hello' or for example payload
- * loaded directly into memory via JTAG, etc:
- */
- file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
- (uintptr_t)source_buffer,
- source_size);
- /*
- * Make sure that device for device_path exist
- * in load_image(). Otherwise, shell and grub will fail.
- */
- ret = efi_install_multiple_protocol_interfaces(&mem_handle,
- &efi_guid_device_path,
- file_path, NULL);
- if (ret != EFI_SUCCESS)
- goto out;
- msg_path = file_path;
- } else {
- file_path = efi_dp_append(bootefi_device_path,
- bootefi_image_path);
- msg_path = bootefi_image_path;
- log_debug("Loaded from disk\n");
- }
-
- log_info("Booting %pD\n", msg_path);
-
- ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
- source_size, &handle));
- if (ret != EFI_SUCCESS) {
- log_err("Loading image failed\n");
- goto out;
- }
-
- /* Transfer environment variable as load options */
- ret = efi_env_set_load_options(handle, "bootargs", &load_options);
- if (ret != EFI_SUCCESS)
- goto out;
-
- ret = do_bootefi_exec(handle, load_options);
-
-out:
- ret2 = efi_uninstall_multiple_protocol_interfaces(mem_handle,
- &efi_guid_device_path,
- file_path, NULL);
- efi_free_pool(file_path);
- return (ret != EFI_SUCCESS) ? ret : ret2;
-}
-
-/**
- * efi_binary_run() - run loaded UEFI image
- *
- * @image: memory address of the UEFI image
- * @size: size of the UEFI image
- * @fdt: device-tree
- *
- * Execute an EFI binary image loaded at @image.
- * @size may be zero if the binary is loaded with U-Boot load command.
- *
- * Return: status code
- */
-efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
-{
- efi_status_t ret;
-
- /* Initialize EFI drivers */
- ret = efi_init_obj_list();
- if (ret != EFI_SUCCESS) {
- log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
- ret & ~EFI_ERROR_MASK);
- return -1;
- }
-
- ret = efi_install_fdt(fdt);
- if (ret != EFI_SUCCESS)
- return ret;
-
- return efi_run_image(image, size);
-}
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c579d89211..1951291747 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1816,7 +1816,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
if (device_path) {
info->device_handle = efi_dp_find_obj(device_path, NULL, NULL);
- dp = efi_dp_append(device_path, file_path);
+ dp = efi_dp_concat(device_path, file_path, false);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto failure;
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 8dbd8105ae..46aa59b9e4 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -271,30 +271,27 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
}
/**
- * efi_dp_append_or_concatenate() - Append or concatenate two device paths.
- * Concatenated device path will be separated
- * by a sub-type 0xff end node
+ * efi_dp_concat() - Concatenate two device paths and add and terminate them
+ * with an end node.
*
- * @dp1: First device path
- * @dp2: Second device path
- * @concat: If true the two device paths will be concatenated and separated
- * by an end of entrire device path sub-type 0xff end node.
- * If true the second device path will be appended to the first and
- * terminated by an end node
+ * @dp1: First device path
+ * @dp2: Second device path
+ * @split_end_node: If true the two device paths will be concatenated and
+ * separated by an end node (DEVICE_PATH_SUB_TYPE_END).
+ * If false the second device path will be concatenated to the
+ * first one as-is.
*
* Return:
* concatenated device path or NULL. Caller must free the returned value
*/
-static struct
-efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
- const struct efi_device_path *dp2,
- bool concat)
+struct
+efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
+ const struct efi_device_path *dp2,
+ bool split_end_node)
{
struct efi_device_path *ret;
- size_t end_size = sizeof(END);
+ size_t end_size;
- if (concat)
- end_size = 2 * sizeof(END);
if (!dp1 && !dp2) {
/* return an end node */
ret = efi_dp_dup(&END);
@@ -306,14 +303,20 @@ efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
/* both dp1 and dp2 are non-null */
unsigned sz1 = efi_dp_size(dp1);
unsigned sz2 = efi_dp_size(dp2);
- void *p = efi_alloc(sz1 + sz2 + end_size);
+ void *p;
+
+ if (split_end_node)
+ end_size = 2 * sizeof(END);
+ else
+ end_size = sizeof(END);
+ p = efi_alloc(sz1 + sz2 + end_size);
if (!p)
return NULL;
ret = p;
memcpy(p, dp1, sz1);
p += sz1;
- if (concat) {
+ if (split_end_node) {
memcpy(p, &END, sizeof(END));
p += sizeof(END);
}
@@ -327,37 +330,6 @@ efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
return ret;
}
-/**
- * efi_dp_append() - Append a device to an existing device path.
- *
- * @dp1: First device path
- * @dp2: Second device path
- *
- * Return:
- * concatenated device path or NULL. Caller must free the returned value
- */
-struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
- const struct efi_device_path *dp2)
-{
- return efi_dp_append_or_concatenate(dp1, dp2, false);
-}
-
-/**
- * efi_dp_concat() - Concatenate 2 device paths. The final device path will
- * contain two device paths separated by and end node (0xff).
- *
- * @dp1: First device path
- * @dp2: Second device path
- *
- * Return:
- * concatenated device path or NULL. Caller must free the returned value
- */
-struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
- const struct efi_device_path *dp2)
-{
- return efi_dp_append_or_concatenate(dp1, dp2, true);
-}
-
struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
const struct efi_device_path *node)
{
@@ -1089,7 +1061,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
if (path && !file)
return EFI_INVALID_PARAMETER;
- if (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs")) {
+ if (IS_ENABLED(CONFIG_EFI_BINARY_EXEC) &&
+ (!strcmp(dev, "Mem") || !strcmp(dev, "hostfs"))) {
/* loadm command and semihosting */
efi_get_image_parameters(&image_addr, &image_size);
diff --git a/lib/efi_loader/efi_device_path_utilities.c b/lib/efi_loader/efi_device_path_utilities.c
index 844d8acd67..c95dbfa9b5 100644
--- a/lib/efi_loader/efi_device_path_utilities.c
+++ b/lib/efi_loader/efi_device_path_utilities.c
@@ -76,7 +76,7 @@ static struct efi_device_path * EFIAPI append_device_path(
const struct efi_device_path *src2)
{
EFI_ENTRY("%pD, %pD", src1, src2);
- return EFI_EXIT(efi_dp_append(src1, src2));
+ return EFI_EXIT(efi_dp_concat(src1, src2, false));
}
/*
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index ed997008c4..013842f077 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -31,20 +31,15 @@ const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
*
* @header: EFI object header
* @ops: EFI disk I/O protocol interface
- * @dev_index: device index of block device
* @media: block I/O media information
* @dp: device path to the block device
- * @part: partition
* @volume: simple file system protocol of the partition
- * @dev: associated DM device
*/
struct efi_disk_obj {
struct efi_object header;
struct efi_block_io ops;
- int dev_index;
struct efi_block_io_media media;
struct efi_device_path *dp;
- unsigned int part;
struct efi_simple_file_system_protocol *volume;
};
@@ -382,7 +377,6 @@ static int efi_fs_exists(struct blk_desc *desc, int part)
* @parent: parent handle
* @dp_parent: parent device path
* @desc: internal block device
- * @dev_index: device index for block device
* @part_info: partition info
* @part: partition
* @disk: pointer to receive the created handle
@@ -393,7 +387,6 @@ static efi_status_t efi_disk_add_dev(
efi_handle_t parent,
struct efi_device_path *dp_parent,
struct blk_desc *desc,
- int dev_index,
struct disk_partition *part_info,
unsigned int part,
struct efi_disk_obj **disk,
@@ -455,7 +448,6 @@ static efi_status_t efi_disk_add_dev(
diskobj->dp = efi_dp_from_part(desc, part);
diskobj->media.last_block = desc->lba - 1;
}
- diskobj->part = part;
/*
* Install the device path and the block IO protocol.
@@ -498,7 +490,6 @@ static efi_status_t efi_disk_add_dev(
goto error;
}
diskobj->ops = block_io_disk_template;
- diskobj->dev_index = dev_index;
/* Fill in EFI IO Media info (for read/write callbacks) */
diskobj->media.removable_media = desc->removable;
@@ -518,7 +509,7 @@ static efi_status_t efi_disk_add_dev(
EFI_PRINT("BlockIO: part %u, present %d, logical %d, removable %d"
", last_block %llu\n",
- diskobj->part,
+ part,
diskobj->media.media_present,
diskobj->media.logical_partition,
diskobj->media.removable_media,
@@ -565,7 +556,7 @@ static int efi_disk_create_raw(struct udevice *dev, efi_handle_t agent_handle)
diskid = desc->devnum;
ret = efi_disk_add_dev(NULL, NULL, desc,
- diskid, NULL, 0, &disk, agent_handle);
+ NULL, 0, &disk, agent_handle);
if (ret != EFI_SUCCESS) {
if (ret == EFI_NOT_READY) {
log_notice("Disk %s not ready\n", dev->name);
@@ -626,7 +617,7 @@ static int efi_disk_create_part(struct udevice *dev, efi_handle_t agent_handle)
return -1;
dp_parent = (struct efi_device_path *)handler->protocol_interface;
- ret = efi_disk_add_dev(parent, dp_parent, desc, diskid,
+ ret = efi_disk_add_dev(parent, dp_parent, desc,
info, part, &disk, agent_handle);
if (ret != EFI_SUCCESS) {
log_err("Adding partition for %s failed\n", dev->name);
diff --git a/lib/efi_loader/efi_esrt.c b/lib/efi_loader/efi_esrt.c
index dafd447b6d..443bd999ce 100644
--- a/lib/efi_loader/efi_esrt.c
+++ b/lib/efi_loader/efi_esrt.c
@@ -364,7 +364,7 @@ efi_status_t efi_esrt_populate(void)
if (ret != EFI_SUCCESS) {
EFI_PRINT("ESRT Unable to find FMP handle (%u)\n",
idx);
- goto out;
+ continue;
}
fmp = handler->protocol_interface;
@@ -379,15 +379,14 @@ efi_status_t efi_esrt_populate(void)
* fmp->get_image_info to return BUFFER_TO_SMALL.
*/
EFI_PRINT("ESRT erroneous FMP implementation\n");
- ret = EFI_INVALID_PARAMETER;
- goto out;
+ continue;
}
ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, info_size,
(void **)&img_info);
if (ret != EFI_SUCCESS) {
EFI_PRINT("ESRT failed to allocate memory for image info\n");
- goto out;
+ continue;
}
/*
@@ -405,7 +404,7 @@ efi_status_t efi_esrt_populate(void)
if (ret != EFI_SUCCESS) {
EFI_PRINT("ESRT failed to obtain image info from FMP\n");
efi_free_pool(img_info);
- goto out;
+ continue;
}
num_entries += desc_count;
@@ -413,6 +412,13 @@ efi_status_t efi_esrt_populate(void)
efi_free_pool(img_info);
}
+ /* error occurs in fmp->get_image_info() if num_entries is 0 here */
+ if (!num_entries) {
+ EFI_PRINT("Error occurs, num_entries should not be 0\n");
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
EFI_PRINT("ESRT create table with %u entries\n", num_entries);
/*
* Allocate an ESRT with the sufficient number of entries to accommodate
@@ -436,7 +442,7 @@ efi_status_t efi_esrt_populate(void)
if (ret != EFI_SUCCESS) {
EFI_PRINT("ESRT unable to find FMP handle (%u)\n",
idx);
- break;
+ continue;
}
fmp = handler->protocol_interface;
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 1fde1885e3..9fd13297a6 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -206,18 +206,10 @@ void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_
{
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_uintn_t size, expected_size;
+ uint num_banks = 1;
+ uint active_index = 0;
+ struct fmp_state *var_state;
efi_firmware_get_lsv_from_dtb(fw_array->image_index,
&fw_array->image_type_id,
@@ -226,6 +218,31 @@ void efi_firmware_fill_version_info(struct efi_firmware_image_descriptor *image_
image_info->version_name = NULL; /* not supported */
image_info->last_attempt_version = 0;
image_info->last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
+ image_info->version = 0;
+
+ /* get the fw_version */
+ efi_create_indexed_name(varname, sizeof(varname), "FmpState",
+ fw_array->image_index);
+ if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+ ret = fwu_get_active_index(&active_index);
+ if (ret)
+ return;
+
+ num_banks = CONFIG_FWU_NUM_BANKS;
+ }
+
+ size = num_banks * sizeof(*var_state);
+ expected_size = size;
+ var_state = calloc(1, size);
+ if (!var_state)
+ return;
+
+ ret = efi_get_variable_int(varname, &fw_array->image_type_id,
+ NULL, &size, var_state, NULL);
+ if (ret == EFI_SUCCESS && expected_size == size)
+ image_info->version = var_state[active_index].fw_version;
+
+ free(var_state);
}
/**
@@ -361,8 +378,11 @@ efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_in
{
u16 varname[13]; /* u"FmpStateXXXX" */
efi_status_t ret;
+ uint num_banks = 1;
+ uint update_bank = 0;
+ efi_uintn_t size;
efi_guid_t *image_type_id;
- struct fmp_state var_state = { 0 };
+ struct fmp_state *var_state;
image_type_id = efi_firmware_get_image_type_id(image_index);
if (!image_type_id)
@@ -371,19 +391,44 @@ efi_status_t efi_firmware_set_fmp_state_var(struct fmp_state *state, u8 image_in
efi_create_indexed_name(varname, sizeof(varname), "FmpState",
image_index);
+ if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
+ ret = fwu_plat_get_update_index(&update_bank);
+ if (ret)
+ return EFI_INVALID_PARAMETER;
+
+ num_banks = CONFIG_FWU_NUM_BANKS;
+ }
+
+ size = num_banks * sizeof(*var_state);
+ var_state = calloc(1, size);
+ if (!var_state)
+ return EFI_OUT_OF_RESOURCES;
+
+ /*
+ * GetVariable may fail, EFI_NOT_FOUND is returned if FmpState
+ * variable has not been set yet.
+ * Ignore the error here since the correct FmpState variable
+ * is set later.
+ */
+ efi_get_variable_int(varname, image_type_id, NULL, &size, var_state,
+ NULL);
+
/*
* 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;
+ var_state[update_bank].fw_version = state->fw_version;
+ size = num_banks * sizeof(*var_state);
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);
+ size, var_state, false);
+
+ free(var_state);
return ret;
}
@@ -610,6 +655,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
u16 **abort_reason)
{
int ret;
+ u8 dfu_alt_num;
efi_status_t status;
struct fmp_state state = { 0 };
@@ -624,19 +670,25 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
if (status != EFI_SUCCESS)
return EFI_EXIT(status);
+ /*
+ * dfu_alt_num is assigned from 0 while image_index starts from 1.
+ * dfu_alt_num is calculated by (image_index - 1) when multi bank update
+ * is not used.
+ */
+ dfu_alt_num = image_index - 1;
if (IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) {
/*
* Based on the value of update bank, derive the
* image index value.
*/
- ret = fwu_get_image_index(&image_index);
+ ret = fwu_get_dfu_alt_num(image_index, &dfu_alt_num);
if (ret) {
log_debug("Unable to get FWU image_index\n");
return EFI_EXIT(EFI_DEVICE_ERROR);
}
}
- if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
+ if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size,
NULL, NULL))
return EFI_EXIT(EFI_DEVICE_ERROR);
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 17f27ca1a0..11066eb505 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -4,13 +4,20 @@
*/
#define LOG_CATEGORY LOGC_EFI
+#include <bootm.h>
#include <env.h>
+#include <image.h>
+#include <log.h>
#include <malloc.h>
+#include <mapmem.h>
#include <dm.h>
#include <fs.h>
+#include <efi_api.h>
#include <efi_load_initrd.h>
#include <efi_loader.h>
#include <efi_variable.h>
+#include <linux/libfdt.h>
+#include <linux/list.h>
#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD)
/* GUID used by Linux to identify the LoadFile2 protocol with the initrd */
@@ -281,3 +288,282 @@ bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *inde
return false;
}
+
+/**
+ * efi_env_set_load_options() - set load options from environment variable
+ *
+ * @handle: the image handle
+ * @env_var: name of the environment variable
+ * @load_options: pointer to load options (output)
+ * Return: status code
+ */
+efi_status_t efi_env_set_load_options(efi_handle_t handle,
+ const char *env_var,
+ u16 **load_options)
+{
+ const char *env = env_get(env_var);
+ size_t size;
+ u16 *pos;
+ efi_status_t ret;
+
+ *load_options = NULL;
+ if (!env)
+ return EFI_SUCCESS;
+ size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
+ pos = calloc(size, 1);
+ if (!pos)
+ return EFI_OUT_OF_RESOURCES;
+ *load_options = pos;
+ utf8_utf16_strcpy(&pos, env);
+ ret = efi_set_load_options(handle, size, *load_options);
+ if (ret != EFI_SUCCESS) {
+ free(*load_options);
+ *load_options = NULL;
+ }
+ return ret;
+}
+
+/**
+ * copy_fdt() - Copy the device tree to a new location available to EFI
+ *
+ * The FDT is copied to a suitable location within the EFI memory map.
+ * Additional 12 KiB are added to the space in case the device tree needs to be
+ * expanded later with fdt_open_into().
+ *
+ * @fdtp: On entry a pointer to the flattened device tree.
+ * On exit a pointer to the copy of the flattened device tree.
+ * FDT start
+ * Return: status code
+ */
+static efi_status_t copy_fdt(void **fdtp)
+{
+ unsigned long fdt_ram_start = -1L, fdt_pages;
+ efi_status_t ret = 0;
+ void *fdt, *new_fdt;
+ u64 new_fdt_addr;
+ uint fdt_size;
+ int i;
+
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+ u64 ram_start = gd->bd->bi_dram[i].start;
+ u64 ram_size = gd->bd->bi_dram[i].size;
+
+ if (!ram_size)
+ continue;
+
+ if (ram_start < fdt_ram_start)
+ fdt_ram_start = ram_start;
+ }
+
+ /*
+ * Give us at least 12 KiB of breathing room in case the device tree
+ * needs to be expanded later.
+ */
+ fdt = *fdtp;
+ fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
+ fdt_size = fdt_pages << EFI_PAGE_SHIFT;
+
+ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
+ &new_fdt_addr);
+ if (ret != EFI_SUCCESS) {
+ log_err("ERROR: Failed to reserve space for FDT\n");
+ goto done;
+ }
+ new_fdt = (void *)(uintptr_t)new_fdt_addr;
+ memcpy(new_fdt, fdt, fdt_totalsize(fdt));
+ fdt_set_totalsize(new_fdt, fdt_size);
+
+ *fdtp = (void *)(uintptr_t)new_fdt_addr;
+done:
+ return ret;
+}
+
+/**
+ * get_config_table() - get configuration table
+ *
+ * @guid: GUID of the configuration table
+ * Return: pointer to configuration table or NULL
+ */
+static void *get_config_table(const efi_guid_t *guid)
+{
+ size_t i;
+
+ for (i = 0; i < systab.nr_tables; i++) {
+ if (!guidcmp(guid, &systab.tables[i].guid))
+ return systab.tables[i].table;
+ }
+ return NULL;
+}
+
+/**
+ * efi_install_fdt() - install device tree
+ *
+ * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
+ * address will be installed as configuration table, otherwise the device
+ * tree located at the address indicated by environment variable fdt_addr or as
+ * fallback fdtcontroladdr will be used.
+ *
+ * On architectures using ACPI tables device trees shall not be installed as
+ * configuration table.
+ *
+ * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
+ * the hardware device tree as indicated by environment variable
+ * fdt_addr or as fallback the internal device tree as indicated by
+ * the environment variable fdtcontroladdr
+ * Return: status code
+ */
+efi_status_t efi_install_fdt(void *fdt)
+{
+ struct bootm_headers img = { 0 };
+ efi_status_t ret;
+
+ /*
+ * The EBBR spec requires that we have either an FDT or an ACPI table
+ * but not both.
+ */
+ if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
+ log_warning("WARNING: Can't have ACPI table and device tree - ignoring DT.\n");
+
+ if (fdt == EFI_FDT_USE_INTERNAL) {
+ const char *fdt_opt;
+ uintptr_t fdt_addr;
+
+ /* Look for device tree that is already installed */
+ if (get_config_table(&efi_guid_fdt))
+ return EFI_SUCCESS;
+ /* Check if there is a hardware device tree */
+ fdt_opt = env_get("fdt_addr");
+ /* Use our own device tree as fallback */
+ if (!fdt_opt) {
+ fdt_opt = env_get("fdtcontroladdr");
+ if (!fdt_opt) {
+ log_err("ERROR: need device tree\n");
+ return EFI_NOT_FOUND;
+ }
+ }
+ fdt_addr = hextoul(fdt_opt, NULL);
+ if (!fdt_addr) {
+ log_err("ERROR: invalid $fdt_addr or $fdtcontroladdr\n");
+ return EFI_LOAD_ERROR;
+ }
+ fdt = map_sysmem(fdt_addr, 0);
+ }
+
+ /* Install device tree */
+ if (fdt_check_header(fdt)) {
+ log_err("ERROR: invalid device tree\n");
+ return EFI_LOAD_ERROR;
+ }
+
+ /* Create memory reservations as indicated by the device tree */
+ efi_carve_out_dt_rsv(fdt);
+
+ if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE))
+ return EFI_SUCCESS;
+
+ /* Prepare device tree for payload */
+ ret = copy_fdt(&fdt);
+ if (ret) {
+ log_err("ERROR: out of memory\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (image_setup_libfdt(&img, fdt, NULL)) {
+ log_err("ERROR: failed to process device tree\n");
+ return EFI_LOAD_ERROR;
+ }
+
+ efi_try_purge_kaslr_seed(fdt);
+
+ if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
+ ret = efi_tcg2_measure_dtb(fdt);
+ if (ret == EFI_SECURITY_VIOLATION) {
+ log_err("ERROR: failed to measure DTB\n");
+ return ret;
+ }
+ }
+
+ /* Install device tree as UEFI table */
+ ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
+ if (ret != EFI_SUCCESS) {
+ log_err("ERROR: failed to install device tree\n");
+ return ret;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * do_bootefi_exec() - execute EFI binary
+ *
+ * The image indicated by @handle is started. When it returns the allocated
+ * memory for the @load_options is freed.
+ *
+ * @handle: handle of loaded image
+ * @load_options: load options
+ * Return: status code
+ *
+ * Load the EFI binary into a newly assigned memory unwinding the relocation
+ * information, install the loaded image protocol, and call the binary.
+ */
+efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
+{
+ efi_status_t ret;
+ efi_uintn_t exit_data_size = 0;
+ u16 *exit_data = NULL;
+ struct efi_event *evt;
+
+ /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
+ switch_to_non_secure_mode();
+
+ /*
+ * The UEFI standard requires that the watchdog timer is set to five
+ * minutes when invoking an EFI boot option.
+ *
+ * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
+ * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
+ */
+ ret = efi_set_watchdog(300);
+ if (ret != EFI_SUCCESS) {
+ log_err("ERROR: Failed to set watchdog timer\n");
+ goto out;
+ }
+
+ /* Call our payload! */
+ ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
+ if (ret != EFI_SUCCESS) {
+ log_err("## Application failed, r = %lu\n",
+ ret & ~EFI_ERROR_MASK);
+ if (exit_data) {
+ log_err("## %ls\n", exit_data);
+ efi_free_pool(exit_data);
+ }
+ }
+
+ efi_restore_gd();
+
+out:
+ free(load_options);
+
+ if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
+ if (efi_initrd_deregister() != EFI_SUCCESS)
+ log_err("Failed to remove loadfile2 for initrd\n");
+ }
+
+ /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
+ list_for_each_entry(evt, &efi_events, link) {
+ if (evt->group &&
+ !guidcmp(evt->group,
+ &efi_guid_event_group_return_to_efibootmgr)) {
+ efi_signal_event(evt);
+ EFI_CALL(systab.boottime->close_event(evt));
+ break;
+ }
+ }
+
+ /* Control is returned to U-Boot, disable EFI watchdog */
+ efi_set_watchdog(0);
+
+ return ret;
+}
diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c
index eb6d2ba43c..8d2ef6deb5 100644
--- a/lib/efi_loader/efi_smbios.c
+++ b/lib/efi_loader/efi_smbios.c
@@ -13,6 +13,9 @@
#include <mapmem.h>
#include <smbios.h>
#include <linux/sizes.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
const efi_guid_t smbios3_guid = SMBIOS3_TABLE_GUID;
@@ -57,7 +60,9 @@ static int install_smbios_table(void)
ulong addr;
void *buf;
- if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || IS_ENABLED(CONFIG_X86))
+ if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) ||
+ IS_ENABLED(CONFIG_X86) ||
+ IS_ENABLED(CONFIG_QFW_SMBIOS))
return 0;
/* Align the table to a 4KB boundary to keep EFI happy */
diff --git a/lib/efi_loader/smbiosdump.c b/lib/efi_loader/smbiosdump.c
new file mode 100644
index 0000000000..f0b901897e
--- /dev/null
+++ b/lib/efi_loader/smbiosdump.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+ *
+ * smbiosdump.efi saves the SMBIOS table as file.
+ *
+ * Specifying 'nocolor' as load option data suppresses colored output and
+ * clearing of the screen.
+ */
+
+#include <efi_api.h>
+#include <part.h>
+#include <smbios.h>
+#include <string.h>
+
+#define BUFFER_SIZE 64
+
+static struct efi_simple_text_output_protocol *cerr;
+static struct efi_simple_text_output_protocol *cout;
+static struct efi_simple_text_input_protocol *cin;
+static struct efi_boot_services *bs;
+static efi_handle_t handle;
+static struct efi_system_table *systable;
+static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID;
+static const efi_guid_t smbios3_guid = SMBIOS3_TABLE_GUID;
+static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+static const efi_guid_t guid_simple_file_system_protocol =
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
+static bool nocolor;
+
+/**
+ * color() - set foreground color
+ *
+ * @color: foreground color
+ */
+static void color(u8 color)
+{
+ if (!nocolor)
+ cout->set_attribute(cout, color | EFI_BACKGROUND_BLACK);
+}
+
+/**
+ * print() - print string
+ *
+ * @string: text
+ */
+static void print(u16 *string)
+{
+ cout->output_string(cout, string);
+}
+
+/**
+ * cls() - clear screen
+ */
+static void cls(void)
+{
+ if (nocolor)
+ print(u"\r\n");
+ else
+ cout->clear_screen(cout);
+}
+
+/**
+ * error() - print error string
+ *
+ * @string: error text
+ */
+static void error(u16 *string)
+{
+ color(EFI_LIGHTRED);
+ print(string);
+ color(EFI_LIGHTBLUE);
+}
+
+/**
+ * efi_input_yn() - get answer to yes/no question
+ *
+ * Return:
+ * y or Y
+ * EFI_SUCCESS
+ * n or N
+ * EFI_ACCESS_DENIED
+ * ESC
+ * EFI_ABORTED
+ */
+static efi_status_t efi_input_yn(void)
+{
+ struct efi_input_key key = {0};
+ efi_uintn_t index;
+ efi_status_t ret;
+
+ /* Drain the console input */
+ ret = cin->reset(cin, true);
+ for (;;) {
+ ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+ if (ret != EFI_SUCCESS)
+ continue;
+ ret = cin->read_key_stroke(cin, &key);
+ if (ret != EFI_SUCCESS)
+ continue;
+ switch (key.scan_code) {
+ case 0x17: /* Escape */
+ return EFI_ABORTED;
+ default:
+ break;
+ }
+ /* Convert to lower case */
+ switch (key.unicode_char | 0x20) {
+ case 'y':
+ return EFI_SUCCESS;
+ case 'n':
+ return EFI_ACCESS_DENIED;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * efi_input() - read string from console
+ *
+ * @buffer: input buffer
+ * @buffer_size: buffer size
+ * Return: status code
+ */
+static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
+{
+ struct efi_input_key key = {0};
+ efi_uintn_t index;
+ efi_uintn_t pos = 0;
+ u16 outbuf[2] = u" ";
+ efi_status_t ret;
+
+ /* Drain the console input */
+ ret = cin->reset(cin, true);
+ *buffer = 0;
+ for (;;) {
+ ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
+ if (ret != EFI_SUCCESS)
+ continue;
+ ret = cin->read_key_stroke(cin, &key);
+ if (ret != EFI_SUCCESS)
+ continue;
+ switch (key.scan_code) {
+ case 0x17: /* Escape */
+ print(u"\r\nAborted\r\n");
+ return EFI_ABORTED;
+ default:
+ break;
+ }
+ switch (key.unicode_char) {
+ case 0x08: /* Backspace */
+ if (pos) {
+ buffer[pos--] = 0;
+ print(u"\b \b");
+ }
+ break;
+ case 0x0a: /* Linefeed */
+ case 0x0d: /* Carriage return */
+ print(u"\r\n");
+ return EFI_SUCCESS;
+ default:
+ break;
+ }
+ /* Ignore surrogate codes */
+ if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
+ continue;
+ if (key.unicode_char >= 0x20 &&
+ pos < buffer_size - 1) {
+ *outbuf = key.unicode_char;
+ buffer[pos++] = key.unicode_char;
+ buffer[pos] = 0;
+ print(outbuf);
+ }
+ }
+}
+
+/**
+ * skip_whitespace() - skip over leading whitespace
+ *
+ * @pos: UTF-16 string
+ * Return: pointer to first non-whitespace
+ */
+static u16 *skip_whitespace(u16 *pos)
+{
+ for (; *pos && *pos <= 0x20; ++pos)
+ ;
+ return pos;
+}
+
+/**
+ * starts_with() - check if @string starts with @keyword
+ *
+ * @string: string to search for keyword
+ * @keyword: keyword to be searched
+ * Return: true fi @string starts with the keyword
+ */
+static bool starts_with(u16 *string, u16 *keyword)
+{
+ if (!string || !keyword)
+ return NULL;
+
+ for (; *keyword; ++string, ++keyword) {
+ if (*string != *keyword)
+ return false;
+ }
+ return true;
+}
+
+/**
+ * open_file_system() - open simple file system protocol
+ *
+ * file_system: interface of the simple file system protocol
+ * Return: status code
+ */
+static efi_status_t
+open_file_system(struct efi_simple_file_system_protocol **file_system)
+{
+ struct efi_loaded_image *loaded_image;
+ efi_status_t ret;
+ efi_handle_t *handle_buffer = NULL;
+ efi_uintn_t count;
+
+ ret = bs->open_protocol(handle, &loaded_image_guid,
+ (void **)&loaded_image, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS) {
+ error(u"Loaded image protocol not found\r\n");
+ return ret;
+ }
+
+ /* Open the simple file system protocol on the same partition */
+ ret = bs->open_protocol(loaded_image->device_handle,
+ &guid_simple_file_system_protocol,
+ (void **)file_system, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret == EFI_SUCCESS)
+ return ret;
+
+ /* Open the simple file system protocol on the UEFI system partition */
+ ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
+ NULL, &count, &handle_buffer);
+ if (ret == EFI_SUCCESS && handle_buffer)
+ ret = bs->open_protocol(handle_buffer[0],
+ &guid_simple_file_system_protocol,
+ (void **)file_system, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS)
+ error(u"Failed to open simple file system protocol\r\n");
+ if (handle)
+ bs->free_pool(handle_buffer);
+
+ return ret;
+}
+
+/**
+ * do_help() - print help
+ */
+static void do_help(void)
+{
+ error(u"check - check SMBIOS table\r\n");
+ error(u"save <file> - save SMBIOS table to file\r\n");
+ error(u"exit - exit the shell\r\n");
+}
+
+/**
+ * get_config_table() - get configuration table
+ *
+ * @guid: GUID of the configuration table
+ * Return: pointer to configuration table or NULL
+ */
+static void *get_config_table(const efi_guid_t *guid)
+{
+ size_t i;
+
+ for (i = 0; i < systable->nr_tables; ++i) {
+ if (!memcmp(guid, &systable->tables[i].guid, 16))
+ return systable->tables[i].table;
+ }
+
+ return NULL;
+}
+
+/**
+ * checksum() - calculate checksum
+ *
+ * @buf: buffer to checksum
+ * @len: length of buffer
+ * Return: checksum
+ */
+u8 checksum(void *buf, int len)
+{
+ u8 ret = 0;
+
+ for (u8 *ptr = buf; len; --len, ++ptr)
+ ret -= *ptr;
+
+ return ret;
+}
+
+/**
+ * do_check() - check SMBIOS table
+ *
+ * Return: status code
+ */
+efi_status_t do_check(void)
+{
+ struct smbios3_entry *smbios3_anchor;
+ void *table, *table_end;
+ u32 len;
+
+ smbios3_anchor = get_config_table(&smbios3_guid);
+ if (smbios3_anchor) {
+ int r;
+
+ r = memcmp(smbios3_anchor->anchor, "_SM3_", 5);
+ if (r) {
+ error(u"Invalid anchor string\n");
+ return EFI_LOAD_ERROR;
+ }
+ print(u"Found SMBIOS 3 entry point\n");
+ if (smbios3_anchor->length != 0x18) {
+ error(u"Invalid anchor length\n");
+ return EFI_LOAD_ERROR;
+ }
+ if (checksum(smbios3_anchor, smbios3_anchor->length)) {
+ error(u"Invalid anchor checksum\n");
+ return EFI_LOAD_ERROR;
+ }
+ table = (void *)(uintptr_t)smbios3_anchor->struct_table_address;
+ len = smbios3_anchor->max_struct_size;
+ } else {
+ struct smbios_entry *smbios_anchor;
+ int r;
+
+ smbios_anchor = get_config_table(&smbios_guid);
+ if (!smbios_anchor) {
+ error(u"No SMBIOS table\n");
+ return EFI_NOT_FOUND;
+ }
+ r = memcmp(smbios_anchor->anchor, "_SM_", 4);
+ if (r) {
+ error(u"Invalid anchor string\n");
+ return EFI_LOAD_ERROR;
+ }
+ print(u"Found SMBIOS 2.1 entry point\n");
+ if (smbios_anchor->length != 0x1f) {
+ error(u"Invalid anchor length\n");
+ return EFI_LOAD_ERROR;
+ }
+ if (checksum(smbios_anchor, smbios_anchor->length)) {
+ error(u"Invalid anchor checksum\n");
+ return EFI_LOAD_ERROR;
+ }
+ r = memcmp(smbios_anchor->intermediate_anchor, "_DMI_", 5);
+ if (r) {
+ error(u"Invalid intermediate anchor string\n");
+ return EFI_LOAD_ERROR;
+ }
+ if (checksum(&smbios_anchor->intermediate_anchor, 0xf)) {
+ error(u"Invalid intermediate anchor checksum\n");
+ return EFI_LOAD_ERROR;
+ }
+ table = (void *)(uintptr_t)smbios_anchor->struct_table_address;
+ len = smbios_anchor->struct_table_length;
+ }
+
+ table_end = (void *)((u8 *)table + len);
+ for (struct smbios_header *pos = table; ;) {
+ u8 *str = (u8 *)pos + pos->length;
+
+ if (!*str)
+ ++str;
+ while (*str) {
+ for (; *str; ++str) {
+ if ((void *)str >= table_end) {
+ error(u"Structure table length exceeded\n");
+ return EFI_LOAD_ERROR;
+ }
+ }
+ ++str;
+ }
+ ++str;
+ if ((void *)str > table_end) {
+ error(u"Structure table length exceeded\n");
+ return EFI_LOAD_ERROR;
+ }
+ if (pos->type == 0x7f) /* End of table */
+ break;
+ pos = (struct smbios_header *)str;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * save_file() - save file to EFI system partition
+ *
+ * @filename: file name
+ * @buf: buffer to write
+ * @size: size of the buffer
+ */
+efi_status_t save_file(u16 *filename, void *buf, efi_uintn_t size)
+{
+ efi_uintn_t ret;
+ struct efi_simple_file_system_protocol *file_system;
+ struct efi_file_handle *root, *file;
+
+ ret = open_file_system(&file_system);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ /* Open volume */
+ ret = file_system->open_volume(file_system, &root);
+ if (ret != EFI_SUCCESS) {
+ error(u"Failed to open volume\r\n");
+ return ret;
+ }
+ /* Check if file already exists */
+ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
+ if (ret == EFI_SUCCESS) {
+ file->close(file);
+ print(u"Overwrite existing file (y/n)? ");
+ ret = efi_input_yn();
+ print(u"\r\n");
+ if (ret != EFI_SUCCESS) {
+ root->close(root);
+ error(u"Aborted by user\r\n");
+ bs->free_pool(buf);
+ return ret;
+ }
+ }
+
+ /* Create file */
+ ret = root->open(root, &file, filename,
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
+ EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
+ if (ret == EFI_SUCCESS) {
+ /* Write file */
+ ret = file->write(file, &size, buf);
+ if (ret != EFI_SUCCESS)
+ error(u"Failed to write file\r\n");
+ file->close(file);
+ } else {
+ error(u"Failed to open file\r\n");
+ }
+ root->close(root);
+
+ return ret;
+}
+
+/**
+ * do_save() - save SMBIOS table
+ *
+ * @filename: file name
+ * Return: status code
+ */
+static efi_status_t do_save(u16 *filename)
+{
+ struct smbios3_entry *smbios3_anchor;
+ u8 *buf;
+ efi_uintn_t size;
+ efi_uintn_t ret;
+
+ ret = do_check();
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ smbios3_anchor = get_config_table(&smbios3_guid);
+ if (smbios3_anchor) {
+ size = 0x20 + smbios3_anchor->max_struct_size;
+ ret = bs->allocate_pool(EFI_LOADER_DATA, size, (void **)&buf);
+ if (ret != EFI_SUCCESS) {
+ error(u"Out of memory\n");
+ return ret;
+ }
+
+ memset(buf, 0, size);
+ memcpy(buf, smbios3_anchor, smbios3_anchor->length);
+ memcpy(buf + 0x20,
+ (void *)(uintptr_t)smbios3_anchor->struct_table_address,
+ smbios3_anchor->max_struct_size);
+
+ smbios3_anchor = (struct smbios3_entry *)buf;
+ smbios3_anchor->struct_table_address = 0x20;
+ smbios3_anchor->checksum +=
+ checksum(smbios3_anchor, smbios3_anchor->length);
+ } else {
+ struct smbios_entry *smbios_anchor;
+
+ smbios_anchor = get_config_table(&smbios_guid);
+ if (!smbios_anchor) {
+ /* Should not be reached after successful do_check() */
+ error(u"No SMBIOS table\n");
+ return EFI_NOT_FOUND;
+ }
+
+ size = 0x20 + smbios_anchor->struct_table_length;
+
+ ret = bs->allocate_pool(EFI_LOADER_DATA, size, (void **)&buf);
+ if (ret != EFI_SUCCESS) {
+ error(u"Out of memory\n");
+ return ret;
+ }
+
+ memset(buf, 0, size);
+ memcpy(buf, smbios_anchor, smbios_anchor->length);
+ memcpy(buf + 0x20,
+ (void *)(uintptr_t)smbios_anchor->struct_table_address,
+ smbios_anchor->struct_table_length);
+
+ smbios_anchor = (struct smbios_entry *)buf;
+ smbios_anchor->struct_table_address = 0x20;
+ smbios_anchor->intermediate_checksum +=
+ checksum(&smbios_anchor->intermediate_anchor, 0xf);
+ smbios_anchor->checksum +=
+ checksum(smbios_anchor, smbios_anchor->length);
+ }
+
+ filename = skip_whitespace(filename);
+
+ ret = save_file(filename, buf, size);
+
+ if (ret == EFI_SUCCESS) {
+ print(filename);
+ print(u" written\r\n");
+ }
+
+ bs->free_pool(buf);
+
+ return ret;
+}
+
+/**
+ * get_load_options() - get load options
+ *
+ * Return: load options or NULL
+ */
+static u16 *get_load_options(void)
+{
+ efi_status_t ret;
+ struct efi_loaded_image *loaded_image;
+
+ ret = bs->open_protocol(handle, &loaded_image_guid,
+ (void **)&loaded_image, NULL, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS) {
+ error(u"Loaded image protocol not found\r\n");
+ return NULL;
+ }
+
+ if (!loaded_image->load_options_size || !loaded_image->load_options)
+ return NULL;
+
+ return loaded_image->load_options;
+}
+
+/**
+ * command_loop - process user commands
+ */
+static void command_loop(void)
+{
+ for (;;) {
+ u16 command[BUFFER_SIZE];
+ u16 *pos;
+ efi_uintn_t ret;
+
+ print(u"=> ");
+ ret = efi_input(command, sizeof(command));
+ if (ret == EFI_ABORTED)
+ break;
+ pos = skip_whitespace(command);
+ if (starts_with(pos, u"exit")) {
+ break;
+ } else if (starts_with(pos, u"check")) {
+ ret = do_check();
+ if (ret == EFI_SUCCESS)
+ print(u"OK\n");
+ } else if (starts_with(pos, u"save ")) {
+ do_save(pos + 5);
+ } else {
+ do_help();
+ }
+ }
+}
+
+/**
+ * efi_main() - entry point of the EFI application.
+ *
+ * @handle: handle of the loaded image
+ * @systab: system table
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
+ struct efi_system_table *systab)
+{
+ u16 *load_options;
+
+ handle = image_handle;
+ systable = systab;
+ cerr = systable->std_err;
+ cout = systable->con_out;
+ cin = systable->con_in;
+ bs = systable->boottime;
+ load_options = get_load_options();
+
+ if (starts_with(load_options, u"nocolor"))
+ nocolor = true;
+
+ color(EFI_WHITE);
+ cls();
+ print(u"SMBIOS Dump\r\n===========\r\n\r\n");
+ color(EFI_LIGHTBLUE);
+
+ command_loop();
+
+ color(EFI_LIGHTGRAY);
+ cls();
+
+ return EFI_SUCCESS;
+}
diff --git a/lib/fwu_updates/fwu.c b/lib/fwu_updates/fwu.c
index b580574015..86518108c2 100644
--- a/lib/fwu_updates/fwu.c
+++ b/lib/fwu_updates/fwu.c
@@ -125,16 +125,14 @@ static int in_trial_state(struct fwu_mdata *mdata)
return 0;
}
-static int fwu_get_image_type_id(u8 *image_index, efi_guid_t *image_type_id)
+static int fwu_get_image_type_id(u8 image_index, efi_guid_t *image_type_id)
{
- u8 index;
int i;
struct efi_fw_image *image;
- index = *image_index;
image = update_info.images;
for (i = 0; i < update_info.num_images; i++) {
- if (index == image[i].image_index) {
+ if (image_index == image[i].image_index) {
guidcpy(image_type_id, &image[i].image_type_id);
return 0;
}
@@ -332,24 +330,20 @@ int fwu_set_active_index(uint active_idx)
}
/**
- * fwu_get_image_index() - Get the Image Index to be used for capsule update
- * @image_index: The Image Index for the image
- *
- * The FWU multi bank update feature computes the value of image_index at
- * runtime, based on the bank to which the image needs to be written to.
- * Derive the image_index value for the image.
+ * fwu_get_dfu_alt_num() - Get the dfu_alt_num to be used for capsule update
+ * @image_index: The Image Index for the image
+ * @alt_num: pointer to store dfu_alt_num
*
* Currently, the capsule update driver uses the DFU framework for
* the updates. This function gets the DFU alt number which is to
- * be used as the Image Index
+ * be used for capsule update.
*
* Return: 0 if OK, -ve on error
*
*/
-int fwu_get_image_index(u8 *image_index)
+int fwu_get_dfu_alt_num(u8 image_index, u8 *alt_num)
{
int ret, i;
- u8 alt_num;
uint update_bank;
efi_guid_t *image_guid, image_type_id;
struct fwu_mdata *mdata = &g_mdata;
@@ -365,7 +359,7 @@ int fwu_get_image_index(u8 *image_index)
ret = fwu_get_image_type_id(image_index, &image_type_id);
if (ret) {
log_debug("Unable to get image_type_id for image_index %u\n",
- *image_index);
+ image_index);
goto out;
}
@@ -380,15 +374,13 @@ int fwu_get_image_index(u8 *image_index)
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(g_dev, image_guid, &alt_num);
- if (ret) {
+ 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);
- } else {
+ else
log_debug("alt_num %d for partition %pUs\n",
- alt_num, image_guid);
- *image_index = alt_num + 1;
- }
+ *alt_num, image_guid);
goto out;
}
diff --git a/lib/membuff.c b/lib/membuff.c
index 3c6c0ae125..b242a38ff1 100644
--- a/lib/membuff.c
+++ b/lib/membuff.c
@@ -287,7 +287,7 @@ int membuff_free(struct membuff *mb)
(mb->end - mb->start) - 1 - membuff_avail(mb);
}
-int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch)
+int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch, bool must_fit)
{
int len; /* number of bytes read (!= string length) */
char *s, *end;
@@ -309,7 +309,7 @@ int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch)
}
/* couldn't get the whole string */
- if (!ok) {
+ if (!ok && must_fit) {
if (maxlen)
*orig = '\0';
return 0;
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 858ad92a6f..2304030e32 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -104,6 +104,8 @@ static int rsa_engine_get_pub_key(const char *keydir, const char *name,
const char *engine_id;
char key_id[1024];
EVP_PKEY *key = NULL;
+ const char *const pkcs11_schema = "pkcs11:";
+ const char *pkcs11_uri_prepend = "";
if (!evpp)
return -EINVAL;
@@ -113,19 +115,26 @@ static int rsa_engine_get_pub_key(const char *keydir, const char *name,
engine_id = ENGINE_get_id(engine);
if (engine_id && !strcmp(engine_id, "pkcs11")) {
- if (keydir)
+ if (keydir) {
+ // Check for legacy keydir spec and prepend
+ if (strncmp(pkcs11_schema, keydir, strlen(pkcs11_schema))) {
+ pkcs11_uri_prepend = pkcs11_schema;
+ fprintf(stderr, "WARNING: Legacy URI specified. Please add '%s'.\n", pkcs11_schema);
+ }
+
if (strstr(keydir, "object="))
snprintf(key_id, sizeof(key_id),
- "%s;type=public",
- keydir);
+ "%s%s;type=public",
+ pkcs11_uri_prepend, keydir);
else
snprintf(key_id, sizeof(key_id),
- "%s;object=%s;type=public",
- keydir, name);
- else
+ "%s%s;object=%s;type=public",
+ pkcs11_uri_prepend, keydir, name);
+ } else {
snprintf(key_id, sizeof(key_id),
- "object=%s;type=public",
+ "pkcs11:object=%s;type=public",
name);
+ }
} else if (engine_id) {
if (keydir)
snprintf(key_id, sizeof(key_id),
@@ -224,6 +233,8 @@ static int rsa_engine_get_priv_key(const char *keydir, const char *name,
const char *engine_id;
char key_id[1024];
EVP_PKEY *key = NULL;
+ const char *const pkcs11_schema = "pkcs11:";
+ const char *pkcs11_uri_prepend = "";
if (!evpp)
return -EINVAL;
@@ -235,19 +246,26 @@ static int rsa_engine_get_priv_key(const char *keydir, const char *name,
fprintf(stderr, "Please use 'keydir' with PKCS11\n");
return -EINVAL;
}
- if (keydir)
+ if (keydir) {
+ // Check for legacy keydir spec and prepend
+ if (strncmp(pkcs11_schema, keydir, strlen(pkcs11_schema))) {
+ pkcs11_uri_prepend = pkcs11_schema;
+ fprintf(stderr, "WARNING: Legacy URI specified. Please add '%s'.\n", pkcs11_schema);
+ }
+
if (strstr(keydir, "object="))
snprintf(key_id, sizeof(key_id),
- "%s;type=private",
- keydir);
+ "%s%s;type=private",
+ pkcs11_uri_prepend, keydir);
else
snprintf(key_id, sizeof(key_id),
- "%s;object=%s;type=private",
- keydir, name);
- else
+ "%s%s;object=%s;type=private",
+ pkcs11_uri_prepend, keydir, name);
+ } else {
snprintf(key_id, sizeof(key_id),
- "object=%s;type=private",
+ "pkcs11:object=%s;type=private",
name);
+ }
} else if (engine_id) {
if (keydir && name)
snprintf(key_id, sizeof(key_id),
diff --git a/lib/smbios-parser.c b/lib/smbios-parser.c
index b578c30840..ac9a367a87 100644
--- a/lib/smbios-parser.c
+++ b/lib/smbios-parser.c
@@ -5,22 +5,11 @@
#define LOG_CATEGORY LOGC_BOOT
+#include <errno.h>
#include <smbios.h>
-
-static inline int verify_checksum(const struct smbios_entry *e)
-{
- /*
- * Checksums for SMBIOS tables are calculated to have a value, so that
- * the sum over all bytes yields zero (using unsigned 8 bit arithmetic).
- */
- u8 *byte = (u8 *)e;
- u8 sum = 0;
-
- for (int i = 0; i < e->length; i++)
- sum += byte[i];
-
- return sum;
-}
+#include <string.h>
+#include <tables_csum.h>
+#include <linux/kernel.h>
const struct smbios_entry *smbios_entry(u64 address, u32 size)
{
@@ -32,7 +21,7 @@ const struct smbios_entry *smbios_entry(u64 address, u32 size)
if (memcmp(entry->anchor, "_SM_", 4))
return NULL;
- if (verify_checksum(entry))
+ if (table_compute_checksum(entry, entry->length))
return NULL;
return entry;
@@ -50,14 +39,7 @@ static u8 *find_next_header(u8 *pos)
return pos;
}
-static struct smbios_header *get_next_header(struct smbios_header *curr)
-{
- u8 *pos = ((u8 *)curr) + curr->length;
-
- return (struct smbios_header *)find_next_header(pos);
-}
-
-static const struct smbios_header *next_header(const struct smbios_header *curr)
+static struct smbios_header *get_next_header(const struct smbios_header *curr)
{
u8 *pos = ((u8 *)curr) + curr->length;
@@ -73,7 +55,7 @@ const struct smbios_header *smbios_header(const struct smbios_entry *entry, int
if (header->type == type)
return header;
- header = next_header(header);
+ header = get_next_header(header);
}
return NULL;
diff --git a/lib/smbios.c b/lib/smbios.c
index d9d52bd58d..7bd9805fec 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -48,38 +48,44 @@ DECLARE_GLOBAL_DATA_PTR;
/**
* struct map_sysinfo - Mapping of sysinfo strings to DT
*
- * @sysinfo_str: sysinfo string
+ * @si_str: sysinfo string
* @dt_str: DT string
* @max: Max index of the tokenized string to pick. Counting starts from 0
*
*/
struct map_sysinfo {
- const char *sysinfo_str;
+ const char *si_node;
+ const char *si_str;
const char *dt_str;
int max;
};
static const struct map_sysinfo sysinfo_to_dt[] = {
- { .sysinfo_str = "product", .dt_str = "model", 2 },
- { .sysinfo_str = "manufacturer", .dt_str = "compatible", 1 },
+ { .si_node = "system", .si_str = "product", .dt_str = "model", 2 },
+ { .si_node = "system", .si_str = "manufacturer", .dt_str = "compatible", 1 },
+ { .si_node = "baseboard", .si_str = "product", .dt_str = "model", 2 },
+ { .si_node = "baseboard", .si_str = "manufacturer", .dt_str = "compatible", 1 },
};
/**
* struct smbios_ctx - context for writing SMBIOS tables
*
- * @node: node containing the information to write (ofnode_null() if none)
- * @dev: sysinfo device to use (NULL if none)
- * @eos: end-of-string pointer for the table being processed. This is set
- * up when we start processing a table
- * @next_ptr: pointer to the start of the next string to be added. When the
- * table is nopt empty, this points to the byte after the \0 of the
- * previous string.
- * @last_str: points to the last string that was written to the table, or NULL
- * if none
+ * @node: node containing the information to write (ofnode_null()
+ * if none)
+ * @dev: sysinfo device to use (NULL if none)
+ * @subnode_name: sysinfo subnode_name. Used for DT fallback
+ * @eos: end-of-string pointer for the table being processed.
+ * This is set up when we start processing a table
+ * @next_ptr: pointer to the start of the next string to be added.
+ * When the table is not empty, this points to the byte
+ * after the \0 of the previous string.
+ * @last_str: points to the last string that was written to the table,
+ * or NULL if none
*/
struct smbios_ctx {
ofnode node;
struct udevice *dev;
+ const char *subnode_name;
char *eos;
char *next_ptr;
char *last_str;
@@ -108,12 +114,13 @@ struct smbios_write_method {
const char *subnode_name;
};
-static const struct map_sysinfo *convert_sysinfo_to_dt(const char *sysinfo_str)
+static const struct map_sysinfo *convert_sysinfo_to_dt(const char *node, const char *si)
{
int i;
for (i = 0; i < ARRAY_SIZE(sysinfo_to_dt); i++) {
- if (!strcmp(sysinfo_str, sysinfo_to_dt[i].sysinfo_str))
+ if (node && !strcmp(node, sysinfo_to_dt[i].si_node) &&
+ !strcmp(si, sysinfo_to_dt[i].si_str))
return &sysinfo_to_dt[i];
}
@@ -233,7 +240,7 @@ static int smbios_add_prop_si(struct smbios_ctx *ctx, const char *prop,
} else {
const struct map_sysinfo *nprop;
- nprop = convert_sysinfo_to_dt(prop);
+ nprop = convert_sysinfo_to_dt(ctx->subnode_name, prop);
get_str_from_dt(nprop, str_dt, sizeof(str_dt));
str = (const char *)str_dt;
}
@@ -467,7 +474,8 @@ static void smbios_write_type4_dm(struct smbios_type4 *t,
}
#endif
- t->processor_family = processor_family;
+ t->processor_family = 0xfe;
+ t->processor_family2 = processor_family;
t->processor_manufacturer = smbios_add_prop(ctx, NULL, vendor);
t->processor_version = smbios_add_prop(ctx, NULL, name);
}
@@ -489,7 +497,6 @@ static int smbios_write_type4(ulong *current, int handle,
t->l1_cache_handle = 0xffff;
t->l2_cache_handle = 0xffff;
t->l3_cache_handle = 0xffff;
- t->processor_family2 = t->processor_family;
len = t->length + smbios_string_table_len(ctx);
*current += len;
@@ -574,9 +581,13 @@ ulong write_smbios_table(ulong addr)
int tmp;
method = &smbios_write_funcs[i];
- if (IS_ENABLED(CONFIG_OF_CONTROL) && method->subnode_name)
- ctx.node = ofnode_find_subnode(parent_node,
- method->subnode_name);
+ ctx.subnode_name = NULL;
+ if (method->subnode_name) {
+ ctx.subnode_name = method->subnode_name;
+ if (IS_ENABLED(CONFIG_OF_CONTROL))
+ ctx.node = ofnode_find_subnode(parent_node,
+ method->subnode_name);
+ }
tmp = method->write((ulong *)&addr, handle++, &ctx);
max_struct_size = max(max_struct_size, tmp);
@@ -591,8 +602,8 @@ ulong write_smbios_table(ulong addr)
table_addr = (ulong)map_sysmem(tables, 0);
/* now go back and write the SMBIOS3 header */
- se = map_sysmem(start_addr, sizeof(struct smbios_entry));
- memset(se, '\0', sizeof(struct smbios_entry));
+ se = map_sysmem(start_addr, sizeof(struct smbios3_entry));
+ memset(se, '\0', sizeof(struct smbios3_entry));
memcpy(se->anchor, "_SM3_", 5);
se->length = sizeof(struct smbios3_entry);
se->major_ver = SMBIOS_MAJOR_VER;
diff --git a/lib/tables_csum.c b/lib/tables_csum.c
index 636aa59676..305b1ec31c 100644
--- a/lib/tables_csum.c
+++ b/lib/tables_csum.c
@@ -5,9 +5,9 @@
#include <linux/types.h>
-u8 table_compute_checksum(void *v, int len)
+u8 table_compute_checksum(const void *v, const int len)
{
- u8 *bytes = v;
+ const u8 *bytes = v;
u8 checksum = 0;
int i;