aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig10
-rw-r--r--lib/acpi/acpi_device.c33
-rw-r--r--lib/crypto/pkcs7_verify.c37
-rw-r--r--lib/efi/efi_stub.c2
-rw-r--r--lib/efi_driver/efi_block_device.c22
-rw-r--r--lib/efi_driver/efi_uclass.c18
-rw-r--r--lib/efi_loader/Kconfig97
-rw-r--r--lib/efi_loader/Makefile4
-rw-r--r--lib/efi_loader/efi_boottime.c273
-rw-r--r--lib/efi_loader/efi_capsule.c1032
-rw-r--r--lib/efi_loader/efi_device_path.c18
-rw-r--r--lib/efi_loader/efi_disk.c22
-rw-r--r--lib/efi_loader/efi_firmware.c478
-rw-r--r--lib/efi_loader/efi_hii_config.c10
-rw-r--r--lib/efi_loader/efi_load_initrd.c11
-rw-r--r--lib/efi_loader/efi_root_node.c3
-rw-r--r--lib/efi_loader/efi_runtime.c100
-rw-r--r--lib/efi_loader/efi_setup.c93
-rw-r--r--lib/efi_loader/efi_signature.c192
-rw-r--r--lib/efi_loader/efi_string.c10
-rw-r--r--lib/efi_loader/efi_tcg2.c553
-rw-r--r--lib/efi_loader/efi_variable.c93
-rw-r--r--lib/efi_selftest/Makefile17
-rw-r--r--lib/efi_selftest/efi_selftest_load_file.c475
-rw-r--r--lib/efi_selftest/efi_selftest_load_initrd.c7
-rw-r--r--lib/efi_selftest/efi_selftest_miniapp_exception.c2
-rw-r--r--lib/fdtdec.c11
-rw-r--r--lib/hashtable.c12
-rw-r--r--lib/smbios.c2
-rw-r--r--lib/time.c10
-rw-r--r--lib/tpm-v2.c11
31 files changed, 3233 insertions, 425 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index 7673d2e..a704568 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -168,7 +168,7 @@ config REGEX
choice
prompt "Pseudo-random library support type"
depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \
- RNG_SANDBOX || UT_LIB && AES
+ RNG_SANDBOX || UT_LIB && AES || FAT_WRITE
default LIB_RAND
help
Select the library to provide pseudo-random number generator
@@ -699,3 +699,11 @@ config LIB_ELF
This supports fir 32 bit and 64 bit versions.
endmenu
+
+config PHANDLE_CHECK_SEQ
+ bool "Enable phandle check while getting sequence number"
+ default n
+ help
+ When there are multiple device tree nodes with same name,
+ enable this config option to distinguish them using
+ phandles in fdtdec_get_alias_seq() function.
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index c3439a5..b5f2ceb 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -602,7 +602,7 @@ static void acpi_device_write_i2c(struct acpi_ctx *ctx,
static int acpi_device_set_i2c(const struct udevice *dev, struct acpi_i2c *i2c,
const char *scope)
{
- struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+ struct dm_i2c_chip *chip = dev_get_parent_plat(dev);
struct udevice *bus = dev_get_parent(dev);
memset(i2c, '\0', sizeof(*i2c));
@@ -724,10 +724,10 @@ static void acpi_device_write_spi(struct acpi_ctx *ctx, const struct acpi_spi *s
static int acpi_device_set_spi(const struct udevice *dev, struct acpi_spi *spi,
const char *scope)
{
- struct dm_spi_slave_platdata *plat;
+ struct dm_spi_slave_plat *plat;
struct spi_slave *slave = dev_get_parent_priv(dev);
- plat = dev_get_parent_platdata(slave->dev);
+ plat = dev_get_parent_plat(slave->dev);
memset(spi, '\0', sizeof(*spi));
spi->device_select = plat->cs;
spi->device_select_polarity = SPI_POLARITY_LOW;
@@ -784,16 +784,6 @@ static const char *acpi_name_from_id(enum uclass_id id)
}
}
-static int acpi_check_seq(const struct udevice *dev)
-{
- if (dev->req_seq == -1) {
- log_warning("Device '%s' has no seq\n", dev->name);
- return log_msg_ret("no seq", -ENXIO);
- }
-
- return dev->req_seq;
-}
-
/* If you change this function, add test cases to dm_test_acpi_get_name() */
int acpi_device_infer_name(const struct udevice *dev, char *out_name)
{
@@ -826,29 +816,18 @@ int acpi_device_infer_name(const struct udevice *dev, char *out_name)
}
}
if (!name) {
- int num;
-
switch (id) {
/* DSDT: acpi/lpss.asl */
case UCLASS_SERIAL:
- num = acpi_check_seq(dev);
- if (num < 0)
- return num;
- sprintf(out_name, "URT%d", num);
+ sprintf(out_name, "URT%d", dev_seq(dev));
name = out_name;
break;
case UCLASS_I2C:
- num = acpi_check_seq(dev);
- if (num < 0)
- return num;
- sprintf(out_name, "I2C%d", num);
+ sprintf(out_name, "I2C%d", dev_seq(dev));
name = out_name;
break;
case UCLASS_SPI:
- num = acpi_check_seq(dev);
- if (num < 0)
- return num;
- sprintf(out_name, "SPI%d", num);
+ sprintf(out_name, "SPI%d", dev_seq(dev));
name = out_name;
break;
default:
diff --git a/lib/crypto/pkcs7_verify.c b/lib/crypto/pkcs7_verify.c
index 320ba49..58683ef 100644
--- a/lib/crypto/pkcs7_verify.c
+++ b/lib/crypto/pkcs7_verify.c
@@ -50,8 +50,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct image_region regions[2];
int ret = 0;
- /* The digest was calculated already. */
- if (sig->digest)
+ /*
+ * [RFC2315 9.3]
+ * If the authenticated attributes are present,
+ * the message-digest is calculated on the
+ * attributes present in the
+ * authenticatedAttributes field and not just
+ * the contents field
+ */
+ if (!sinfo->authattrs && sig->digest)
return 0;
if (!sinfo->sig->hash_algo)
@@ -63,17 +70,25 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
else
return -ENOPKG;
- sig->digest = calloc(1, sig->digest_size);
- if (!sig->digest) {
- pr_warn("Sig %u: Out of memory\n", sinfo->index);
- return -ENOMEM;
- }
+ /*
+ * Calculate the hash only if the data is present.
+ * In case of authenticated variable and capsule,
+ * the hash has already been calculated on the
+ * efi_image_regions and populated
+ */
+ if (pkcs7->data) {
+ sig->digest = calloc(1, sig->digest_size);
+ if (!sig->digest) {
+ pr_warn("Sig %u: Out of memory\n", sinfo->index);
+ return -ENOMEM;
+ }
- regions[0].data = pkcs7->data;
- regions[0].size = pkcs7->data_len;
+ regions[0].data = pkcs7->data;
+ regions[0].size = pkcs7->data_len;
- /* Digest the message [RFC2315 9.3] */
- hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+ /* Digest the message [RFC2315 9.3] */
+ hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+ }
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
index 7d650d5..b3393e4 100644
--- a/lib/efi/efi_stub.c
+++ b/lib/efi/efi_stub.c
@@ -67,7 +67,7 @@ void putc(const char ch)
putc('\r');
if (use_uart) {
- NS16550_t com_port = (NS16550_t)0x3f8;
+ struct ns16550 *com_port = (struct ns16550 *)0x3f8;
while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0)
;
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 0e72a68..0937e35 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -42,7 +42,7 @@
* handle handle of the controller on which this driver is installed
* io block io protocol proxied by this driver
*/
-struct efi_blk_platdata {
+struct efi_blk_plat {
efi_handle_t handle;
struct efi_block_io *io;
};
@@ -59,8 +59,8 @@ struct efi_blk_platdata {
static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
void *buffer)
{
- struct efi_blk_platdata *platdata = dev_get_platdata(dev);
- struct efi_block_io *io = platdata->io;
+ struct efi_blk_plat *plat = dev_get_plat(dev);
+ struct efi_block_io *io = plat->io;
efi_status_t ret;
EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n",
@@ -88,8 +88,8 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
const void *buffer)
{
- struct efi_blk_platdata *platdata = dev_get_platdata(dev);
- struct efi_block_io *io = platdata->io;
+ struct efi_blk_plat *plat = dev_get_plat(dev);
+ struct efi_block_io *io = plat->io;
efi_status_t ret;
EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n",
@@ -118,7 +118,7 @@ static int efi_bl_bind_partitions(efi_handle_t handle, struct udevice *dev)
struct blk_desc *desc;
const char *if_typename;
- desc = dev_get_uclass_platdata(dev);
+ desc = dev_get_uclass_plat(dev);
if_typename = blk_get_if_type_name(desc->if_type);
return efi_disk_create_partitions(handle, desc, if_typename,
@@ -140,7 +140,7 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
struct efi_object *obj = efi_search_obj(handle);
struct efi_block_io *io = interface;
int disks;
- struct efi_blk_platdata *platdata;
+ struct efi_blk_plat *plat;
EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
@@ -169,9 +169,9 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
/* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */
device_set_name_alloced(bdev);
- platdata = dev_get_platdata(bdev);
- platdata->handle = handle;
- platdata->io = interface;
+ plat = dev_get_plat(bdev);
+ plat->handle = handle;
+ plat->io = interface;
ret = device_probe(bdev);
if (ret)
@@ -196,7 +196,7 @@ U_BOOT_DRIVER(efi_blk) = {
.name = "efi_blk",
.id = UCLASS_BLK,
.ops = &efi_blk_ops,
- .platdata_auto_alloc_size = sizeof(struct efi_blk_platdata),
+ .plat_auto = sizeof(struct efi_blk_plat),
};
/* EFI driver operators */
diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
index 0cf74b0..382c2b4 100644
--- a/lib/efi_driver/efi_uclass.c
+++ b/lib/efi_driver/efi_uclass.c
@@ -238,7 +238,7 @@ static efi_status_t EFIAPI efi_uc_stop(
}
ret = EFI_CALL(systab.boottime->free_pool(entry_buffer));
if (ret != EFI_SUCCESS)
- printf("%s: ERROR: Cannot free pool\n", __func__);
+ log_err("Cannot free EFI memory pool\n");
/* Detach driver from controller */
ret = EFI_CALL(systab.boottime->close_protocol(
@@ -260,10 +260,10 @@ static efi_status_t efi_add_driver(struct driver *drv)
const struct efi_driver_ops *ops = drv->ops;
struct efi_driver_binding_extended_protocol *bp;
- debug("EFI: Adding driver '%s'\n", drv->name);
+ log_debug("Adding EFI driver '%s'\n", drv->name);
if (!ops->protocol) {
- printf("EFI: ERROR: protocol GUID missing for driver '%s'\n",
- drv->name);
+ log_err("EFI protocol GUID missing for driver '%s'\n",
+ drv->name);
return EFI_INVALID_PARAMETER;
}
bp = calloc(1, sizeof(struct efi_driver_binding_extended_protocol));
@@ -305,14 +305,14 @@ efi_status_t efi_driver_init(void)
struct driver *drv;
efi_status_t ret = EFI_SUCCESS;
- debug("EFI: Initializing EFI driver framework\n");
+ log_debug("Initializing EFI driver framework\n");
for (drv = ll_entry_start(struct driver, driver);
drv < ll_entry_end(struct driver, driver); ++drv) {
if (drv->id == UCLASS_EFI) {
ret = efi_add_driver(drv);
if (ret != EFI_SUCCESS) {
- printf("EFI: ERROR: failed to add driver %s\n",
- drv->name);
+ log_err("Failed to add EFI driver %s\n",
+ drv->name);
break;
}
}
@@ -328,7 +328,7 @@ efi_status_t efi_driver_init(void)
*/
static int efi_uc_init(struct uclass *class)
{
- printf("EFI: Initializing UCLASS_EFI\n");
+ log_debug("Initializing UCLASS_EFI\n");
return 0;
}
@@ -340,7 +340,7 @@ static int efi_uc_init(struct uclass *class)
*/
static int efi_uc_destroy(struct uclass *class)
{
- printf("Destroying UCLASS_EFI\n");
+ log_debug("Destroying UCLASS_EFI\n");
return 0;
}
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index dd8b93b..fdf245d 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -108,6 +108,91 @@ config EFI_SET_TIME
Provide the SetTime() runtime service at boottime. This service
can be used by an EFI application to adjust the real time clock.
+config EFI_HAVE_CAPSULE_SUPPORT
+ bool
+
+config EFI_RUNTIME_UPDATE_CAPSULE
+ bool "UpdateCapsule() runtime service"
+ default n
+ select EFI_HAVE_CAPSULE_SUPPORT
+ help
+ Select this option if you want to use UpdateCapsule and
+ QueryCapsuleCapabilities API's.
+
+config EFI_CAPSULE_ON_DISK
+ bool "Enable capsule-on-disk support"
+ select EFI_HAVE_CAPSULE_SUPPORT
+ default n
+ help
+ Select this option if you want to use capsule-on-disk feature,
+ that is, capsules can be fetched and executed from files
+ under a specific directory on UEFI system partition instead of
+ via UpdateCapsule API.
+
+config EFI_CAPSULE_ON_DISK_EARLY
+ bool "Initiate capsule-on-disk at U-Boot boottime"
+ depends on EFI_CAPSULE_ON_DISK
+ default n
+ select EFI_SETUP_EARLY
+ help
+ Normally, without this option enabled, capsules will be
+ executed only at the first time of invoking one of efi command.
+ If this option is enabled, capsules will be enforced to be
+ executed as part of U-Boot initialisation so that they will
+ surely take place whatever is set to distro_bootcmd.
+
+config EFI_CAPSULE_FIRMWARE
+ bool
+ default n
+
+config EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ bool "Capsule: Firmware Management Protocol"
+ depends on EFI_HAVE_CAPSULE_SUPPORT
+ default y
+ help
+ Select this option if you want to enable capsule-based
+ firmware update using Firmware Management Protocol.
+
+config EFI_CAPSULE_AUTHENTICATE
+ bool "Update Capsule authentication"
+ depends on EFI_CAPSULE_FIRMWARE
+ depends on EFI_CAPSULE_ON_DISK
+ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ select SHA256
+ select RSA
+ select RSA_VERIFY
+ select RSA_VERIFY_WITH_PKEY
+ select X509_CERTIFICATE_PARSER
+ select PKCS7_MESSAGE_PARSER
+ select PKCS7_VERIFY
+ default n
+ help
+ Select this option if you want to enable capsule
+ authentication
+
+config EFI_CAPSULE_FIRMWARE_FIT
+ bool "FMP driver for FIT image"
+ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ depends on FIT
+ select UPDATE_FIT
+ select DFU
+ select EFI_CAPSULE_FIRMWARE
+ default n
+ help
+ Select this option if you want to enable firmware management protocol
+ driver for FIT image
+
+config EFI_CAPSULE_FIRMWARE_RAW
+ bool "FMP driver for raw image"
+ depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT
+ select DFU
+ select DFU_WRITE_ALT
+ select EFI_CAPSULE_FIRMWARE
+ default n
+ help
+ Select this option if you want to enable firmware management protocol
+ driver for raw image
+
config EFI_DEVICE_PATH_TO_TEXT
bool "Device path to text protocol"
default y
@@ -179,7 +264,8 @@ config EFI_HAVE_RUNTIME_RESET
# bool "Reset runtime service is available"
bool
default y
- depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || SYSRESET_X86
+ depends on ARCH_BCM283X || FSL_LAYERSCAPE || PSCI_RESET || \
+ SANDBOX || SYSRESET_X86
config EFI_GRUB_ARM32_WORKAROUND
bool "Workaround for GRUB on 32bit ARM"
@@ -206,6 +292,15 @@ config EFI_TCG2_PROTOCOL
Provide a EFI_TCG2_PROTOCOL implementation using the TPM hardware
of the platform.
+config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
+ int "EFI_TCG2_PROTOCOL EventLog size"
+ depends on EFI_TCG2_PROTOCOL
+ default 4096
+ help
+ Define the size of the EventLog for EFI_TCG2_PROTOCOL. Note that
+ this is going to be allocated twice. One for the eventlog it self
+ and one for the configuration table that is required from the spec
+
config EFI_LOAD_FILE2_INITRD
bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk"
default n
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index cd4b252..462d4d9 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -23,12 +23,14 @@ endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-y += efi_bootmgr.o
obj-y += efi_boottime.o
+obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
+obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
obj-y += efi_console.o
obj-y += efi_device_path.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o
obj-y += efi_device_path_utilities.o
obj-y += efi_file.o
-obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o
+obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o
obj-y += efi_image_loader.o
obj-y += efi_memory.o
obj-y += efi_root_node.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index a89bdb3..b2cb016 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -81,6 +81,9 @@ const efi_guid_t efi_guid_event_group_ready_to_boot =
/* event group ResetSystem() invoked (before ExitBootServices) */
const efi_guid_t efi_guid_event_group_reset_system =
EFI_EVENT_GROUP_RESET_SYSTEM;
+/* GUIDs of the Load File and Load File2 protocols */
+const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID;
+const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID;
static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t controller_handle,
@@ -244,8 +247,8 @@ static void efi_queue_event(struct efi_event *event)
}
if (event)
list_add_tail(&event->queue_link, &efi_event_queue);
+ efi_process_event_queue();
}
- efi_process_event_queue();
}
/**
@@ -1770,30 +1773,108 @@ failure:
}
/**
- * efi_load_image_from_path() - load an image using a file path
+ * efi_locate_device_path() - Get the device path and handle of an device
+ * implementing a protocol
+ * @protocol: GUID of the protocol
+ * @device_path: device path
+ * @device: handle of the device
+ *
+ * This function implements the LocateDevicePath service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_locate_device_path(
+ const efi_guid_t *protocol,
+ struct efi_device_path **device_path,
+ efi_handle_t *device)
+{
+ struct efi_device_path *dp;
+ size_t i;
+ struct efi_handler *handler;
+ efi_handle_t *handles;
+ size_t len, len_dp;
+ size_t len_best = 0;
+ efi_uintn_t no_handles;
+ u8 *remainder;
+ efi_status_t ret;
+
+ EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
+
+ if (!protocol || !device_path || !*device_path) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /* Find end of device path */
+ len = efi_dp_instance_size(*device_path);
+
+ /* Get all handles implementing the protocol */
+ ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
+ &no_handles, &handles));
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ for (i = 0; i < no_handles; ++i) {
+ /* Find the device path protocol */
+ ret = efi_search_protocol(handles[i], &efi_guid_device_path,
+ &handler);
+ if (ret != EFI_SUCCESS)
+ continue;
+ dp = (struct efi_device_path *)handler->protocol_interface;
+ len_dp = efi_dp_instance_size(dp);
+ /*
+ * This handle can only be a better fit
+ * if its device path length is longer than the best fit and
+ * if its device path length is shorter of equal the searched
+ * device path.
+ */
+ if (len_dp <= len_best || len_dp > len)
+ continue;
+ /* Check if dp is a subpath of device_path */
+ if (memcmp(*device_path, dp, len_dp))
+ continue;
+ if (!device) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+ *device = handles[i];
+ len_best = len_dp;
+ }
+ if (len_best) {
+ remainder = (u8 *)*device_path + len_best;
+ *device_path = (struct efi_device_path *)remainder;
+ ret = EFI_SUCCESS;
+ } else {
+ ret = EFI_NOT_FOUND;
+ }
+out:
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_load_image_from_file() - load an image from file system
*
* Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the
* callers obligation to update the memory type as needed.
*
- * @file_path: the path of the image to load
- * @buffer: buffer containing the loaded image
- * @size: size of the loaded image
- * Return: status code
+ * @file_path: the path of the image to load
+ * @buffer: buffer containing the loaded image
+ * @size: size of the loaded image
+ * Return: status code
*/
static
-efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
+efi_status_t efi_load_image_from_file(struct efi_device_path *file_path,
void **buffer, efi_uintn_t *size)
{
struct efi_file_info *info = NULL;
struct efi_file_handle *f;
- static efi_status_t ret;
+ efi_status_t ret;
u64 addr;
efi_uintn_t bs;
- /* In case of failure nothing is returned */
- *buffer = NULL;
- *size = 0;
-
/* Open file */
f = efi_file_from_path(file_path);
if (!f)
@@ -1842,6 +1923,86 @@ error:
}
/**
+ * efi_load_image_from_path() - load an image using a file path
+ *
+ * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the
+ * callers obligation to update the memory type as needed.
+ *
+ * @boot_policy: true for request originating from the boot manager
+ * @file_path: the path of the image to load
+ * @buffer: buffer containing the loaded image
+ * @size: size of the loaded image
+ * Return: status code
+ */
+static
+efi_status_t efi_load_image_from_path(bool boot_policy,
+ struct efi_device_path *file_path,
+ void **buffer, efi_uintn_t *size)
+{
+ efi_handle_t device;
+ efi_status_t ret;
+ struct efi_device_path *dp;
+ struct efi_load_file_protocol *load_file_protocol = NULL;
+ efi_uintn_t buffer_size;
+ uint64_t addr, pages;
+ const efi_guid_t *guid;
+
+ /* In case of failure nothing is returned */
+ *buffer = NULL;
+ *size = 0;
+
+ dp = file_path;
+ ret = EFI_CALL(efi_locate_device_path(
+ &efi_simple_file_system_protocol_guid, &dp, &device));
+ if (ret == EFI_SUCCESS)
+ return efi_load_image_from_file(file_path, buffer, size);
+
+ ret = EFI_CALL(efi_locate_device_path(
+ &efi_guid_load_file_protocol, &dp, &device));
+ if (ret == EFI_SUCCESS) {
+ guid = &efi_guid_load_file_protocol;
+ } else if (!boot_policy) {
+ guid = &efi_guid_load_file2_protocol;
+ ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device));
+ }
+ if (ret != EFI_SUCCESS)
+ return EFI_NOT_FOUND;
+ ret = EFI_CALL(efi_handle_protocol(device, guid,
+ (void **)&load_file_protocol));
+ if (ret != EFI_SUCCESS)
+ return EFI_NOT_FOUND;
+ buffer_size = 0;
+ ret = load_file_protocol->load_file(load_file_protocol, dp,
+ boot_policy, &buffer_size,
+ NULL);
+ if (ret != EFI_BUFFER_TOO_SMALL)
+ goto out;
+ pages = efi_size_in_pages(buffer_size);
+ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_BOOT_SERVICES_DATA,
+ pages, &addr);
+ if (ret != EFI_SUCCESS) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ ret = EFI_CALL(load_file_protocol->load_file(
+ load_file_protocol, dp, boot_policy,
+ &buffer_size, (void *)(uintptr_t)addr));
+ if (ret != EFI_SUCCESS)
+ efi_free_pages(addr, pages);
+out:
+ if (load_file_protocol)
+ EFI_CALL(efi_close_protocol(device,
+ &efi_guid_load_file2_protocol,
+ efi_root, NULL));
+ if (ret == EFI_SUCCESS) {
+ *buffer = (void *)(uintptr_t)addr;
+ *size = buffer_size;
+ }
+
+ return ret;
+}
+
+/**
* efi_load_image() - load an EFI image into memory
* @boot_policy: true for request originating from the boot manager
* @parent_image: the caller's image handle
@@ -1883,8 +2044,8 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
}
if (!source_buffer) {
- ret = efi_load_image_from_path(file_path, &dest_buffer,
- &source_size);
+ ret = efi_load_image_from_path(boot_policy, file_path,
+ &dest_buffer, &source_size);
if (ret != EFI_SUCCESS)
goto error;
} else {
@@ -2404,88 +2565,6 @@ found:
}
/**
- * efi_locate_device_path() - Get the device path and handle of an device
- * implementing a protocol
- * @protocol: GUID of the protocol
- * @device_path: device path
- * @device: handle of the device
- *
- * This function implements the LocateDevicePath service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * Return: status code
- */
-static efi_status_t EFIAPI efi_locate_device_path(
- const efi_guid_t *protocol,
- struct efi_device_path **device_path,
- efi_handle_t *device)
-{
- struct efi_device_path *dp;
- size_t i;
- struct efi_handler *handler;
- efi_handle_t *handles;
- size_t len, len_dp;
- size_t len_best = 0;
- efi_uintn_t no_handles;
- u8 *remainder;
- efi_status_t ret;
-
- EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
-
- if (!protocol || !device_path || !*device_path) {
- ret = EFI_INVALID_PARAMETER;
- goto out;
- }
-
- /* Find end of device path */
- len = efi_dp_instance_size(*device_path);
-
- /* Get all handles implementing the protocol */
- ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
- &no_handles, &handles));
- if (ret != EFI_SUCCESS)
- goto out;
-
- for (i = 0; i < no_handles; ++i) {
- /* Find the device path protocol */
- ret = efi_search_protocol(handles[i], &efi_guid_device_path,
- &handler);
- if (ret != EFI_SUCCESS)
- continue;
- dp = (struct efi_device_path *)handler->protocol_interface;
- len_dp = efi_dp_instance_size(dp);
- /*
- * This handle can only be a better fit
- * if its device path length is longer than the best fit and
- * if its device path length is shorter of equal the searched
- * device path.
- */
- if (len_dp <= len_best || len_dp > len)
- continue;
- /* Check if dp is a subpath of device_path */
- if (memcmp(*device_path, dp, len_dp))
- continue;
- if (!device) {
- ret = EFI_INVALID_PARAMETER;
- goto out;
- }
- *device = handles[i];
- len_best = len_dp;
- }
- if (len_best) {
- remainder = (u8 *)*device_path + len_best;
- *device_path = (struct efi_device_path *)remainder;
- ret = EFI_SUCCESS;
- } else {
- ret = EFI_NOT_FOUND;
- }
-out:
- return EFI_EXIT(ret);
-}
-
-/**
* efi_install_multiple_protocol_interfaces() - Install multiple protocol
* interfaces
* @handle: handle on which the protocol interfaces shall be installed
@@ -2700,7 +2779,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value)
*
* Return: status code
*/
-static efi_status_t efi_protocol_open(
+efi_status_t efi_protocol_open(
struct efi_handler *handler,
void **protocol_interface, void *agent_handle,
void *controller_handle, uint32_t attributes)
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
new file mode 100644
index 0000000..dad1b0f
--- /dev/null
+++ b/lib/efi_loader/efi_capsule.c
@@ -0,0 +1,1032 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI Capsule
+ *
+ * Copyright (c) 2018 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <efi_variable.h>
+#include <fs.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <sort.h>
+
+#include <crypto/pkcs7.h>
+#include <crypto/pkcs7_parser.h>
+#include <linux/err.h>
+
+const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
+static const efi_guid_t efi_guid_firmware_management_capsule_id =
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
+const efi_guid_t efi_guid_firmware_management_protocol =
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID;
+
+#ifdef CONFIG_EFI_CAPSULE_ON_DISK
+/* for file system access */
+static struct efi_file_handle *bootdev_root;
+#endif
+
+/**
+ * get_last_capsule - get the last capsule index
+ *
+ * Retrieve the index of the capsule invoked last time from "CapsuleLast"
+ * variable.
+ *
+ * Return:
+ * * > 0 - the last capsule index invoked
+ * * 0xffff - on error, or no capsule invoked yet
+ */
+static __maybe_unused unsigned int get_last_capsule(void)
+{
+ u16 value16[11]; /* "CapsuleXXXX": non-null-terminated */
+ char value[11], *p;
+ efi_uintn_t size;
+ unsigned long index = 0xffff;
+ efi_status_t ret;
+
+ size = sizeof(value16);
+ ret = efi_get_variable_int(L"CapsuleLast", &efi_guid_capsule_report,
+ NULL, &size, value16, NULL);
+ if (ret != EFI_SUCCESS || u16_strncmp(value16, L"Capsule", 7))
+ goto err;
+
+ p = value;
+ utf16_utf8_strcpy(&p, value16);
+ strict_strtoul(&value[7], 16, &index);
+err:
+ return index;
+}
+
+/**
+ * set_capsule_result - set a result variable
+ * @capsule: Capsule
+ * @return_status: Return status
+ *
+ * Create and set a result variable, "CapsuleXXXX", for the capsule,
+ * @capsule.
+ */
+static __maybe_unused
+void set_capsule_result(int index, struct efi_capsule_header *capsule,
+ efi_status_t return_status)
+{
+ u16 variable_name16[12];
+ struct efi_capsule_result_variable_header result;
+ struct efi_time time;
+ efi_status_t ret;
+
+ efi_create_indexed_name(variable_name16, sizeof(variable_name16),
+ "Capsule", index);
+ result.variable_total_size = sizeof(result);
+ result.capsule_guid = capsule->capsule_guid;
+ ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL));
+ if (ret == EFI_SUCCESS)
+ memcpy(&result.capsule_processed, &time, sizeof(time));
+ else
+ memset(&result.capsule_processed, 0, sizeof(time));
+ result.capsule_status = return_status;
+ ret = efi_set_variable(variable_name16, &efi_guid_capsule_report,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(result), &result);
+ if (ret)
+ log_err("EFI: creating %ls failed\n", variable_name16);
+}
+
+#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT
+/**
+ * efi_fmp_find - search for Firmware Management Protocol drivers
+ * @image_type: Image type guid
+ * @instance: Instance number
+ * @handles: Handles of FMP drivers
+ * @no_handles: Number of handles
+ *
+ * Search for Firmware Management Protocol drivers, matching the image
+ * type, @image_type and the machine instance, @instance, from the list,
+ * @handles.
+ *
+ * Return:
+ * * Protocol instance - on success
+ * * NULL - on failure
+ */
+static struct efi_firmware_management_protocol *
+efi_fmp_find(efi_guid_t *image_type, u64 instance, efi_handle_t *handles,
+ efi_uintn_t no_handles)
+{
+ efi_handle_t *handle;
+ struct efi_firmware_management_protocol *fmp;
+ struct efi_firmware_image_descriptor *image_info, *desc;
+ efi_uintn_t info_size, descriptor_size;
+ u32 descriptor_version;
+ u8 descriptor_count;
+ u32 package_version;
+ u16 *package_version_name;
+ bool found = false;
+ int i, j;
+ efi_status_t ret;
+
+ for (i = 0, handle = handles; i < no_handles; i++, handle++) {
+ ret = EFI_CALL(efi_handle_protocol(
+ *handle,
+ &efi_guid_firmware_management_protocol,
+ (void **)&fmp));
+ if (ret != EFI_SUCCESS)
+ continue;
+
+ /* get device's image info */
+ info_size = 0;
+ image_info = NULL;
+ descriptor_version = 0;
+ descriptor_count = 0;
+ descriptor_size = 0;
+ package_version = 0;
+ package_version_name = NULL;
+ ret = EFI_CALL(fmp->get_image_info(fmp, &info_size,
+ image_info,
+ &descriptor_version,
+ &descriptor_count,
+ &descriptor_size,
+ &package_version,
+ &package_version_name));
+ if (ret != EFI_BUFFER_TOO_SMALL)
+ goto skip;
+
+ image_info = malloc(info_size);
+ if (!image_info)
+ goto skip;
+
+ ret = EFI_CALL(fmp->get_image_info(fmp, &info_size,
+ image_info,
+ &descriptor_version,
+ &descriptor_count,
+ &descriptor_size,
+ &package_version,
+ &package_version_name));
+ if (ret != EFI_SUCCESS ||
+ descriptor_version != EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION)
+ goto skip;
+
+ /* matching */
+ for (j = 0, desc = image_info; j < descriptor_count;
+ j++, desc = (void *)desc + descriptor_size) {
+ log_debug("+++ desc[%d] index: %d, name: %ls\n",
+ j, desc->image_index, desc->image_id_name);
+ if (!guidcmp(&desc->image_type_id, image_type) &&
+ (!instance ||
+ !desc->hardware_instance ||
+ desc->hardware_instance == instance))
+ found = true;
+ }
+
+skip:
+ efi_free_pool(package_version_name);
+ free(image_info);
+ EFI_CALL(efi_close_protocol(
+ (efi_handle_t)fmp,
+ &efi_guid_firmware_management_protocol,
+ NULL, NULL));
+ if (found)
+ return fmp;
+ }
+
+ return NULL;
+}
+
+#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
+
+const efi_guid_t efi_guid_capsule_root_cert_guid =
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
+
+__weak int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
+{
+ /* The platform is supposed to provide
+ * a method for getting the public key
+ * stored in the form of efi signature
+ * list
+ */
+ return 0;
+}
+
+efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
+ void **image, efi_uintn_t *image_size)
+{
+ u8 *buf;
+ int ret;
+ void *fdt_pkey, *pkey;
+ efi_uintn_t pkey_len;
+ uint64_t monotonic_count;
+ struct efi_signature_store *truststore;
+ struct pkcs7_message *capsule_sig;
+ struct efi_image_regions *regs;
+ struct efi_firmware_image_authentication *auth_hdr;
+ efi_status_t status;
+
+ status = EFI_SECURITY_VIOLATION;
+ capsule_sig = NULL;
+ truststore = NULL;
+ regs = NULL;
+
+ /* Sanity checks */
+ if (capsule == NULL || capsule_size == 0)
+ goto out;
+
+ auth_hdr = (struct efi_firmware_image_authentication *)capsule;
+ if (capsule_size < sizeof(*auth_hdr))
+ goto out;
+
+ if (auth_hdr->auth_info.hdr.dwLength <=
+ offsetof(struct win_certificate_uefi_guid, cert_data))
+ goto out;
+
+ if (guidcmp(&auth_hdr->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
+ goto out;
+
+ *image = (uint8_t *)capsule + sizeof(auth_hdr->monotonic_count) +
+ auth_hdr->auth_info.hdr.dwLength;
+ *image_size = capsule_size - auth_hdr->auth_info.hdr.dwLength -
+ sizeof(auth_hdr->monotonic_count);
+ memcpy(&monotonic_count, &auth_hdr->monotonic_count,
+ sizeof(monotonic_count));
+
+ /* data to be digested */
+ regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 2, 1);
+ if (!regs)
+ goto out;
+
+ regs->max = 2;
+ efi_image_region_add(regs, (uint8_t *)*image,
+ (uint8_t *)*image + *image_size, 1);
+
+ efi_image_region_add(regs, (uint8_t *)&monotonic_count,
+ (uint8_t *)&monotonic_count + sizeof(monotonic_count),
+ 1);
+
+ capsule_sig = efi_parse_pkcs7_header(auth_hdr->auth_info.cert_data,
+ auth_hdr->auth_info.hdr.dwLength
+ - sizeof(auth_hdr->auth_info),
+ &buf);
+ if (IS_ERR(capsule_sig)) {
+ debug("Parsing variable's pkcs7 header failed\n");
+ capsule_sig = NULL;
+ goto out;
+ }
+
+ ret = efi_get_public_key_data(&fdt_pkey, &pkey_len);
+ if (ret < 0)
+ goto out;
+
+ pkey = malloc(pkey_len);
+ if (!pkey)
+ goto out;
+
+ memcpy(pkey, fdt_pkey, pkey_len);
+ truststore = efi_build_signature_store(pkey, pkey_len);
+ if (!truststore)
+ goto out;
+
+ /* verify signature */
+ if (efi_signature_verify(regs, capsule_sig, truststore, NULL)) {
+ debug("Verified\n");
+ } else {
+ debug("Verifying variable's signature failed\n");
+ goto out;
+ }
+
+ status = EFI_SUCCESS;
+
+out:
+ efi_sigstore_free(truststore);
+ pkcs7_free_message(capsule_sig);
+ free(regs);
+
+ return status;
+}
+#else
+efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
+ void **image, efi_uintn_t *image_size)
+{
+ return EFI_UNSUPPORTED;
+}
+#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */
+
+
+/**
+ * efi_capsule_update_firmware - update firmware from capsule
+ * @capsule_data: Capsule
+ *
+ * Update firmware, using a capsule, @capsule_data. Loading any FMP
+ * drivers embedded in a capsule is not supported.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_capsule_update_firmware(
+ struct efi_capsule_header *capsule_data)
+{
+ struct efi_firmware_management_capsule_header *capsule;
+ struct efi_firmware_management_capsule_image_header *image;
+ size_t capsule_size;
+ void *image_binary, *vendor_code;
+ efi_handle_t *handles;
+ efi_uintn_t no_handles;
+ int item;
+ struct efi_firmware_management_protocol *fmp;
+ u16 *abort_reason;
+ efi_status_t ret = EFI_SUCCESS;
+
+ /* sanity check */
+ if (capsule_data->header_size < sizeof(*capsule) ||
+ capsule_data->header_size >= capsule_data->capsule_image_size)
+ return EFI_INVALID_PARAMETER;
+
+ capsule = (void *)capsule_data + capsule_data->header_size;
+ capsule_size = capsule_data->capsule_image_size
+ - capsule_data->header_size;
+
+ if (capsule->version != 0x00000001)
+ return EFI_UNSUPPORTED;
+
+ handles = NULL;
+ ret = EFI_CALL(efi_locate_handle_buffer(
+ BY_PROTOCOL,
+ &efi_guid_firmware_management_protocol,
+ NULL, &no_handles, (efi_handle_t **)&handles));
+ if (ret != EFI_SUCCESS)
+ return EFI_UNSUPPORTED;
+
+ /* Payload */
+ for (item = capsule->embedded_driver_count;
+ item < capsule->embedded_driver_count
+ + capsule->payload_item_count; item++) {
+ /* sanity check */
+ if ((capsule->item_offset_list[item] + sizeof(*image)
+ >= capsule_size)) {
+ log_err("EFI: A capsule has not enough data\n");
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ image = (void *)capsule + capsule->item_offset_list[item];
+
+ if (image->version != 0x00000003) {
+ ret = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ /* find a device for update firmware */
+ /* TODO: should we pass index as well, or nothing but type? */
+ fmp = efi_fmp_find(&image->update_image_type_id,
+ image->update_hardware_instance,
+ handles, no_handles);
+ if (!fmp) {
+ log_err("EFI Capsule: driver not found for firmware type: %pUl, hardware instance: %lld\n",
+ &image->update_image_type_id,
+ image->update_hardware_instance);
+ ret = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ /* do update */
+ image_binary = (void *)image + sizeof(*image);
+ vendor_code = image_binary + image->update_image_size;
+
+ abort_reason = NULL;
+ ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index,
+ image_binary,
+ image->update_image_size,
+ vendor_code, NULL,
+ &abort_reason));
+ if (ret != EFI_SUCCESS) {
+ log_err("EFI Capsule: firmware update failed: %ls\n",
+ abort_reason);
+ efi_free_pool(abort_reason);
+ goto out;
+ }
+ }
+
+out:
+ efi_free_pool(handles);
+
+ return ret;
+}
+#else
+static efi_status_t efi_capsule_update_firmware(
+ struct efi_capsule_header *capsule_data)
+{
+ return EFI_UNSUPPORTED;
+}
+#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT */
+
+/**
+ * efi_update_capsule() - process information from operating system
+ * @capsule_header_array: Array of virtual address pointers
+ * @capsule_count: Number of pointers in capsule_header_array
+ * @scatter_gather_list: Array of physical address pointers
+ *
+ * This function implements the UpdateCapsule() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_update_capsule(
+ struct efi_capsule_header **capsule_header_array,
+ efi_uintn_t capsule_count,
+ u64 scatter_gather_list)
+{
+ struct efi_capsule_header *capsule;
+ unsigned int i;
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %lu, %llu\n", capsule_header_array, capsule_count,
+ scatter_gather_list);
+
+ if (!capsule_count) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = EFI_SUCCESS;
+ for (i = 0, capsule = *capsule_header_array; i < capsule_count;
+ i++, capsule = *(++capsule_header_array)) {
+ /* sanity check */
+ if (capsule->header_size < sizeof(*capsule) ||
+ capsule->capsule_image_size < sizeof(*capsule)) {
+ log_err("EFI: A capsule has not enough data\n");
+ continue;
+ }
+
+ log_debug("Capsule[%d] (guid:%pUl)\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("EFI: not support capsule type: %pUl\n",
+ &capsule->capsule_guid);
+ ret = EFI_UNSUPPORTED;
+ }
+
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+out:
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_query_capsule_caps() - check if capsule is supported
+ * @capsule_header_array: Array of virtual pointers
+ * @capsule_count: Number of pointers in capsule_header_array
+ * @maximum_capsule_size: Maximum capsule size
+ * @reset_type: Type of reset needed for capsule update
+ *
+ * This function implements the QueryCapsuleCapabilities() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: status code
+ */
+efi_status_t EFIAPI efi_query_capsule_caps(
+ struct efi_capsule_header **capsule_header_array,
+ efi_uintn_t capsule_count,
+ u64 *maximum_capsule_size,
+ u32 *reset_type)
+{
+ struct efi_capsule_header *capsule __attribute__((unused));
+ unsigned int i;
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %lu, %p, %p\n", capsule_header_array, capsule_count,
+ maximum_capsule_size, reset_type);
+
+ if (!maximum_capsule_size) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ *maximum_capsule_size = U64_MAX;
+ *reset_type = EFI_RESET_COLD;
+
+ ret = EFI_SUCCESS;
+ for (i = 0, capsule = *capsule_header_array; i < capsule_count;
+ i++, capsule = *(++capsule_header_array)) {
+ /* TODO */
+ }
+out:
+ return EFI_EXIT(ret);
+}
+
+#ifdef CONFIG_EFI_CAPSULE_ON_DISK
+/**
+ * get_dp_device - retrieve a device path from boot variable
+ * @boot_var: Boot variable name
+ * @device_dp Device path
+ *
+ * Retrieve a device patch from boot variable, @boot_var.
+ *
+ * Return: status code
+ */
+static efi_status_t get_dp_device(u16 *boot_var,
+ struct efi_device_path **device_dp)
+{
+ void *buf = NULL;
+ efi_uintn_t size;
+ struct efi_load_option lo;
+ struct efi_device_path *file_dp;
+ efi_status_t ret;
+
+ size = 0;
+ ret = efi_get_variable_int(boot_var, &efi_global_variable_guid,
+ NULL, &size, NULL, NULL);
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ buf = malloc(size);
+ if (!buf)
+ return EFI_OUT_OF_RESOURCES;
+ ret = efi_get_variable_int(boot_var, &efi_global_variable_guid,
+ NULL, &size, buf, NULL);
+ }
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ efi_deserialize_load_option(&lo, buf, &size);
+
+ if (lo.attributes & LOAD_OPTION_ACTIVE) {
+ efi_dp_split_file_path(lo.file_path, device_dp, &file_dp);
+ efi_free_pool(file_dp);
+
+ ret = EFI_SUCCESS;
+ } else {
+ ret = EFI_NOT_FOUND;
+ }
+
+ free(buf);
+
+ return ret;
+}
+
+/**
+ * device_is_present_and_system_part - check if a device exists
+ * @dp Device path
+ *
+ * Check if a device pointed to by the device path, @dp, exists and is
+ * located in UEFI system partition.
+ *
+ * Return: true - yes, false - no
+ */
+static bool device_is_present_and_system_part(struct efi_device_path *dp)
+{
+ efi_handle_t handle;
+
+ handle = efi_dp_find_obj(dp, NULL);
+ if (!handle)
+ return false;
+
+ return efi_disk_is_system_part(handle);
+}
+
+/**
+ * find_boot_device - identify the boot device
+ *
+ * Identify the boot device from boot-related variables as UEFI
+ * specification describes and put its handle into bootdev_root.
+ *
+ * Return: status code
+ */
+static efi_status_t find_boot_device(void)
+{
+ char boot_var[9];
+ u16 boot_var16[9], *p, bootnext, *boot_order = NULL;
+ efi_uintn_t size;
+ int i, num;
+ struct efi_simple_file_system_protocol *volume;
+ struct efi_device_path *boot_dev = NULL;
+ efi_status_t ret;
+
+ /* find active boot device in BootNext */
+ bootnext = 0;
+ size = sizeof(bootnext);
+ ret = efi_get_variable_int(L"BootNext",
+ (efi_guid_t *)&efi_global_variable_guid,
+ NULL, &size, &bootnext, NULL);
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+ /* BootNext does exist here */
+ if (ret == EFI_BUFFER_TOO_SMALL || size != sizeof(u16)) {
+ log_err("BootNext must be 16-bit integer\n");
+ goto skip;
+ }
+ sprintf((char *)boot_var, "Boot%04X", bootnext);
+ p = boot_var16;
+ utf8_utf16_strcpy(&p, boot_var);
+
+ ret = get_dp_device(boot_var16, &boot_dev);
+ if (ret == EFI_SUCCESS) {
+ if (device_is_present_and_system_part(boot_dev)) {
+ goto out;
+ } else {
+ efi_free_pool(boot_dev);
+ boot_dev = NULL;
+ }
+ }
+ }
+
+skip:
+ /* find active boot device in BootOrder */
+ size = 0;
+ ret = efi_get_variable_int(L"BootOrder", &efi_global_variable_guid,
+ NULL, &size, NULL, NULL);
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ boot_order = malloc(size);
+ if (!boot_order) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
+ ret = efi_get_variable_int(L"BootOrder",
+ &efi_global_variable_guid,
+ NULL, &size, boot_order, NULL);
+ }
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /* check in higher order */
+ num = size / sizeof(u16);
+ for (i = 0; i < num; i++) {
+ sprintf((char *)boot_var, "Boot%04X", boot_order[i]);
+ p = boot_var16;
+ utf8_utf16_strcpy(&p, boot_var);
+ ret = get_dp_device(boot_var16, &boot_dev);
+ if (ret != EFI_SUCCESS)
+ continue;
+
+ if (device_is_present_and_system_part(boot_dev))
+ break;
+
+ efi_free_pool(boot_dev);
+ boot_dev = NULL;
+ }
+out:
+ if (boot_dev) {
+ u16 *path_str;
+
+ path_str = efi_dp_str(boot_dev);
+ log_debug("EFI Capsule: bootdev is %ls\n", path_str);
+ efi_free_pool(path_str);
+
+ volume = efi_fs_from_path(boot_dev);
+ if (!volume)
+ ret = EFI_DEVICE_ERROR;
+ else
+ ret = EFI_CALL(volume->open_volume(volume,
+ &bootdev_root));
+ efi_free_pool(boot_dev);
+ } else {
+ ret = EFI_NOT_FOUND;
+ }
+ free(boot_order);
+
+ return ret;
+}
+
+/**
+ * efi_capsule_scan_dir - traverse a capsule directory in boot device
+ * @files: Array of file names
+ * @num: Number of elements in @files
+ *
+ * Traverse a capsule directory in boot device.
+ * Called by initialization code, and returns an array of capsule file
+ * names in @files.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_capsule_scan_dir(u16 ***files, unsigned int *num)
+{
+ struct efi_file_handle *dirh;
+ struct efi_file_info *dirent;
+ efi_uintn_t dirent_size, tmp_size;
+ unsigned int count;
+ u16 **tmp_files;
+ efi_status_t ret;
+
+ ret = find_boot_device();
+ if (ret == EFI_NOT_FOUND) {
+ log_debug("EFI Capsule: bootdev is not set\n");
+ *num = 0;
+ return EFI_SUCCESS;
+ } else if (ret != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ /* count capsule files */
+ ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
+ EFI_CAPSULE_DIR,
+ EFI_FILE_MODE_READ, 0));
+ if (ret != EFI_SUCCESS) {
+ *num = 0;
+ return EFI_SUCCESS;
+ }
+
+ dirent_size = 256;
+ dirent = malloc(dirent_size);
+ if (!dirent)
+ return EFI_OUT_OF_RESOURCES;
+
+ count = 0;
+ while (1) {
+ tmp_size = dirent_size;
+ ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ dirent = realloc(dirent, tmp_size);
+ if (!dirent) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+ dirent_size = tmp_size;
+ ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
+ }
+ if (ret != EFI_SUCCESS)
+ goto err;
+ if (!tmp_size)
+ break;
+
+ if (!(dirent->attribute & EFI_FILE_DIRECTORY) &&
+ u16_strcmp(dirent->file_name, L".") &&
+ u16_strcmp(dirent->file_name, L".."))
+ count++;
+ }
+
+ ret = EFI_CALL((*dirh->setpos)(dirh, 0));
+ if (ret != EFI_SUCCESS)
+ goto err;
+
+ /* make a list */
+ tmp_files = malloc(count * sizeof(*files));
+ if (!tmp_files) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ count = 0;
+ while (1) {
+ tmp_size = dirent_size;
+ ret = EFI_CALL((*dirh->read)(dirh, &tmp_size, dirent));
+ if (ret != EFI_SUCCESS)
+ goto err;
+ if (!tmp_size)
+ break;
+
+ if (!(dirent->attribute & EFI_FILE_DIRECTORY) &&
+ u16_strcmp(dirent->file_name, L".") &&
+ u16_strcmp(dirent->file_name, L".."))
+ tmp_files[count++] = u16_strdup(dirent->file_name);
+ }
+ /* ignore an error */
+ EFI_CALL((*dirh->close)(dirh));
+
+ /* in ascii order */
+ /* FIXME: u16 version of strcasecmp */
+ qsort(tmp_files, count, sizeof(*tmp_files),
+ (int (*)(const void *, const void *))strcasecmp);
+ *files = tmp_files;
+ *num = count;
+ ret = EFI_SUCCESS;
+err:
+ free(dirent);
+
+ return ret;
+}
+
+/**
+ * efi_capsule_read_file - read in a capsule file
+ * @filename: File name
+ * @capsule: Pointer to buffer for capsule
+ *
+ * Read a capsule file and put its content in @capsule.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_capsule_read_file(const u16 *filename,
+ struct efi_capsule_header **capsule)
+{
+ struct efi_file_handle *dirh, *fh;
+ struct efi_file_info *file_info = NULL;
+ struct efi_capsule_header *buf = NULL;
+ efi_uintn_t size;
+ efi_status_t ret;
+
+ ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
+ EFI_CAPSULE_DIR,
+ EFI_FILE_MODE_READ, 0));
+ if (ret != EFI_SUCCESS)
+ return ret;
+ ret = EFI_CALL((*dirh->open)(dirh, &fh, (u16 *)filename,
+ EFI_FILE_MODE_READ, 0));
+ /* ignore an error */
+ EFI_CALL((*dirh->close)(dirh));
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ /* file size */
+ size = 0;
+ ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid,
+ &size, file_info));
+ if (ret == EFI_BUFFER_TOO_SMALL) {
+ file_info = malloc(size);
+ if (!file_info) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+ ret = EFI_CALL((*fh->getinfo)(fh, &efi_file_info_guid,
+ &size, file_info));
+ }
+ if (ret != EFI_SUCCESS)
+ goto err;
+ size = file_info->file_size;
+ free(file_info);
+ buf = malloc(size);
+ if (!buf) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto err;
+ }
+
+ /* fetch data */
+ ret = EFI_CALL((*fh->read)(fh, &size, buf));
+ if (ret == EFI_SUCCESS) {
+ if (size >= buf->capsule_image_size) {
+ *capsule = buf;
+ } else {
+ free(buf);
+ ret = EFI_INVALID_PARAMETER;
+ }
+ } else {
+ free(buf);
+ }
+err:
+ EFI_CALL((*fh->close)(fh));
+
+ return ret;
+}
+
+/**
+ * efi_capsule_delete_file - delete a capsule file
+ * @filename: File name
+ *
+ * Delete a capsule file from capsule directory.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_capsule_delete_file(const u16 *filename)
+{
+ struct efi_file_handle *dirh, *fh;
+ efi_status_t ret;
+
+ ret = EFI_CALL((*bootdev_root->open)(bootdev_root, &dirh,
+ EFI_CAPSULE_DIR,
+ EFI_FILE_MODE_READ, 0));
+ if (ret != EFI_SUCCESS)
+ return ret;
+ ret = EFI_CALL((*dirh->open)(dirh, &fh, (u16 *)filename,
+ EFI_FILE_MODE_READ, 0));
+ /* ignore an error */
+ EFI_CALL((*dirh->close)(dirh));
+
+ ret = EFI_CALL((*fh->delete)(fh));
+
+ return ret;
+}
+
+/**
+ * efi_capsule_scan_done - reset a scan help function
+ *
+ * Reset a scan help function
+ */
+static void efi_capsule_scan_done(void)
+{
+ EFI_CALL((*bootdev_root->close)(bootdev_root));
+ bootdev_root = NULL;
+}
+
+/**
+ * arch_efi_load_capsule_drivers - initialize capsule drivers
+ *
+ * Architecture or board specific initialization routine
+ *
+ * Return: status code
+ */
+efi_status_t __weak arch_efi_load_capsule_drivers(void)
+{
+ __maybe_unused efi_handle_t handle;
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_FIT)) {
+ handle = NULL;
+ ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
+ &handle, &efi_guid_firmware_management_protocol,
+ &efi_fmp_fit, NULL));
+ }
+
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_RAW)) {
+ handle = NULL;
+ ret = EFI_CALL(efi_install_multiple_protocol_interfaces(
+ &efi_root,
+ &efi_guid_firmware_management_protocol,
+ &efi_fmp_raw, NULL));
+ }
+
+ return ret;
+}
+
+/**
+ * efi_launch_capsule - launch capsules
+ *
+ * Launch all the capsules in system at boot time.
+ * Called by efi init code
+ *
+ * Return: status codde
+ */
+efi_status_t efi_launch_capsules(void)
+{
+ u64 os_indications;
+ efi_uintn_t size;
+ struct efi_capsule_header *capsule = NULL;
+ u16 **files;
+ unsigned int nfiles, index, i;
+ u16 variable_name16[12];
+ efi_status_t ret;
+
+ size = sizeof(os_indications);
+ ret = efi_get_variable_int(L"OsIndications", &efi_global_variable_guid,
+ NULL, &size, &os_indications, NULL);
+ if (ret != EFI_SUCCESS ||
+ !(os_indications
+ & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED))
+ return EFI_SUCCESS;
+
+ index = get_last_capsule();
+
+ /* Load capsule drivers */
+ ret = arch_efi_load_capsule_drivers();
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ /*
+ * Find capsules on disk.
+ * All the capsules are collected at the beginning because
+ * capsule files will be removed instantly.
+ */
+ nfiles = 0;
+ files = NULL;
+ ret = efi_capsule_scan_dir(&files, &nfiles);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ if (!nfiles)
+ return EFI_SUCCESS;
+
+ /* Launch capsules */
+ for (i = 0, ++index; i < nfiles; i++, index++) {
+ log_debug("capsule from %ls ...\n", files[i]);
+ if (index > 0xffff)
+ index = 0;
+ ret = efi_capsule_read_file(files[i], &capsule);
+ if (ret == EFI_SUCCESS) {
+ ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0));
+ if (ret != EFI_SUCCESS)
+ log_err("EFI Capsule update failed at %ls\n",
+ files[i]);
+
+ free(capsule);
+ } else {
+ log_err("EFI: reading capsule failed: %ls\n", files[i]);
+ }
+ /* create CapsuleXXXX */
+ set_capsule_result(index, capsule, ret);
+
+ /* delete a capsule either in case of success or failure */
+ ret = efi_capsule_delete_file(files[i]);
+ if (ret != EFI_SUCCESS)
+ log_err("EFI: deleting a capsule file failed: %ls\n",
+ files[i]);
+ }
+ efi_capsule_scan_done();
+
+ for (i = 0; i < nfiles; i++)
+ free(files[i]);
+ free(files);
+
+ /* CapsuleLast */
+ efi_create_indexed_name(variable_name16, sizeof(variable_name16),
+ "Capsule", index - 1);
+ efi_set_variable_int(L"CapsuleLast", &efi_guid_capsule_report,
+ EFI_VARIABLE_READ_ONLY |
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 22, variable_name16, false);
+
+ return ret;
+}
+#endif /* CONFIG_EFI_CAPSULE_ON_DISK */
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 8a5c13c..c9315dd 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -531,7 +531,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_ETH: {
struct efi_device_path_mac_addr *dp =
dp_fill(buf, dev->parent);
- struct eth_pdata *pdata = dev->platdata;
+ struct eth_pdata *pdata = dev_get_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
@@ -551,7 +551,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_ROOT: {
/* stop traversing parents at this point: */
struct efi_device_path_vendor *dp;
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
dp_fill(buf, dev->parent);
dp = buf;
@@ -568,7 +568,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
#ifdef CONFIG_VIRTIO_BLK
case UCLASS_VIRTIO: {
struct efi_device_path_vendor *dp;
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
dp_fill(buf, dev->parent);
dp = buf;
@@ -586,7 +586,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_IDE: {
struct efi_device_path_atapi *dp =
dp_fill(buf, dev->parent);
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
@@ -603,7 +603,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_SCSI: {
struct efi_device_path_scsi *dp =
dp_fill(buf, dev->parent);
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
@@ -617,14 +617,14 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_MMC: {
struct efi_device_path_sd_mmc_path *sddp =
dp_fill(buf, dev->parent);
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
sddp->dp.sub_type = is_sd(desc) ?
DEVICE_PATH_SUB_TYPE_MSG_SD :
DEVICE_PATH_SUB_TYPE_MSG_MMC;
sddp->dp.length = sizeof(*sddp);
- sddp->slot_number = dev->seq;
+ sddp->slot_number = dev_seq(dev);
return &sddp[1];
}
#endif
@@ -632,7 +632,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
case UCLASS_AHCI: {
struct efi_device_path_sata *dp =
dp_fill(buf, dev->parent);
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SATA;
@@ -677,7 +677,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
DEVICE_PATH_SUB_TYPE_MSG_SD :
DEVICE_PATH_SUB_TYPE_MSG_MMC;
sddp->dp.length = sizeof(*sddp);
- sddp->slot_number = dev->seq;
+ sddp->slot_number = dev_seq(dev);
return &sddp[1];
}
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 7bd1cce..26b9534 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -376,6 +376,23 @@ static efi_status_t efi_disk_add_dev(
/* Fill in object data */
if (part) {
struct efi_device_path *node = efi_dp_part_node(desc, part);
+ struct efi_handler *handler;
+ void *protocol_interface;
+
+ /* Parent must expose EFI_BLOCK_IO_PROTOCOL */
+ ret = efi_search_protocol(parent, &efi_block_io_guid, &handler);
+ if (ret != EFI_SUCCESS)
+ goto error;
+
+ /*
+ * Link the partition (child controller) to the block device
+ * (controller).
+ */
+ ret = efi_protocol_open(handler, &protocol_interface, NULL,
+ &diskobj->header,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
+ if (ret != EFI_SUCCESS)
+ goto error;
diskobj->dp = efi_dp_append_node(dp_parent, node);
efi_free_pool(node);
@@ -453,6 +470,9 @@ static efi_status_t efi_disk_add_dev(
}
}
return EFI_SUCCESS;
+error:
+ efi_delete_handle(&diskobj->header);
+ return ret;
}
/**
@@ -527,7 +547,7 @@ efi_status_t efi_disk_register(void)
for (uclass_first_device_check(UCLASS_BLK, &dev); dev;
uclass_next_device_check(&dev)) {
- struct blk_desc *desc = dev_get_uclass_platdata(dev);
+ struct blk_desc *desc = dev_get_uclass_plat(dev);
const char *if_typename = blk_get_if_type_name(desc->if_type);
/* Add block device for the full device */
diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
new file mode 100644
index 0000000..5e401bb
--- /dev/null
+++ b/lib/efi_loader/efi_firmware.c
@@ -0,0 +1,478 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI Firmware management protocol
+ *
+ * Copyright (c) 2020 Linaro Limited
+ * Author: AKASHI Takahiro
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <dfu.h>
+#include <efi_loader.h>
+#include <image.h>
+#include <signatures.h>
+
+#include <linux/list.h>
+
+#define FMP_PAYLOAD_HDR_SIGNATURE SIGNATURE_32('M', 'S', 'S', '1')
+
+/**
+ * struct fmp_payload_header - EDK2 header for the FMP payload
+ *
+ * This structure describes the header which is preprended to the
+ * FMP payload by the edk2 capsule generation scripts.
+ *
+ * @signature: Header signature used to identify the header
+ * @header_size: Size of the structure
+ * @fw_version: Firmware versions used
+ * @lowest_supported_version: Lowest supported version
+ */
+struct fmp_payload_header {
+ u32 signature;
+ u32 header_size;
+ u32 fw_version;
+ u32 lowest_supported_version;
+};
+
+/* Place holder; not supported */
+static
+efi_status_t EFIAPI efi_firmware_get_image_unsupported(
+ struct efi_firmware_management_protocol *this,
+ u8 image_index,
+ void *image,
+ efi_uintn_t *image_size)
+{
+ EFI_ENTRY("%p %d %p %p\n", this, image_index, image, image_size);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/* Place holder; not supported */
+static
+efi_status_t EFIAPI efi_firmware_check_image_unsupported(
+ struct efi_firmware_management_protocol *this,
+ u8 image_index,
+ const void *image,
+ efi_uintn_t *image_size,
+ u32 *image_updatable)
+{
+ EFI_ENTRY("%p %d %p %p %p\n", this, image_index, image, image_size,
+ image_updatable);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/* Place holder; not supported */
+static
+efi_status_t EFIAPI efi_firmware_get_package_info_unsupported(
+ struct efi_firmware_management_protocol *this,
+ u32 *package_version,
+ u16 **package_version_name,
+ u32 *package_version_name_maxlen,
+ u64 *attributes_supported,
+ u64 *attributes_setting)
+{
+ EFI_ENTRY("%p %p %p %p %p %p\n", this, package_version,
+ package_version_name, package_version_name_maxlen,
+ attributes_supported, attributes_setting);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/* Place holder; not supported */
+static
+efi_status_t EFIAPI efi_firmware_set_package_info_unsupported(
+ struct efi_firmware_management_protocol *this,
+ const void *image,
+ efi_uintn_t *image_size,
+ const void *vendor_code,
+ u32 package_version,
+ const u16 *package_version_name)
+{
+ EFI_ENTRY("%p %p %p %p %x %p\n", this, image, image_size, vendor_code,
+ package_version, package_version_name);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/**
+ * efi_get_dfu_info - return information about the current firmware image
+ * @this: Protocol instance
+ * @image_info_size: Size of @image_info
+ * @image_info: Image information
+ * @descriptor_version: Pointer to version number
+ * @descriptor_count: Pointer to number of descriptors
+ * @descriptor_size: Pointer to descriptor size
+ * package_version: Package version
+ * package_version_name: Package version's name
+ * image_type: Image type GUID
+ *
+ * Return information bout the current firmware image in @image_info.
+ * @image_info will consist of a number of descriptors.
+ * Each descriptor will be created based on "dfu_alt_info" variable.
+ *
+ * Return status code
+ */
+static efi_status_t efi_get_dfu_info(
+ efi_uintn_t *image_info_size,
+ struct efi_firmware_image_descriptor *image_info,
+ u32 *descriptor_version,
+ u8 *descriptor_count,
+ efi_uintn_t *descriptor_size,
+ u32 *package_version,
+ u16 **package_version_name,
+ const efi_guid_t *image_type)
+{
+ struct dfu_entity *dfu;
+ size_t names_len, total_size;
+ int dfu_num, i;
+ u16 *name, *next;
+
+ dfu_init_env_entities(NULL, NULL);
+
+ names_len = 0;
+ dfu_num = 0;
+ list_for_each_entry(dfu, &dfu_list, list) {
+ names_len += (utf8_utf16_strlen(dfu->name) + 1) * 2;
+ dfu_num++;
+ }
+ if (!dfu_num) {
+ log_warning("Probably dfu_alt_info not defined\n");
+ *image_info_size = 0;
+ dfu_free_entities();
+
+ return EFI_SUCCESS;
+ }
+
+ total_size = sizeof(*image_info) * dfu_num + names_len;
+ /*
+ * we will assume that sizeof(*image_info) * dfu_name
+ * is, at least, a multiple of 2. So the start address for
+ * image_id_name would be aligned with 2 bytes.
+ */
+ if (*image_info_size < total_size) {
+ *image_info_size = total_size;
+ dfu_free_entities();
+
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *image_info_size = total_size;
+
+ *descriptor_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+ *descriptor_count = dfu_num;
+ *descriptor_size = sizeof(*image_info);
+ *package_version = 0xffffffff; /* not supported */
+ *package_version_name = NULL; /* not supported */
+
+ /* DFU alt number should correspond to image_index */
+ i = 0;
+ /* Name area starts just after descriptors */
+ name = (u16 *)((u8 *)image_info + sizeof(*image_info) * dfu_num);
+ next = name;
+ list_for_each_entry(dfu, &dfu_list, list) {
+ image_info[i].image_index = dfu->alt + 1;
+ image_info[i].image_type_id = *image_type;
+ image_info[i].image_id = dfu->alt;
+
+ /* copy the DFU entity name */
+ utf8_utf16_strcpy(&next, dfu->name);
+ image_info[i].image_id_name = name;
+ name = ++next;
+
+ image_info[i].version = 0; /* not supported */
+ image_info[i].version_name = NULL; /* not supported */
+ image_info[i].size = 0;
+ image_info[i].attributes_supported =
+ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
+ image_info[i].attributes_setting =
+ IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+
+ /* Check if the capsule authentication is enabled */
+ if (env_get("capsule_authentication_enabled"))
+ 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;
+
+ i++;
+ }
+
+ dfu_free_entities();
+
+ return EFI_SUCCESS;
+}
+
+#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
+/*
+ * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
+ * method with existing FIT image format, and handles
+ * - multiple regions of firmware via DFU
+ * but doesn't support
+ * - versioning of firmware image
+ * - package information
+ */
+const efi_guid_t efi_firmware_image_type_uboot_fit =
+ EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID;
+
+/**
+ * efi_firmware_fit_get_image_info - return information about the current
+ * firmware image
+ * @this: Protocol instance
+ * @image_info_size: Size of @image_info
+ * @image_info: Image information
+ * @descriptor_version: Pointer to version number
+ * @descriptor_count: Pointer to number of descriptors
+ * @descriptor_size: Pointer to descriptor size
+ * package_version: Package version
+ * package_version_name: Package version's name
+ *
+ * Return information bout the current firmware image in @image_info.
+ * @image_info will consist of a number of descriptors.
+ * Each descriptor will be created based on "dfu_alt_info" variable.
+ *
+ * Return status code
+ */
+static
+efi_status_t EFIAPI efi_firmware_fit_get_image_info(
+ struct efi_firmware_management_protocol *this,
+ efi_uintn_t *image_info_size,
+ struct efi_firmware_image_descriptor *image_info,
+ u32 *descriptor_version,
+ u8 *descriptor_count,
+ efi_uintn_t *descriptor_size,
+ u32 *package_version,
+ u16 **package_version_name)
+{
+ efi_status_t ret;
+
+ EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
+ image_info_size, image_info,
+ descriptor_version, descriptor_count, descriptor_size,
+ package_version, package_version_name);
+
+ if (!image_info_size)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ if (*image_info_size &&
+ (!image_info || !descriptor_version || !descriptor_count ||
+ !descriptor_size || !package_version || !package_version_name))
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ ret = efi_get_dfu_info(image_info_size, image_info,
+ descriptor_version, descriptor_count,
+ descriptor_size,
+ package_version, package_version_name,
+ &efi_firmware_image_type_uboot_fit);
+
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_firmware_fit_set_image - update the firmware image
+ * @this: Protocol instance
+ * @image_index: Image index number
+ * @image: New image
+ * @image_size: Size of new image
+ * @vendor_code: Vendor-specific update policy
+ * @progress: Function to report the progress of update
+ * @abort_reason: Pointer to string of abort reason
+ *
+ * Update the firmware to new image, using dfu. The new image should
+ * have FIT image format commonly used in U-Boot.
+ * @vendor_code, @progress and @abort_reason are not supported.
+ *
+ * Return: status code
+ */
+static
+efi_status_t EFIAPI efi_firmware_fit_set_image(
+ struct efi_firmware_management_protocol *this,
+ u8 image_index,
+ const void *image,
+ efi_uintn_t image_size,
+ const void *vendor_code,
+ efi_status_t (*progress)(efi_uintn_t completion),
+ u16 **abort_reason)
+{
+ EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
+ image_size, vendor_code, progress, abort_reason);
+
+ if (!image || image_index != 1)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ if (fit_update(image))
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_firmware_management_protocol efi_fmp_fit = {
+ .get_image_info = efi_firmware_fit_get_image_info,
+ .get_image = efi_firmware_get_image_unsupported,
+ .set_image = efi_firmware_fit_set_image,
+ .check_image = efi_firmware_check_image_unsupported,
+ .get_package_info = efi_firmware_get_package_info_unsupported,
+ .set_package_info = efi_firmware_set_package_info_unsupported,
+};
+#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_FIT */
+
+#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_RAW
+/*
+ * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
+ * method with raw data.
+ */
+const efi_guid_t efi_firmware_image_type_uboot_raw =
+ EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID;
+
+/**
+ * efi_firmware_raw_get_image_info - return information about the current
+ firmware image
+ * @this: Protocol instance
+ * @image_info_size: Size of @image_info
+ * @image_info: Image information
+ * @descriptor_version: Pointer to version number
+ * @descriptor_count: Pointer to number of descriptors
+ * @descriptor_size: Pointer to descriptor size
+ * package_version: Package version
+ * package_version_name: Package version's name
+ *
+ * Return information bout the current firmware image in @image_info.
+ * @image_info will consist of a number of descriptors.
+ * Each descriptor will be created based on "dfu_alt_info" variable.
+ *
+ * Return status code
+ */
+static
+efi_status_t EFIAPI efi_firmware_raw_get_image_info(
+ struct efi_firmware_management_protocol *this,
+ efi_uintn_t *image_info_size,
+ struct efi_firmware_image_descriptor *image_info,
+ u32 *descriptor_version,
+ u8 *descriptor_count,
+ efi_uintn_t *descriptor_size,
+ u32 *package_version,
+ u16 **package_version_name)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this,
+ image_info_size, image_info,
+ descriptor_version, descriptor_count, descriptor_size,
+ package_version, package_version_name);
+
+ if (!image_info_size)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ if (*image_info_size &&
+ (!image_info || !descriptor_version || !descriptor_count ||
+ !descriptor_size || !package_version || !package_version_name))
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ ret = efi_get_dfu_info(image_info_size, image_info,
+ descriptor_version, descriptor_count,
+ descriptor_size,
+ package_version, package_version_name,
+ &efi_firmware_image_type_uboot_raw);
+
+ return EFI_EXIT(ret);
+}
+
+/**
+ * efi_firmware_raw_set_image - update the firmware image
+ * @this: Protocol instance
+ * @image_index: Image index number
+ * @image: New image
+ * @image_size: Size of new image
+ * @vendor_code: Vendor-specific update policy
+ * @progress: Function to report the progress of update
+ * @abort_reason: Pointer to string of abort reason
+ *
+ * Update the firmware to new image, using dfu. The new image should
+ * be a single raw image.
+ * @vendor_code, @progress and @abort_reason are not supported.
+ *
+ * Return: status code
+ */
+static
+efi_status_t EFIAPI efi_firmware_raw_set_image(
+ struct efi_firmware_management_protocol *this,
+ u8 image_index,
+ const void *image,
+ efi_uintn_t image_size,
+ const void *vendor_code,
+ efi_status_t (*progress)(efi_uintn_t completion),
+ u16 **abort_reason)
+{
+ u32 fmp_hdr_signature;
+ struct fmp_payload_header *header;
+ void *capsule_payload;
+ efi_status_t status;
+ efi_uintn_t capsule_payload_size;
+
+ EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
+ image_size, vendor_code, progress, abort_reason);
+
+ if (!image)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ /* Authenticate the capsule if authentication enabled */
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE) &&
+ env_get("capsule_authentication_enabled")) {
+ capsule_payload = NULL;
+ capsule_payload_size = 0;
+ status = efi_capsule_authenticate(image, image_size,
+ &capsule_payload,
+ &capsule_payload_size);
+
+ if (status == EFI_SECURITY_VIOLATION) {
+ printf("Capsule authentication check failed. Aborting update\n");
+ return EFI_EXIT(status);
+ } else if (status != EFI_SUCCESS) {
+ return EFI_EXIT(status);
+ }
+
+ debug("Capsule authentication successfull\n");
+ image = capsule_payload;
+ image_size = capsule_payload_size;
+ } else {
+ debug("Capsule authentication disabled. ");
+ 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;
+
+ }
+
+ if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
+ NULL, NULL))
+ return EFI_EXIT(EFI_DEVICE_ERROR);
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+const struct efi_firmware_management_protocol efi_fmp_raw = {
+ .get_image_info = efi_firmware_raw_get_image_info,
+ .get_image = efi_firmware_get_image_unsupported,
+ .set_image = efi_firmware_raw_set_image,
+ .check_image = efi_firmware_check_image_unsupported,
+ .get_package_info = efi_firmware_get_package_info_unsupported,
+ .set_package_info = efi_firmware_set_package_info_unsupported,
+};
+#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_RAW */
diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c
index 26ea4b9..237e8ac 100644
--- a/lib/efi_loader/efi_hii_config.c
+++ b/lib/efi_loader/efi_hii_config.c
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * EFI Human Interface Infrastructure ... Configuration
+ * EFI Human Interface Infrastructure ... Configuration
*
- * Copyright (c) 2017 Leif Lindholm
- * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ * Copyright (c) 2017 Leif Lindholm
+ * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited
+ *
+ * As this is still a non-working stub and the protocol is neither required
+ * by the EFI shell nor by the UEFI SCT this module has been removed from
+ * the Makefile.
*/
#include <common.h>
diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c
index d517d68..b9ee883 100644
--- a/lib/efi_loader/efi_load_initrd.c
+++ b/lib/efi_loader/efi_load_initrd.c
@@ -4,16 +4,11 @@
*/
#include <common.h>
-#include <env.h>
-#include <malloc.h>
-#include <mapmem.h>
-#include <dm.h>
-#include <fs.h>
#include <efi_loader.h>
#include <efi_load_initrd.h>
-
-static const efi_guid_t efi_guid_load_file2_protocol =
- EFI_LOAD_FILE2_PROTOCOL_GUID;
+#include <fs.h>
+#include <malloc.h>
+#include <mapmem.h>
static efi_status_t EFIAPI
efi_load_file2_initrd(struct efi_load_file_protocol *this,
diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c
index f68b0fd..b17db31 100644
--- a/lib/efi_loader/efi_root_node.c
+++ b/lib/efi_loader/efi_root_node.c
@@ -77,9 +77,6 @@ efi_status_t efi_root_node_register(void)
/* HII database protocol */
&efi_guid_hii_database_protocol,
(void *)&efi_hii_database,
- /* HII configuration routing protocol */
- &efi_guid_hii_config_routing_protocol,
- (void *)&efi_hii_config_routing,
#endif
NULL));
efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE;
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 1fa1595..93c9478 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -449,6 +449,50 @@ efi_status_t __weak __efi_runtime EFIAPI efi_set_time(struct efi_time *time)
}
/**
+ * efi_update_capsule_unsupported() - process information from operating system
+ *
+ * This function implements the UpdateCapsule() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @capsule_header_array: pointer to array of virtual pointers
+ * @capsule_count: number of pointers in capsule_header_array
+ * @scatter_gather_list: pointer to array of physical pointers
+ * Returns: status code
+ */
+efi_status_t __efi_runtime EFIAPI efi_update_capsule_unsupported(
+ struct efi_capsule_header **capsule_header_array,
+ efi_uintn_t capsule_count,
+ u64 scatter_gather_list)
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * efi_query_capsule_caps_unsupported() - check if capsule is supported
+ *
+ * This function implements the QueryCapsuleCapabilities() runtime service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @capsule_header_array: pointer to array of virtual pointers
+ * @capsule_count: number of pointers in capsule_header_array
+ * @maximum_capsule_size: maximum capsule size
+ * @reset_type: type of reset needed for capsule update
+ * Returns: status code
+ */
+efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps_unsupported(
+ struct efi_capsule_header **capsule_header_array,
+ efi_uintn_t capsule_count,
+ u64 *maximum_capsule_size,
+ u32 *reset_type)
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
* efi_is_runtime_service_pointer() - check if pointer points to runtime table
*
* @p: pointer to check
@@ -471,6 +515,13 @@ void efi_runtime_detach(void)
efi_runtime_services.reset_system = efi_reset_system;
efi_runtime_services.get_time = efi_get_time;
efi_runtime_services.set_time = efi_set_time;
+ if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE)) {
+ /* won't support at runtime */
+ efi_runtime_services.update_capsule =
+ efi_update_capsule_unsupported;
+ efi_runtime_services.query_capsule_caps =
+ efi_query_capsule_caps_unsupported;
+ }
/* Update CRC32 */
efi_update_table_header_crc32(&efi_runtime_services.hdr);
@@ -879,50 +930,6 @@ static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void)
return EFI_UNSUPPORTED;
}
-/**
- * efi_update_capsule() - process information from operating system
- *
- * This function implements the UpdateCapsule() runtime service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * @capsule_header_array: pointer to array of virtual pointers
- * @capsule_count: number of pointers in capsule_header_array
- * @scatter_gather_list: pointer to arry of physical pointers
- * Returns: status code
- */
-efi_status_t __efi_runtime EFIAPI efi_update_capsule(
- struct efi_capsule_header **capsule_header_array,
- efi_uintn_t capsule_count,
- u64 scatter_gather_list)
-{
- return EFI_UNSUPPORTED;
-}
-
-/**
- * efi_query_capsule_caps() - check if capsule is supported
- *
- * This function implements the QueryCapsuleCapabilities() runtime service.
- *
- * See the Unified Extensible Firmware Interface (UEFI) specification for
- * details.
- *
- * @capsule_header_array: pointer to array of virtual pointers
- * @capsule_count: number of pointers in capsule_header_array
- * @maximum_capsule_size: maximum capsule size
- * @reset_type: type of reset needed for capsule update
- * Returns: status code
- */
-efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
- struct efi_capsule_header **capsule_header_array,
- efi_uintn_t capsule_count,
- u64 *maximum_capsule_size,
- u32 *reset_type)
-{
- return EFI_UNSUPPORTED;
-}
-
struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
.hdr = {
.signature = EFI_RUNTIME_SERVICES_SIGNATURE,
@@ -940,7 +947,12 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = {
.set_variable = efi_set_variable,
.get_next_high_mono_count = (void *)&efi_unimplemented,
.reset_system = &efi_reset_system_boottime,
+#ifdef CONFIG_EFI_RUNTIME_UPDATE_CAPSULE
.update_capsule = efi_update_capsule,
.query_capsule_caps = efi_query_capsule_caps,
+#else
+ .update_capsule = efi_update_capsule_unsupported,
+ .query_capsule_caps = efi_query_capsule_caps_unsupported,
+#endif
.query_variable_info = efi_query_variable_info,
};
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index e206b60..5800cbf 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -100,9 +100,9 @@ static efi_status_t efi_init_secure_boot(void)
ret = efi_set_variable_int(L"SignatureSupport",
&efi_global_variable_guid,
+ EFI_VARIABLE_READ_ONLY |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_READ_ONLY,
+ EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(signature_types),
&signature_types, false);
if (ret != EFI_SUCCESS)
@@ -118,13 +118,67 @@ static efi_status_t efi_init_secure_boot(void)
#endif /* CONFIG_EFI_SECURE_BOOT */
/**
+ * efi_init_capsule - initialize capsule update state
+ *
+ * Return: status code
+ */
+static efi_status_t efi_init_capsule(void)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_UPDATE)) {
+ ret = efi_set_variable_int(L"CapsuleMax",
+ &efi_guid_capsule_report,
+ EFI_VARIABLE_READ_ONLY |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 22, L"CapsuleFFFF", false);
+ if (ret != EFI_SUCCESS)
+ printf("EFI: cannot initialize CapsuleMax variable\n");
+ }
+
+ return ret;
+}
+
+/**
+ * efi_init_os_indications() - indicate supported features for OS requests
+ *
+ * Set the OsIndicationsSupported variable.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_init_os_indications(void)
+{
+ u64 os_indications_supported = 0;
+
+ if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT))
+ os_indications_supported |=
+ EFI_OS_INDICATIONS_CAPSULE_RESULT_VAR_SUPPORTED;
+
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK))
+ os_indications_supported |=
+ EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
+
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT))
+ os_indications_supported |=
+ EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED;
+
+ return efi_set_variable_int(L"OsIndicationsSupported",
+ &efi_global_variable_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_READ_ONLY,
+ sizeof(os_indications_supported),
+ &os_indications_supported, false);
+}
+
+/**
* efi_init_obj_list() - Initialize and populate EFI object list
*
* Return: status code
*/
efi_status_t efi_init_obj_list(void)
{
- u64 os_indications_supported = 0; /* None */
efi_status_t ret = EFI_SUCCESS;
/* Initialize once only */
@@ -157,12 +211,6 @@ efi_status_t efi_init_obj_list(void)
goto out;
}
- if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
- ret = efi_tcg2_register();
- if (ret != EFI_SUCCESS)
- goto out;
- }
-
/* Initialize variable services */
ret = efi_init_variables();
if (ret != EFI_SUCCESS)
@@ -174,13 +222,7 @@ efi_status_t efi_init_obj_list(void)
goto out;
/* Indicate supported features */
- ret = efi_set_variable_int(L"OsIndicationsSupported",
- &efi_global_variable_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_READ_ONLY,
- sizeof(os_indications_supported),
- &os_indications_supported, false);
+ ret = efi_init_os_indications();
if (ret != EFI_SUCCESS)
goto out;
@@ -189,6 +231,12 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
+ if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
+ ret = efi_tcg2_register();
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
/* Secure boot */
ret = efi_init_secure_boot();
if (ret != EFI_SUCCESS)
@@ -209,11 +257,6 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
#endif
-#ifdef CONFIG_EFI_LOAD_FILE2_INITRD
- ret = efi_initrd_register();
- if (ret != EFI_SUCCESS)
- goto out;
-#endif
#ifdef CONFIG_NET
ret = efi_net_register();
if (ret != EFI_SUCCESS)
@@ -233,11 +276,19 @@ efi_status_t efi_init_obj_list(void)
if (ret != EFI_SUCCESS)
goto out;
+ ret = efi_init_capsule();
+ if (ret != EFI_SUCCESS)
+ goto out;
+
/* Initialize EFI runtime services */
ret = efi_reset_system_init();
if (ret != EFI_SUCCESS)
goto out;
+ /* Execute capsules after reboot */
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
+ !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
+ ret = efi_launch_capsules();
out:
efi_obj_list_initialized = ret;
return ret;
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 79dee27..c7ec275 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -26,7 +26,92 @@ const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID;
const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID;
const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
-#ifdef CONFIG_EFI_SECURE_BOOT
+#if defined(CONFIG_EFI_SECURE_BOOT) || defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
+static u8 pkcs7_hdr[] = {
+ /* SEQUENCE */
+ 0x30, 0x82, 0x05, 0xc7,
+ /* OID: pkcs7-signedData */
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
+ /* Context Structured? */
+ 0xa0, 0x82, 0x05, 0xb8,
+};
+
+/**
+ * efi_parse_pkcs7_header - parse a signature in payload
+ * @buf: Pointer to payload's value
+ * @buflen: Length of @buf
+ * @tmpbuf: Pointer to temporary buffer
+ *
+ * Parse a signature embedded in payload's value and instantiate
+ * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
+ * pkcs7's signedData, some header needed be prepended for correctly
+ * parsing authentication data
+ * A temporary buffer will be allocated if needed, and it should be
+ * kept valid during the authentication because some data in the buffer
+ * will be referenced by efi_signature_verify().
+ *
+ * Return: Pointer to pkcs7_message structure on success, NULL on error
+ */
+struct pkcs7_message *efi_parse_pkcs7_header(const void *buf,
+ size_t buflen,
+ u8 **tmpbuf)
+{
+ u8 *ebuf;
+ size_t ebuflen, len;
+ struct pkcs7_message *msg;
+
+ /*
+ * This is the best assumption to check if the binary is
+ * already in a form of pkcs7's signedData.
+ */
+ if (buflen > sizeof(pkcs7_hdr) &&
+ !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
+ msg = pkcs7_parse_message(buf, buflen);
+ if (IS_ERR(msg))
+ return NULL;
+ return msg;
+ }
+
+ /*
+ * Otherwise, we should add a dummy prefix sequence for pkcs7
+ * message parser to be able to process.
+ * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
+ * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
+ * TODO:
+ * The header should be composed in a more refined manner.
+ */
+ EFI_PRINT("Makeshift prefix added to authentication data\n");
+ ebuflen = sizeof(pkcs7_hdr) + buflen;
+ if (ebuflen <= 0x7f) {
+ EFI_PRINT("Data is too short\n");
+ return NULL;
+ }
+
+ ebuf = malloc(ebuflen);
+ if (!ebuf) {
+ EFI_PRINT("Out of memory\n");
+ return NULL;
+ }
+
+ memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
+ memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
+ len = ebuflen - 4;
+ ebuf[2] = (len >> 8) & 0xff;
+ ebuf[3] = len & 0xff;
+ len = ebuflen - 0x13;
+ ebuf[0x11] = (len >> 8) & 0xff;
+ ebuf[0x12] = len & 0xff;
+
+ msg = pkcs7_parse_message(ebuf, ebuflen);
+
+ if (IS_ERR(msg)) {
+ free(ebuf);
+ return NULL;
+ }
+
+ *tmpbuf = ebuf;
+ return msg;
+}
/**
* efi_hash_regions - calculate a hash value
@@ -652,6 +737,63 @@ err:
}
/**
+ * efi_sigstore_parse_sigdb - parse the signature list and populate
+ * the signature store
+ *
+ * @sig_list: Pointer to the signature list
+ * @size: Size of the signature list
+ *
+ * Parse the efi signature list and instantiate a signature store
+ * structure.
+ *
+ * Return: Pointer to signature store on success, NULL on error
+ */
+struct efi_signature_store *efi_build_signature_store(void *sig_list,
+ efi_uintn_t size)
+{
+ struct efi_signature_list *esl;
+ struct efi_signature_store *sigstore = NULL, *siglist;
+
+ esl = sig_list;
+ while (size > 0) {
+ /* List must exist if there is remaining data. */
+ if (size < sizeof(*esl)) {
+ EFI_PRINT("Signature list in wrong format\n");
+ goto err;
+ }
+
+ if (size < esl->signature_list_size) {
+ EFI_PRINT("Signature list in wrong format\n");
+ goto err;
+ }
+
+ /* Parse a single siglist. */
+ siglist = efi_sigstore_parse_siglist(esl);
+ if (!siglist) {
+ EFI_PRINT("Parsing of signature list of failed\n");
+ goto err;
+ }
+
+ /* Append siglist */
+ siglist->next = sigstore;
+ sigstore = siglist;
+
+ /* Next */
+ size -= esl->signature_list_size;
+ esl = (void *)esl + esl->signature_list_size;
+ }
+ free(sig_list);
+
+ return sigstore;
+
+err:
+ efi_sigstore_free(sigstore);
+ free(sig_list);
+
+ return NULL;
+}
+
+/**
* efi_sigstore_parse_sigdb - parse a signature database variable
* @name: Variable's name
*
@@ -662,8 +804,7 @@ err:
*/
struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
{
- struct efi_signature_store *sigstore = NULL, *siglist;
- struct efi_signature_list *esl;
+ struct efi_signature_store *sigstore = NULL;
const efi_guid_t *vendor;
void *db;
efi_uintn_t db_size;
@@ -699,47 +840,10 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
if (ret != EFI_SUCCESS) {
EFI_PRINT("Getting variable, %ls, failed\n", name);
- goto err;
- }
-
- /* Parse siglist list */
- esl = db;
- while (db_size > 0) {
- /* List must exist if there is remaining data. */
- if (db_size < sizeof(*esl)) {
- EFI_PRINT("variable, %ls, in wrong format\n", name);
- goto err;
- }
-
- if (db_size < esl->signature_list_size) {
- EFI_PRINT("variable, %ls, in wrong format\n", name);
- goto err;
- }
-
- /* Parse a single siglist. */
- siglist = efi_sigstore_parse_siglist(esl);
- if (!siglist) {
- EFI_PRINT("Parsing signature list of %ls failed\n",
- name);
- goto err;
- }
-
- /* Append siglist */
- siglist->next = sigstore;
- sigstore = siglist;
-
- /* Next */
- db_size -= esl->signature_list_size;
- esl = (void *)esl + esl->signature_list_size;
+ free(db);
+ return NULL;
}
- free(db);
- return sigstore;
-
-err:
- efi_sigstore_free(sigstore);
- free(db);
-
- return NULL;
+ return efi_build_signature_store(db, db_size);
}
-#endif /* CONFIG_EFI_SECURE_BOOT */
+#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */
diff --git a/lib/efi_loader/efi_string.c b/lib/efi_loader/efi_string.c
index 3de721f..9627242 100644
--- a/lib/efi_loader/efi_string.c
+++ b/lib/efi_loader/efi_string.c
@@ -23,13 +23,19 @@
* Return: A pointer to the next position after the created string
* in @buffer, or NULL otherwise
*/
-u16 *efi_create_indexed_name(u16 *buffer, const char *name, unsigned int index)
+u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
+ unsigned int index)
{
u16 *p = buffer;
char index_buf[5];
+ size_t size;
+ size = (utf8_utf16_strlen(name) * sizeof(u16) +
+ sizeof(index_buf) * sizeof(u16));
+ if (buffer_size < size)
+ return NULL;
utf8_utf16_strcpy(&p, name);
- sprintf(index_buf, "%04X", index);
+ snprintf(index_buf, sizeof(index_buf), "%04X", index);
utf8_utf16_strcpy(&p, index_buf);
return p;
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 62f2f94..797d6eb 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -14,11 +14,24 @@
#include <efi_tcg2.h>
#include <log.h>
#include <tpm-v2.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
#include <linux/unaligned/access_ok.h>
#include <linux/unaligned/generic.h>
+#include <hexdump.h>
+
+struct event_log_buffer {
+ void *buffer;
+ void *final_buffer;
+ size_t pos; /* eventlog position */
+ size_t final_pos; /* final events config table position */
+ size_t last_event_size;
+ bool get_event_called;
+ bool truncated;
+};
-DECLARE_GLOBAL_DATA_PTR;
-
+static struct event_log_buffer event_log;
/*
* When requesting TPM2_CAP_TPM_PROPERTIES the value is on a standard offset.
* Since the current tpm2_get_capability() response buffers starts at
@@ -30,33 +43,40 @@ DECLARE_GLOBAL_DATA_PTR;
#define properties_offset (offsetof(struct tpml_tagged_tpm_property, tpm_property) + \
offsetof(struct tpms_tagged_property, value))
-struct {
+static const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID;
+static const efi_guid_t efi_guid_final_events = EFI_TCG2_FINAL_EVENTS_TABLE_GUID;
+
+struct digest_info {
u16 hash_alg;
u32 hash_mask;
-} hash_algo_list[] = {
+ u16 hash_len;
+};
+
+const static struct digest_info hash_algo_list[] = {
{
TPM2_ALG_SHA1,
EFI_TCG2_BOOT_HASH_ALG_SHA1,
+ TPM2_SHA1_DIGEST_SIZE,
},
{
TPM2_ALG_SHA256,
EFI_TCG2_BOOT_HASH_ALG_SHA256,
+ TPM2_SHA256_DIGEST_SIZE,
},
{
TPM2_ALG_SHA384,
EFI_TCG2_BOOT_HASH_ALG_SHA384,
+ TPM2_SHA384_DIGEST_SIZE,
},
{
TPM2_ALG_SHA512,
EFI_TCG2_BOOT_HASH_ALG_SHA512,
- },
- {
- TPM2_ALG_SM3_256,
- EFI_TCG2_BOOT_HASH_ALG_SM3_256,
+ TPM2_SHA512_DIGEST_SIZE,
},
};
#define MAX_HASH_COUNT ARRAY_SIZE(hash_algo_list)
+
/**
* alg_to_mask - Get a TCG hash mask for algorithms
*
@@ -76,7 +96,146 @@ static u32 alg_to_mask(u16 hash_alg)
return 0;
}
-const efi_guid_t efi_guid_tcg2_protocol = EFI_TCG2_PROTOCOL_GUID;
+/**
+ * alg_to_len - Get a TCG hash len for algorithms
+ *
+ * @hash_alg: TCG defined algorithm
+ *
+ * @Return: len of chosen algorithm, 0 if the algorithm is not supported
+ */
+static u16 alg_to_len(u16 hash_alg)
+{
+ int i;
+
+ for (i = 0; i < MAX_HASH_COUNT; i++) {
+ if (hash_algo_list[i].hash_alg == hash_alg)
+ return hash_algo_list[i].hash_len;
+ }
+
+ return 0;
+}
+
+static u32 tcg_event_final_size(struct tpml_digest_values *digest_list)
+{
+ u32 len;
+ int i;
+
+ len = offsetof(struct tcg_pcr_event2, digests);
+ len += offsetof(struct tpml_digest_values, digests);
+ for (i = 0; i < digest_list->count; i++) {
+ u16 hash_alg = digest_list->digests[i].hash_alg;
+
+ len += offsetof(struct tpmt_ha, digest);
+ len += alg_to_len(hash_alg);
+ }
+ len += sizeof(u32); /* tcg_pcr_event2 event_size*/
+
+ return len;
+}
+
+/* tcg2_pcr_extend - Extend PCRs for a TPM2 device for a given tpml_digest_values
+ *
+ * @dev: device
+ * @digest_list: list of digest algorithms to extend
+ *
+ * @Return: status code
+ */
+static efi_status_t tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
+ struct tpml_digest_values *digest_list)
+{
+ u32 rc;
+ int i;
+
+ for (i = 0; i < digest_list->count; i++) {
+ u32 alg = digest_list->digests[i].hash_alg;
+
+ rc = tpm2_pcr_extend(dev, pcr_index, alg,
+ (u8 *)&digest_list->digests[i].digest,
+ alg_to_len(alg));
+ if (rc) {
+ EFI_PRINT("Failed to extend PCR\n");
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/* tcg2_agile_log_append - Append an agile event to out eventlog
+ *
+ * @pcr_index: PCR index
+ * @event_type: type of event added
+ * @digest_list: list of digest algorithms to add
+ * @size: size of event
+ * @event: event to add
+ *
+ * @Return: status code
+ */
+static efi_status_t tcg2_agile_log_append(u32 pcr_index, u32 event_type,
+ struct tpml_digest_values *digest_list,
+ u32 size, u8 event[])
+{
+ void *log = event_log.buffer + event_log.pos;
+ size_t pos;
+ int i;
+ u32 event_size;
+
+ if (event_log.get_event_called)
+ log = event_log.final_buffer + event_log.final_pos;
+
+ /*
+ * size refers to the length of event[] only, we need to check against
+ * the final tcg_pcr_event2 size
+ */
+ event_size = size + tcg_event_final_size(digest_list);
+ if (event_log.pos + event_size > TPM2_EVENT_LOG_SIZE ||
+ event_log.final_pos + event_size > TPM2_EVENT_LOG_SIZE) {
+ event_log.truncated = true;
+ return EFI_VOLUME_FULL;
+ }
+
+ put_unaligned_le32(pcr_index, log);
+ pos = offsetof(struct tcg_pcr_event2, event_type);
+ put_unaligned_le32(event_type, log + pos);
+ pos = offsetof(struct tcg_pcr_event2, digests); /* count */
+ put_unaligned_le32(digest_list->count, log + pos);
+
+ pos += offsetof(struct tpml_digest_values, digests);
+ for (i = 0; i < digest_list->count; i++) {
+ u16 hash_alg = digest_list->digests[i].hash_alg;
+ u8 *digest = (u8 *)&digest_list->digests[i].digest;
+
+ put_unaligned_le16(hash_alg, log + pos);
+ pos += offsetof(struct tpmt_ha, digest);
+ memcpy(log + pos, digest, alg_to_len(hash_alg));
+ pos += alg_to_len(hash_alg);
+ }
+
+ put_unaligned_le32(size, log + pos);
+ pos += sizeof(u32); /* tcg_pcr_event2 event_size*/
+ memcpy(log + pos, event, size);
+ pos += size;
+
+ /* make sure the calculated buffer is what we checked against */
+ if (pos != event_size)
+ return EFI_INVALID_PARAMETER;
+
+ /* if GetEventLog hasn't been called update the normal log */
+ if (!event_log.get_event_called) {
+ event_log.pos += pos;
+ event_log.last_event_size = pos;
+ } else {
+ /* if GetEventLog has been called update config table log */
+ struct efi_tcg2_final_events_table *final_event;
+
+ final_event =
+ (struct efi_tcg2_final_events_table *)(event_log.final_buffer);
+ final_event->number_of_events++;
+ event_log.final_pos += pos;
+ }
+
+ return EFI_SUCCESS;
+}
/**
* platform_get_tpm_device() - retrieve TPM device
@@ -208,7 +367,7 @@ static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
*
* Return: true if PCR is active
*/
-bool is_active_pcr(struct tpms_pcr_selection *selection)
+static bool is_active_pcr(struct tpms_pcr_selection *selection)
{
int i;
/*
@@ -309,6 +468,103 @@ out:
}
/**
+ * __get_active_pcr_banks() - returns the currently active PCR banks
+ *
+ * @active_pcr_banks: pointer for receiving the bitmap of currently
+ * active PCR banks
+ *
+ * Return: status code
+ */
+static efi_status_t __get_active_pcr_banks(u32 *active_pcr_banks)
+{
+ struct udevice *dev;
+ u32 active, supported, pcr_banks;
+ efi_status_t ret;
+ int err;
+
+ ret = platform_get_tpm2_device(&dev);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ err = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks);
+ if (err) {
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
+
+ *active_pcr_banks = active;
+
+out:
+ return ret;
+}
+
+/* tcg2_create_digest - create a list of digests of the supported PCR banks
+ * for a given memory range
+ *
+ * @input: input memory
+ * @length: length of buffer to calculate the digest
+ * @digest_list: list of digests to fill in
+ *
+ * Return: status code
+ */
+static efi_status_t tcg2_create_digest(const u8 *input, u32 length,
+ struct tpml_digest_values *digest_list)
+{
+ sha1_context ctx;
+ sha256_context ctx_256;
+ sha512_context ctx_512;
+ u8 final[TPM2_ALG_SHA512];
+ efi_status_t ret;
+ u32 active;
+ int i;
+
+ ret = __get_active_pcr_banks(&active);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ digest_list->count = 0;
+ for (i = 0; i < MAX_HASH_COUNT; i++) {
+ u16 hash_alg = hash_algo_list[i].hash_alg;
+
+ if (!(active & alg_to_mask(hash_alg)))
+ continue;
+ switch (hash_alg) {
+ case TPM2_ALG_SHA1:
+ sha1_starts(&ctx);
+ sha1_update(&ctx, input, length);
+ sha1_finish(&ctx, final);
+ digest_list->count++;
+ break;
+ case TPM2_ALG_SHA256:
+ sha256_starts(&ctx_256);
+ sha256_update(&ctx_256, input, length);
+ sha256_finish(&ctx_256, final);
+ digest_list->count++;
+ break;
+ case TPM2_ALG_SHA384:
+ sha384_starts(&ctx_512);
+ sha384_update(&ctx_512, input, length);
+ sha384_finish(&ctx_512, final);
+ digest_list->count++;
+ break;
+ case TPM2_ALG_SHA512:
+ sha512_starts(&ctx_512);
+ sha512_update(&ctx_512, input, length);
+ sha512_finish(&ctx_512, final);
+ digest_list->count++;
+ break;
+ default:
+ EFI_PRINT("Unsupported algorithm %x\n", hash_alg);
+ return EFI_INVALID_PARAMETER;
+ }
+ digest_list->digests[i].hash_alg = hash_alg;
+ memcpy(&digest_list->digests[i].digest, final, (u32)alg_to_len(hash_alg));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
* efi_tcg2_get_capability() - protocol capability information and state information
*
* @this: TCG2 protocol instance
@@ -427,7 +683,28 @@ efi_tcg2_get_eventlog(struct efi_tcg2_protocol *this,
u64 *event_log_location, u64 *event_log_last_entry,
bool *event_log_truncated)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret = EFI_SUCCESS;
+ struct udevice *dev;
+
+ EFI_ENTRY("%p, %u, %p, %p, %p", this, log_format, event_log_location,
+ event_log_last_entry, event_log_truncated);
+
+ ret = platform_get_tpm2_device(&dev);
+ if (ret != EFI_SUCCESS) {
+ event_log_location = NULL;
+ event_log_last_entry = NULL;
+ *event_log_truncated = false;
+ ret = EFI_SUCCESS;
+ goto out;
+ }
+ *event_log_location = (uintptr_t)event_log.buffer;
+ *event_log_last_entry = (uintptr_t)(event_log.buffer + event_log.pos -
+ event_log.last_event_size);
+ *event_log_truncated = event_log.truncated;
+ event_log.get_event_called = true;
+
+out:
+ return EFI_EXIT(ret);
}
/**
@@ -450,7 +727,76 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags,
u64 data_to_hash, u64 data_to_hash_len,
struct efi_tcg2_event *efi_tcg_event)
{
- return EFI_UNSUPPORTED;
+ struct udevice *dev;
+ efi_status_t ret;
+ u32 event_type, pcr_index, event_size;
+ struct tpml_digest_values digest_list;
+
+ EFI_ENTRY("%p, %llu, %llu, %llu, %p", this, flags, data_to_hash,
+ data_to_hash_len, efi_tcg_event);
+
+ if (!this || !data_to_hash || !efi_tcg_event) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ ret = platform_get_tpm2_device(&dev);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ if (efi_tcg_event->size < efi_tcg_event->header.header_size +
+ sizeof(u32)) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (efi_tcg_event->header.pcr_index < 0 ||
+ efi_tcg_event->header.pcr_index > TPM2_MAX_PCRS) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ /*
+ * if PE_COFF_IMAGE is set we need to make sure the image is not
+ * corrupted, verify it and hash the PE/COFF image in accordance with
+ * the procedure specified in "Calculating the PE Image Hash"
+ * section of the "Windows Authenticode Portable Executable Signature
+ * Format"
+ * Not supported for now
+ */
+ if (flags & PE_COFF_IMAGE) {
+ ret = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ pcr_index = efi_tcg_event->header.pcr_index;
+ event_type = efi_tcg_event->header.event_type;
+
+ ret = tcg2_create_digest((u8 *)data_to_hash, data_to_hash_len,
+ &digest_list);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = tcg2_pcr_extend(dev, pcr_index, &digest_list);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ if (flags & EFI_TCG2_EXTEND_ONLY) {
+ if (event_log.truncated)
+ ret = EFI_VOLUME_FULL;
+ goto out;
+ }
+
+ /*
+ * The efi_tcg_event size includes the size component and the
+ * headersize
+ */
+ event_size = efi_tcg_event->size - sizeof(efi_tcg_event->size) -
+ efi_tcg_event->header.header_size;
+ ret = tcg2_agile_log_append(pcr_index, event_type, &digest_list,
+ event_size, efi_tcg_event->event);
+out:
+ return EFI_EXIT(ret);
}
/**
@@ -464,7 +810,7 @@ efi_tcg2_hash_log_extend_event(struct efi_tcg2_protocol *this, u64 flags,
*
* Return: status code
*/
-efi_status_t EFIAPI
+static efi_status_t EFIAPI
efi_tcg2_submit_command(struct efi_tcg2_protocol *this,
u32 input_param_block_size, u8 *input_param_block,
u32 output_param_block_size, u8 *output_param_block)
@@ -481,11 +827,16 @@ efi_tcg2_submit_command(struct efi_tcg2_protocol *this,
*
* Return: status code
*/
-efi_status_t EFIAPI
+static efi_status_t EFIAPI
efi_tcg2_get_active_pcr_banks(struct efi_tcg2_protocol *this,
u32 *active_pcr_banks)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret;
+
+ EFI_ENTRY("%p, %p", this, active_pcr_banks);
+ ret = __get_active_pcr_banks(active_pcr_banks);
+
+ return EFI_EXIT(ret);
}
/**
@@ -496,7 +847,7 @@ efi_tcg2_get_active_pcr_banks(struct efi_tcg2_protocol *this,
*
* Return: status code
*/
-efi_status_t EFIAPI
+static efi_status_t EFIAPI
efi_tcg2_set_active_pcr_banks(struct efi_tcg2_protocol *this,
u32 active_pcr_banks)
{
@@ -515,7 +866,7 @@ efi_tcg2_set_active_pcr_banks(struct efi_tcg2_protocol *this,
*
* Return: status code
*/
-efi_status_t EFIAPI
+static efi_status_t EFIAPI
efi_tcg2_get_result_of_set_active_pcr_banks(struct efi_tcg2_protocol *this,
u32 *operation_present, u32 *response)
{
@@ -533,6 +884,169 @@ static const struct efi_tcg2_protocol efi_tcg2_protocol = {
};
/**
+ * create_specid_event() - Create the first event in the eventlog
+ *
+ * @dev: tpm device
+ * @event_header: Pointer to the final event header
+ * @event_size: final spec event size
+ *
+ * Return: status code
+ */
+static efi_status_t create_specid_event(struct udevice *dev, void *buffer,
+ size_t *event_size)
+{
+ struct tcg_efi_spec_id_event *spec_event;
+ size_t spec_event_size;
+ efi_status_t ret = EFI_DEVICE_ERROR;
+ u32 active, supported;
+ int err, i;
+
+ /*
+ * Create Spec event. This needs to be the first event in the log
+ * according to the TCG EFI protocol spec
+ */
+
+ /* Setup specID event data */
+ spec_event = (struct tcg_efi_spec_id_event *)buffer;
+ memcpy(spec_event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
+ sizeof(spec_event->signature));
+ put_unaligned_le32(0, &spec_event->platform_class); /* type client */
+ spec_event->spec_version_minor =
+ TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2;
+ spec_event->spec_version_major =
+ TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2;
+ spec_event->spec_errata =
+ TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2;
+ spec_event->uintn_size = sizeof(efi_uintn_t) / sizeof(u32);
+
+ err = tpm2_get_pcr_info(dev, &supported, &active,
+ &spec_event->number_of_algorithms);
+ if (err)
+ goto out;
+ if (spec_event->number_of_algorithms > MAX_HASH_COUNT ||
+ spec_event->number_of_algorithms < 1)
+ goto out;
+
+ for (i = 0; i < spec_event->number_of_algorithms; i++) {
+ u16 hash_alg = hash_algo_list[i].hash_alg;
+ u16 hash_len = hash_algo_list[i].hash_len;
+
+ if (active && alg_to_mask(hash_alg)) {
+ put_unaligned_le16(hash_alg,
+ &spec_event->digest_sizes[i].algorithm_id);
+ put_unaligned_le16(hash_len,
+ &spec_event->digest_sizes[i].digest_size);
+ }
+ }
+ /*
+ * the size of the spec event and placement of vendor_info_size
+ * depends on supported algoriths
+ */
+ spec_event_size =
+ offsetof(struct tcg_efi_spec_id_event, digest_sizes) +
+ spec_event->number_of_algorithms * sizeof(spec_event->digest_sizes[0]);
+ /* no vendor info for us */
+ memset(buffer + spec_event_size, 0,
+ sizeof(spec_event->vendor_info_size));
+ spec_event_size += sizeof(spec_event->vendor_info_size);
+ *event_size = spec_event_size;
+
+ return EFI_SUCCESS;
+
+out:
+ return ret;
+}
+
+/**
+ * create_final_event() - Create the final event and install the config
+ * defined by the TCG EFI spec
+ */
+static efi_status_t create_final_event(void)
+{
+ struct efi_tcg2_final_events_table *final_event;
+ efi_status_t ret;
+
+ /*
+ * All events generated after the invocation of
+ * EFI_TCG2_GET_EVENT_LOGS need to be stored in an instance of an
+ * EFI_CONFIGURATION_TABLE
+ */
+ ret = efi_allocate_pool(EFI_ACPI_MEMORY_NVS, TPM2_EVENT_LOG_SIZE,
+ &event_log.final_buffer);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ memset(event_log.final_buffer, 0xff, TPM2_EVENT_LOG_SIZE);
+ final_event = event_log.final_buffer;
+ final_event->number_of_events = 0;
+ final_event->version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;
+ event_log.final_pos = sizeof(*final_event);
+ ret = efi_install_configuration_table(&efi_guid_final_events,
+ final_event);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ return EFI_SUCCESS;
+out:
+ return ret;
+}
+
+/**
+ * efi_init_event_log() - initialize an eventlog
+ */
+static efi_status_t efi_init_event_log(void)
+{
+ /*
+ * vendor_info_size is currently set to 0, we need to change the length
+ * and allocate the flexible array member if this changes
+ */
+ struct tcg_pcr_event *event_header = NULL;
+ struct udevice *dev;
+ size_t spec_event_size;
+ efi_status_t ret;
+
+ ret = platform_get_tpm2_device(&dev);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, TPM2_EVENT_LOG_SIZE,
+ (void **)&event_log.buffer);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ /*
+ * initialize log area as 0xff so the OS can easily figure out the
+ * last log entry
+ */
+ memset(event_log.buffer, 0xff, TPM2_EVENT_LOG_SIZE);
+ event_log.pos = 0;
+ event_log.last_event_size = 0;
+ event_log.get_event_called = false;
+ event_log.truncated = false;
+
+ /*
+ * The log header is defined to be in SHA1 event log entry format.
+ * Setup event header
+ */
+ event_header = (struct tcg_pcr_event *)event_log.buffer;
+ put_unaligned_le32(0, &event_header->pcr_index);
+ put_unaligned_le32(EV_NO_ACTION, &event_header->event_type);
+ memset(&event_header->digest, 0, sizeof(event_header->digest));
+ ret = create_specid_event(dev, event_log.buffer + sizeof(*event_header),
+ &spec_event_size);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ put_unaligned_le32(spec_event_size, &event_header->event_size);
+ event_log.pos = spec_event_size + sizeof(*event_header);
+ event_log.last_event_size = event_log.pos;
+
+ ret = create_final_event();
+
+out:
+ return ret;
+}
+
+/**
* efi_tcg2_register() - register EFI_TCG2_PROTOCOL
*
* If a TPM2 device is available, the TPM TCG2 Protocol is registered
@@ -549,6 +1063,11 @@ efi_status_t efi_tcg2_register(void)
log_warning("Unable to find TPMv2 device\n");
return EFI_SUCCESS;
}
+
+ ret = efi_init_event_log();
+ if (ret != EFI_SUCCESS)
+ return ret;
+
ret = efi_add_protocol(efi_root, &efi_guid_tcg2_protocol,
(void *)&efi_tcg2_protocol);
if (ret != EFI_SUCCESS)
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 0c689cf..ba0874e 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -24,91 +24,6 @@
#include <asm/sections.h>
#ifdef CONFIG_EFI_SECURE_BOOT
-static u8 pkcs7_hdr[] = {
- /* SEQUENCE */
- 0x30, 0x82, 0x05, 0xc7,
- /* OID: pkcs7-signedData */
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02,
- /* Context Structured? */
- 0xa0, 0x82, 0x05, 0xb8,
-};
-
-/**
- * efi_variable_parse_signature - parse a signature in variable
- * @buf: Pointer to variable's value
- * @buflen: Length of @buf
- * @tmpbuf: Pointer to temporary buffer
- *
- * Parse a signature embedded in variable's value and instantiate
- * a pkcs7_message structure. Since pkcs7_parse_message() accepts only
- * pkcs7's signedData, some header needed be prepended for correctly
- * parsing authentication data, particularly for variable's.
- * A temporary buffer will be allocated if needed, and it should be
- * kept valid during the authentication because some data in the buffer
- * will be referenced by efi_signature_verify().
- *
- * Return: Pointer to pkcs7_message structure on success, NULL on error
- */
-static struct pkcs7_message *efi_variable_parse_signature(const void *buf,
- size_t buflen,
- u8 **tmpbuf)
-{
- u8 *ebuf;
- size_t ebuflen, len;
- struct pkcs7_message *msg;
-
- /*
- * This is the best assumption to check if the binary is
- * already in a form of pkcs7's signedData.
- */
- if (buflen > sizeof(pkcs7_hdr) &&
- !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) {
- msg = pkcs7_parse_message(buf, buflen);
- if (IS_ERR(msg))
- return NULL;
- return msg;
- }
-
- /*
- * Otherwise, we should add a dummy prefix sequence for pkcs7
- * message parser to be able to process.
- * NOTE: EDK2 also uses similar hack in WrapPkcs7Data()
- * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
- * TODO:
- * The header should be composed in a more refined manner.
- */
- EFI_PRINT("Makeshift prefix added to authentication data\n");
- ebuflen = sizeof(pkcs7_hdr) + buflen;
- if (ebuflen <= 0x7f) {
- EFI_PRINT("Data is too short\n");
- return NULL;
- }
-
- ebuf = malloc(ebuflen);
- if (!ebuf) {
- EFI_PRINT("Out of memory\n");
- return NULL;
- }
-
- memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr));
- memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen);
- len = ebuflen - 4;
- ebuf[2] = (len >> 8) & 0xff;
- ebuf[3] = len & 0xff;
- len = ebuflen - 0x13;
- ebuf[0x11] = (len >> 8) & 0xff;
- ebuf[0x12] = len & 0xff;
-
- msg = pkcs7_parse_message(ebuf, ebuflen);
-
- if (IS_ERR(msg)) {
- free(ebuf);
- return NULL;
- }
-
- *tmpbuf = ebuf;
- return msg;
-}
/**
* efi_variable_authenticate - authenticate a variable
@@ -215,10 +130,10 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
goto err;
/* ebuf should be kept valid during the authentication */
- var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
- auth->auth_info.hdr.dwLength
- - sizeof(auth->auth_info),
- &ebuf);
+ var_sig = efi_parse_pkcs7_header(auth->auth_info.cert_data,
+ auth->auth_info.hdr.dwLength
+ - sizeof(auth->auth_info),
+ &ebuf);
if (!var_sig) {
EFI_PRINT("Parsing variable's signature failed\n");
goto err;
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 58fb43f..426552b 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -25,9 +25,12 @@ efi_selftest_crc32.o \
efi_selftest_devicepath_util.o \
efi_selftest_events.o \
efi_selftest_event_groups.o \
+efi_selftest_exception.o \
efi_selftest_exitbootservices.o \
efi_selftest_gop.o \
+efi_selftest_load_file.o \
efi_selftest_loaded_image.o \
+efi_selftest_loadimage.o \
efi_selftest_manageprotocols.o \
efi_selftest_mem.o \
efi_selftest_memory.o \
@@ -35,6 +38,8 @@ efi_selftest_open_protocol.o \
efi_selftest_register_notify.o \
efi_selftest_reset.o \
efi_selftest_set_virtual_address_map.o \
+efi_selftest_startimage_exit.o \
+efi_selftest_startimage_return.o \
efi_selftest_textinput.o \
efi_selftest_textinputex.o \
efi_selftest_textoutput.o \
@@ -65,12 +70,6 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy)
obj-y += efi_selftest_block_device.o
endif
-obj-y += \
-efi_selftest_exception.o \
-efi_selftest_loadimage.o \
-efi_selftest_startimage_exit.o \
-efi_selftest_startimage_return.o
-
targets += \
efi_miniapp_file_image_exception.h \
efi_miniapp_file_image_exit.h \
@@ -94,10 +93,12 @@ $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi
$(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \
$(obj)/efi_miniapp_file_image_return.h
-$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h
-
$(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h
+$(obj)/efi_selftest_load_file.o: $(obj)/efi_miniapp_file_image_exit.h
+
+$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h
+
$(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h
$(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h
diff --git a/lib/efi_selftest/efi_selftest_load_file.c b/lib/efi_selftest/efi_selftest_load_file.c
new file mode 100644
index 0000000..4473e7c
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_load_file.c
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_load_file
+ *
+ * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol
+ * by the LoadImage() service.
+ */
+
+#include <efi_selftest.h>
+/* Include containing the miniapp.efi application */
+#include "efi_miniapp_file_image_exit.h"
+
+/* Block size of compressed disk image */
+#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
+
+/* Binary logarithm of the block size */
+#define LB_BLOCK_SIZE 9
+
+#define GUID_VENDOR \
+ EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
+ 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1)
+
+#define GUID_VENDOR2 \
+ EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
+ 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2)
+
+#define FILE_NAME_SIZE 16
+
+static const efi_guid_t efi_st_guid_load_file_protocol =
+ EFI_LOAD_FILE_PROTOCOL_GUID;
+static const efi_guid_t efi_st_guid_load_file2_protocol =
+ EFI_LOAD_FILE2_PROTOCOL_GUID;
+static const efi_guid_t efi_st_guid_device_path =
+ EFI_DEVICE_PATH_PROTOCOL_GUID;
+
+static efi_handle_t image_handle;
+static struct efi_boot_services *boottime;
+static efi_handle_t handle_lf;
+static efi_handle_t handle_lf2;
+
+/* One 8 byte block of the compressed disk image */
+struct line {
+ size_t addr;
+ char *line;
+};
+
+/* Compressed file image */
+struct compressed_file_image {
+ size_t length;
+ struct line lines[];
+};
+
+static struct compressed_file_image img = EFI_ST_DISK_IMG;
+
+static int load_file_call_count;
+static int load_file2_call_count;
+
+/* Decompressed file image */
+static u8 *image;
+
+static struct {
+ struct efi_device_path_vendor v;
+ struct efi_device_path d;
+} dp_lf_prot = {
+ {
+ {
+ DEVICE_PATH_TYPE_HARDWARE_DEVICE,
+ DEVICE_PATH_SUB_TYPE_VENDOR,
+ sizeof(struct efi_device_path_vendor),
+ },
+ GUID_VENDOR,
+ },
+ {
+ DEVICE_PATH_TYPE_END,
+ DEVICE_PATH_SUB_TYPE_END,
+ sizeof(struct efi_device_path),
+ },
+};
+
+static struct {
+ struct efi_device_path_vendor v;
+ struct efi_device_path_file_path f;
+ u16 file_name[FILE_NAME_SIZE];
+ struct efi_device_path e;
+} dp_lf_file = {
+ {
+ {
+ DEVICE_PATH_TYPE_HARDWARE_DEVICE,
+ DEVICE_PATH_SUB_TYPE_VENDOR,
+ sizeof(struct efi_device_path_vendor),
+ },
+ GUID_VENDOR,
+ },
+ {
+ {
+ DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ DEVICE_PATH_SUB_TYPE_FILE_PATH,
+ sizeof(struct efi_device_path_file_path) +
+ FILE_NAME_SIZE * sizeof(u16),
+ }
+ },
+ L"\\lf.efi",
+ {
+ DEVICE_PATH_TYPE_END,
+ DEVICE_PATH_SUB_TYPE_END,
+ sizeof(struct efi_device_path),
+ },
+};
+
+struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp;
+
+static struct {
+ struct efi_device_path_vendor v;
+ struct efi_device_path d;
+} dp_lf2_prot = {
+ {
+ {
+ DEVICE_PATH_TYPE_HARDWARE_DEVICE,
+ DEVICE_PATH_SUB_TYPE_VENDOR,
+ sizeof(struct efi_device_path_vendor),
+ },
+ GUID_VENDOR2,
+ },
+ {
+ DEVICE_PATH_TYPE_END,
+ DEVICE_PATH_SUB_TYPE_END,
+ sizeof(struct efi_device_path),
+ },
+};
+
+static struct {
+ struct efi_device_path_vendor v;
+ struct efi_device_path_file_path f;
+ u16 file_name[FILE_NAME_SIZE];
+ struct efi_device_path e;
+} dp_lf2_file = {
+ {
+ {
+ DEVICE_PATH_TYPE_HARDWARE_DEVICE,
+ DEVICE_PATH_SUB_TYPE_VENDOR,
+ sizeof(struct efi_device_path_vendor),
+ },
+ GUID_VENDOR2,
+ },
+ {
+ {
+ DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ DEVICE_PATH_SUB_TYPE_FILE_PATH,
+ sizeof(struct efi_device_path_file_path) +
+ FILE_NAME_SIZE * sizeof(u16),
+ }
+ },
+ L"\\lf2.efi",
+ {
+ DEVICE_PATH_TYPE_END,
+ DEVICE_PATH_SUB_TYPE_END,
+ sizeof(struct efi_device_path),
+ },
+};
+
+struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp;
+
+/*
+ * Decompress the disk image.
+ *
+ * @image decompressed disk image
+ * @return status code
+ */
+static efi_status_t decompress(u8 **image)
+{
+ u8 *buf;
+ size_t i;
+ size_t addr;
+ size_t len;
+ efi_status_t ret;
+
+ ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
+ (void **)&buf);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Out of memory\n");
+ return ret;
+ }
+ boottime->set_mem(buf, img.length, 0);
+
+ for (i = 0; ; ++i) {
+ if (!img.lines[i].line)
+ break;
+ addr = img.lines[i].addr;
+ len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
+ if (addr + len > img.length)
+ len = img.length - addr;
+ boottime->copy_mem(buf + addr, img.lines[i].line, len);
+ }
+ *image = buf;
+ return ret;
+}
+
+/*
+ * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL
+ *
+ * @this: instance of EFI_LOAD_FILE_PROTOCOL
+ * @file_path: remaining device path
+ * @boot_policy: true if called by boot manager
+ * @buffer_size: (required) buffer size
+ * @buffer: buffer to which the file is to be loaded
+ */
+efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this,
+ struct efi_device_path *file_path,
+ bool boot_policy,
+ efi_uintn_t *buffer_size,
+ void *buffer)
+{
+ ++load_file_call_count;
+ if (memcmp(file_path, dp_lf_file_remainder,
+ sizeof(struct efi_device_path_file_path) +
+ FILE_NAME_SIZE * sizeof(u16) +
+ sizeof(struct efi_device_path))) {
+ efi_st_error("Wrong remaining device path\n");
+ return EFI_NOT_FOUND;
+ }
+ if (this->load_file != load_file) {
+ efi_st_error("wrong this\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*buffer_size < img.length) {
+ *buffer_size = img.length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ memcpy(buffer, image, img.length);
+ *buffer_size = img.length;
+ return EFI_SUCCESS;
+}
+
+
+/*
+ * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL
+ *
+ * @this: instance of EFI_LOAD_FILE2_PROTOCOL
+ * @file_path: remaining device path
+ * @boot_policy: true if called by boot manager
+ * @buffer_size: (required) buffer size
+ * @buffer: buffer to which the file is to be loaded
+ */
+efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this,
+ struct efi_device_path *file_path,
+ bool boot_policy,
+ efi_uintn_t *buffer_size,
+ void *buffer)
+{
+ ++load_file2_call_count;
+ if (memcmp(file_path, dp_lf2_file_remainder,
+ sizeof(struct efi_device_path_file_path) +
+ FILE_NAME_SIZE * sizeof(u16) +
+ sizeof(struct efi_device_path))) {
+ efi_st_error("Wrong remaining device path\n");
+ return EFI_NOT_FOUND;
+ }
+ if (this->load_file != load_file2) {
+ efi_st_error("wrong this\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (boot_policy) {
+ efi_st_error("LOAD_FILE2 called with boot_policy = true");
+ return EFI_INVALID_PARAMETER;
+ }
+ if (*buffer_size < img.length) {
+ *buffer_size = img.length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ memcpy(buffer, image, img.length);
+ *buffer_size = img.length;
+ return EFI_SUCCESS;
+}
+
+static struct efi_load_file_protocol lf_prot = {load_file};
+static struct efi_load_file_protocol lf2_prot = {load_file2};
+
+/*
+ * Setup unit test.
+ *
+ * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL.
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int efi_st_load_file_setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_status_t ret;
+
+ image_handle = handle;
+ boottime = systable->boottime;
+
+ /* Load the application image into memory */
+ decompress(&image);
+
+ ret = boottime->install_multiple_protocol_interfaces(
+ &handle_lf,
+ &efi_st_guid_device_path,
+ &dp_lf_prot,
+ &efi_st_guid_load_file_protocol,
+ &lf_prot,
+ NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("InstallMultipleProtocolInterfaces failed\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->install_multiple_protocol_interfaces(
+ &handle_lf2,
+ &efi_st_guid_device_path,
+ &dp_lf2_prot,
+ &efi_st_guid_load_file2_protocol,
+ &lf2_prot,
+ NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("InstallMultipleProtocolInterfaces failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Tear down unit test.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int efi_st_load_file_teardown(void)
+{
+ efi_status_t ret = EFI_ST_SUCCESS;
+
+ if (handle_lf) {
+ ret = boottime->uninstall_multiple_protocol_interfaces(
+ handle_lf,
+ &efi_st_guid_device_path,
+ &dp_lf_prot,
+ &efi_st_guid_load_file_protocol,
+ &lf_prot,
+ NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error(
+ "UninstallMultipleProtocolInterfaces failed\n");
+ return EFI_ST_FAILURE;
+ }
+ }
+ if (handle_lf2) {
+ ret = boottime->uninstall_multiple_protocol_interfaces(
+ handle_lf2,
+ &efi_st_guid_device_path,
+ &dp_lf2_prot,
+ &efi_st_guid_load_file2_protocol,
+ &lf2_prot,
+ NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error(
+ "UninstallMultipleProtocolInterfaces failed\n");
+ return EFI_ST_FAILURE;
+ }
+ }
+
+ if (image) {
+ ret = boottime->free_pool(image);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to free image\n");
+ return EFI_ST_FAILURE;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Execute unit test.
+ *
+ * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the
+ * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image.
+ *
+ * @return: EFI_ST_SUCCESS for success
+ */
+static int efi_st_load_file_execute(void)
+{
+ efi_status_t ret;
+ efi_handle_t handle;
+ efi_uintn_t exit_data_size = 0;
+ u16 *exit_data = NULL;
+ u16 expected_text[] = EFI_ST_SUCCESS_STR;
+
+ load_file_call_count = 0;
+ load_file2_call_count = 0;
+ handle = NULL;
+ ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL,
+ 0, &handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to load image\n");
+ return EFI_ST_FAILURE;
+ }
+ if (load_file2_call_count || !load_file_call_count) {
+ efi_st_error("Wrong image loaded\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->unload_image(handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to unload image\n");
+ return EFI_ST_FAILURE;
+ }
+
+ load_file_call_count = 0;
+ load_file2_call_count = 0;
+ handle = NULL;
+ ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL,
+ 0, &handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to load image\n");
+ return EFI_ST_FAILURE;
+ }
+ if (load_file2_call_count || !load_file_call_count) {
+ efi_st_error("Wrong image loaded\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->unload_image(handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to unload image\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL,
+ 0, &handle);
+ if (ret != EFI_NOT_FOUND) {
+ efi_st_error(
+ "Boot manager should not use LOAD_FILE2_PROTOCOL\n");
+ return EFI_ST_FAILURE;
+ }
+
+ load_file_call_count = 0;
+ load_file2_call_count = 0;
+ handle = NULL;
+ ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL,
+ 0, &handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to load image\n");
+ return EFI_ST_FAILURE;
+ }
+ if (!load_file2_call_count || load_file_call_count) {
+ efi_st_error("Wrong image loaded\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->start_image(handle, &exit_data_size, &exit_data);
+ if (ret != EFI_UNSUPPORTED) {
+ efi_st_error("Wrong return value from application\n");
+ return EFI_ST_FAILURE;
+ }
+ if (!exit_data || exit_data_size != sizeof(expected_text) ||
+ memcmp(exit_data, expected_text, sizeof(expected_text))) {
+ efi_st_error("Incorrect exit data\n");
+ return EFI_ST_FAILURE;
+ }
+ ret = boottime->free_pool(exit_data);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to free exit data\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(load_file_protocol) = {
+ .name = "load file protocol",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = efi_st_load_file_setup,
+ .execute = efi_st_load_file_execute,
+ .teardown = efi_st_load_file_teardown,
+};
diff --git a/lib/efi_selftest/efi_selftest_load_initrd.c b/lib/efi_selftest/efi_selftest_load_initrd.c
index fe060a6..f591dcd 100644
--- a/lib/efi_selftest/efi_selftest_load_initrd.c
+++ b/lib/efi_selftest/efi_selftest_load_initrd.c
@@ -86,7 +86,6 @@ static int setup(const efi_handle_t handle,
static int execute(void)
{
- efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
struct efi_load_file_protocol *lf2;
struct efi_device_path *dp2, *dp2_invalid;
efi_status_t status;
@@ -99,13 +98,15 @@ static int execute(void)
memset(buffer, 0, sizeof(buffer));
dp2 = (struct efi_device_path *)&dp;
- status = boottime->locate_device_path(&lf2_proto_guid, &dp2, &handle);
+ status = boottime->locate_device_path(&efi_guid_load_file2_protocol,
+ &dp2, &handle);
if (status != EFI_SUCCESS) {
efi_st_error("Unable to locate device path\n");
return EFI_ST_FAILURE;
}
- status = boottime->handle_protocol(handle, &lf2_proto_guid,
+ status = boottime->handle_protocol(handle,
+ &efi_guid_load_file2_protocol,
(void **)&lf2);
if (status != EFI_SUCCESS) {
efi_st_error("Unable to locate protocol\n");
diff --git a/lib/efi_selftest/efi_selftest_miniapp_exception.c b/lib/efi_selftest/efi_selftest_miniapp_exception.c
index 63c63d7..59b7e51 100644
--- a/lib/efi_selftest/efi_selftest_miniapp_exception.c
+++ b/lib/efi_selftest/efi_selftest_miniapp_exception.c
@@ -33,6 +33,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle,
asm volatile (".word 0xe7f7defb\n");
#elif defined(CONFIG_RISCV)
asm volatile (".word 0xffffffff\n");
+#elif defined(CONFIG_SANDBOX)
+ asm volatile (".word 0xffffffff\n");
#elif defined(CONFIG_X86)
asm volatile (".word 0xffff\n");
#endif
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index ee1bd41..0ab7105 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -500,6 +500,17 @@ int fdtdec_get_alias_seq(const void *blob, const char *base, int offset,
slash = strrchr(prop, '/');
if (strcmp(slash + 1, find_name))
continue;
+
+ /*
+ * Adding an extra check to distinguish DT nodes with
+ * same name
+ */
+ if (IS_ENABLED(CONFIG_PHANDLE_CHECK_SEQ)) {
+ if (fdt_get_phandle(blob, offset) !=
+ fdt_get_phandle(blob, fdt_path_offset(blob, prop)))
+ continue;
+ }
+
val = trailing_strtol(name);
if (val != -1) {
*seqp = val;
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 7c08f5c..ff5ff72 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -472,7 +472,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
idx = hsearch_r(e, ENV_FIND, &ep, htab, 0);
if (idx == 0) {
__set_errno(ESRCH);
- return 0; /* not found */
+ return -ENOENT; /* not found */
}
/* Check for permission */
@@ -481,7 +481,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
debug("change_ok() rejected deleting variable "
"%s, skipping it!\n", key);
__set_errno(EPERM);
- return 0;
+ return -EPERM;
}
/* If there is a callback, call it */
@@ -490,12 +490,12 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
debug("callback() rejected deleting variable "
"%s, skipping it!\n", key);
__set_errno(EINVAL);
- return 0;
+ return -EINVAL;
}
_hdelete(key, htab, ep, idx);
- return 1;
+ return 0;
}
#if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV))
@@ -917,7 +917,7 @@ int himport_r(struct hsearch_data *htab,
if (!drop_var_from_set(name, nvars, localvars))
continue;
- if (hdelete_r(name, htab, flag) == 0)
+ if (hdelete_r(name, htab, flag))
debug("DELETE ERROR ##############################\n");
continue;
@@ -979,7 +979,7 @@ int himport_r(struct hsearch_data *htab,
* b) if the variable was not present in current env, we notify
* it might be a typo
*/
- if (hdelete_r(localvars[i], htab, flag) == 0)
+ if (hdelete_r(localvars[i], htab, flag))
printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
else
printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
diff --git a/lib/smbios.c b/lib/smbios.c
index 485a812..1e10fa8 100644
--- a/lib/smbios.c
+++ b/lib/smbios.c
@@ -229,7 +229,7 @@ static void smbios_write_type4_dm(struct smbios_type4 *t, ofnode node)
uclass_find_first_device(UCLASS_CPU, &cpu);
if (cpu) {
- struct cpu_platdata *plat = dev_get_parent_platdata(cpu);
+ struct cpu_plat *plat = dev_get_parent_plat(cpu);
if (plat->family)
processor_family = plat->family;
diff --git a/lib/time.c b/lib/time.c
index 88bc504..cc6944e 100644
--- a/lib/time.c
+++ b/lib/time.c
@@ -9,6 +9,7 @@
#include <dm.h>
#include <errno.h>
#include <init.h>
+#include <spl.h>
#include <time.h>
#include <timer.h>
#include <watchdog.h>
@@ -96,8 +97,13 @@ uint64_t notrace get_ticks(void)
}
ret = timer_get_count(gd->timer, &count);
- if (ret)
- panic("Could not read count from timer (err %d)\n", ret);
+ if (ret) {
+ if (spl_phase() > PHASE_TPL)
+ panic("Could not read count from timer (err %d)\n",
+ ret);
+ else
+ panic("no timer (err %d)\n", ret);
+ }
return count;
}
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 9175906..1f3deb0 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -80,11 +80,12 @@ u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
}
-u32 tpm2_pcr_extend(struct udevice *dev, u32 index, const uint8_t *digest)
+u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
+ const u8 *digest, u32 digest_len)
{
u8 command_v2[COMMAND_BUFFER_SIZE] = {
tpm_u16(TPM2_ST_SESSIONS), /* TAG */
- tpm_u32(33 + TPM2_DIGEST_LEN), /* Length */
+ tpm_u32(33 + digest_len), /* Length */
tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
/* HANDLE */
@@ -99,7 +100,7 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, const uint8_t *digest)
tpm_u16(0), /* Size of <hmac/password> */
/* <hmac/password> (if any) */
tpm_u32(1), /* Count (number of hashes) */
- tpm_u16(TPM2_ALG_SHA256), /* Algorithm of the hash */
+ tpm_u16(algorithm), /* Algorithm of the hash */
/* STRING(digest) Digest */
};
unsigned int offset = 33;
@@ -110,8 +111,8 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, const uint8_t *digest)
* - the digest
*/
ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
- offset, digest, TPM2_DIGEST_LEN);
- offset += TPM2_DIGEST_LEN;
+ offset, digest, digest_len);
+ offset += digest_len;
if (ret)
return TPM_LIB_ERROR;