From 314bed6c854e41b2edd5cefb7009e3b6040abd28 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 28 Oct 2020 18:45:47 +0100 Subject: efi_loader: fix DisconnectController() for sole child If ChildHandle indicates the sole child of the driver, disconnect the driver. This fixes the test results for UEFI SCT 2.6 A sub-tests 5.1.3.12.43, 5.1.3.12.44, 5.1.3.12.45. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b26ac9fbfc..dfa71b1774 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3523,6 +3523,7 @@ static efi_status_t EFIAPI efi_disconnect_controller( size_t number_of_children = 0; efi_status_t r; struct efi_object *efiobj; + bool sole_child; EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle, child_handle); @@ -3545,16 +3546,18 @@ static efi_status_t EFIAPI efi_disconnect_controller( } /* Create list of child handles */ + r = efi_get_child_controllers(efiobj, + driver_image_handle, + &number_of_children, + &child_handle_buffer); + if (r != EFI_SUCCESS) + return r; + sole_child = (number_of_children == 1); + if (child_handle) { number_of_children = 1; + free(child_handle_buffer); child_handle_buffer = &child_handle; - } else { - r = efi_get_child_controllers(efiobj, - driver_image_handle, - &number_of_children, - &child_handle_buffer); - if (r != EFI_SUCCESS) - return r; } /* Get the driver binding protocol */ @@ -3579,7 +3582,7 @@ static efi_status_t EFIAPI efi_disconnect_controller( } } /* Remove the driver */ - if (!child_handle) { + if (!child_handle || sole_child) { r = EFI_CALL(binding_protocol->stop(binding_protocol, controller_handle, 0, NULL)); -- cgit v1.2.1 From 0ca4b558b59d69d0b39ce42664c601690ecc8d6c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 30 Oct 2020 03:05:47 +0100 Subject: rtc: use probe() to initialize emulated RTC Currently the emulated RTC is initialized in the emul_rtc_get() get function. This does not match the design of the driver model. Move the initialization of the emulated RTC to the probe() function. Signed-off-by: Heinrich Schuchardt --- drivers/rtc/emul_rtc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/emul_rtc.c b/drivers/rtc/emul_rtc.c index c98c24bbb3..209b4965c1 100644 --- a/drivers/rtc/emul_rtc.c +++ b/drivers/rtc/emul_rtc.c @@ -30,12 +30,6 @@ static int emul_rtc_get(struct udevice *dev, struct rtc_time *time) struct emul_rtc *priv = dev_get_priv(dev); u64 now; - if (!priv->offset_us) { - /* Use the build date as initial time */ - priv->offset_us = U_BOOT_EPOCH * 1000000ULL - timer_get_us(); - priv->isdst = -1; - } - now = timer_get_us() + priv->offset_us; do_div(now, 1000000); rtc_to_tm(now, time); @@ -63,6 +57,17 @@ static int emul_rtc_set(struct udevice *dev, const struct rtc_time *time) return 0; } +int emul_rtc_probe(struct udevice *dev) +{ + struct emul_rtc *priv = dev_get_priv(dev); + + /* Use the build date as initial time */ + priv->offset_us = U_BOOT_EPOCH * 1000000ULL - timer_get_us(); + priv->isdst = -1; + + return 0; +} + static const struct rtc_ops emul_rtc_ops = { .get = emul_rtc_get, .set = emul_rtc_set, @@ -72,6 +77,7 @@ U_BOOT_DRIVER(rtc_emul) = { .name = "rtc_emul", .id = UCLASS_RTC, .ops = &emul_rtc_ops, + .probe = emul_rtc_probe, .priv_auto_alloc_size = sizeof(struct emul_rtc), }; -- cgit v1.2.1 From fb71c3f49016abcadf0d0cbe9df99975e64de651 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 30 Oct 2020 03:27:22 +0100 Subject: rtc: initialize emulated RTC from environment variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up to now the emulated RTC is initialized using the U-Boot build time. With this patch the environment variable 'rtc_emul_epoch' can be used to provide a better initial time. The variable is a decimal string with the number of seconds since 1970-01-01. Here is an example where the RTC had not been probed yet: => setenv rtc_emul_epoch 1610109000 => date Date: 2021-01-08 (Friday) Time: 12:30:00 If the variable does not exist, the U-Boot build time is used as fallback. The environment variable may be set when shutting down the operating system if the U-Boot environment is exposed to the OS (cf. ENV_IS_IN_FAT and ENV_IS_IN_EXT4). Suggested-by: Pablo Sebastián Greco Signed-off-by: Heinrich Schuchardt --- drivers/rtc/Kconfig | 13 ++++++++----- drivers/rtc/emul_rtc.c | 16 +++++++++++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d06d272e14..cad667a404 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -68,11 +68,14 @@ config RTC_EMULATION depends on DM_RTC help On a board without hardware clock this software real time clock can be - used. The build time is used to initialize the RTC. So you will have - to adjust the time either manually using the 'date' command or use - the 'sntp' to update the RTC with the time from a network time server. - See CONFIG_CMD_SNTP and CONFIG_BOOTP_NTPSERVER. The RTC time is - advanced according to CPU ticks. + used. The initial time may be provided via the environment variable + 'rtc_emul_epoch' as a decimal string indicating seconds since + 1970-01-01. If the environment variable is missing, the build time is + used to initialize the RTC. The time can be adjusted manually via the + 'date' command or the 'sntp' command can be used to update the RTC + with the time from a network time server. See CONFIG_CMD_SNTP and + CONFIG_BOOTP_NTPSERVER. The RTC time is advanced according to CPU + ticks. config RTC_ISL1208 bool "Enable ISL1208 driver" diff --git a/drivers/rtc/emul_rtc.c b/drivers/rtc/emul_rtc.c index 209b4965c1..7e522103fd 100644 --- a/drivers/rtc/emul_rtc.c +++ b/drivers/rtc/emul_rtc.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -60,9 +61,18 @@ static int emul_rtc_set(struct udevice *dev, const struct rtc_time *time) int emul_rtc_probe(struct udevice *dev) { struct emul_rtc *priv = dev_get_priv(dev); - - /* Use the build date as initial time */ - priv->offset_us = U_BOOT_EPOCH * 1000000ULL - timer_get_us(); + const char *epoch_str; + u64 epoch; + + epoch_str = env_get("rtc_emul_epoch"); + + if (epoch_str) { + epoch = simple_strtoull(epoch_str, NULL, 10); + } else { + /* Use the build date as initial time */ + epoch = U_BOOT_EPOCH; + } + priv->offset_us = epoch * 1000000ULL - timer_get_us(); priv->isdst = -1; return 0; -- cgit v1.2.1 From 31393564462ac706c080fbd9625382540a41d27c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 30 Oct 2020 12:14:16 +0100 Subject: efi_loader: typo in function description of u16_strnlen %/u16_strlen/u16_strnlen()/ Signed-off-by: Heinrich Schuchardt --- include/charset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/charset.h b/include/charset.h index 5564f3bce5..cc650a2ce7 100644 --- a/include/charset.h +++ b/include/charset.h @@ -219,7 +219,7 @@ size_t u16_strlen(const void *in); size_t u16_strsize(const void *in); /** - * u16_strlen - count non-zero words + * u16_strnlen() - count non-zero words * * This function matches wscnlen_s() if the -fshort-wchar compiler flag is set. * In the EFI context we explicitly need a function handling u16 strings. -- cgit v1.2.1 From 045fd8b13dc7b08a309043c28fc764c8fd2fde14 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:41 +0900 Subject: dfu: rename dfu_tftp_write() to dfu_write_by_name() This function is essentially independent from tftp, and will also be utilised in implementing UEFI capsule update in a later commit. So just give it a more generic name. In addition, a new configuration option, CONFIG_DFU_WRITE_ALT, was introduced so that the file will be compiled with different options, particularly one added in a later commit. Signed-off-by: AKASHI Takahiro Reviewed-by: Tom Rini --- common/update.c | 5 ++-- drivers/dfu/Kconfig | 5 ++++ drivers/dfu/Makefile | 2 +- drivers/dfu/dfu_alt.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/dfu/dfu_tftp.c | 65 ----------------------------------------- include/dfu.h | 32 ++++++++++----------- 6 files changed, 103 insertions(+), 84 deletions(-) create mode 100644 drivers/dfu/dfu_alt.c delete mode 100644 drivers/dfu/dfu_tftp.c diff --git a/common/update.c b/common/update.c index 36b6b7523d..39946776d7 100644 --- a/common/update.c +++ b/common/update.c @@ -324,8 +324,9 @@ got_update_file: } } else if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) { - ret = dfu_tftp_write(fit_image_name, update_addr, - update_size, interface, devstring); + ret = dfu_write_by_name(fit_image_name, update_addr, + update_size, interface, + devstring); if (ret) return ret; } diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 0eec00ba73..10196f390f 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -14,8 +14,13 @@ config DFU_OVER_TFTP depends on NET if DFU +config DFU_WRITE_ALT + bool + default n + config DFU_TFTP bool "DFU via TFTP" + select DFU_WRITE_ALT select DFU_OVER_TFTP help This option allows performing update of DFU-managed medium with data diff --git a/drivers/dfu/Makefile b/drivers/dfu/Makefile index 0d7925c083..dfbf64da66 100644 --- a/drivers/dfu/Makefile +++ b/drivers/dfu/Makefile @@ -9,5 +9,5 @@ obj-$(CONFIG_$(SPL_)DFU_MTD) += dfu_mtd.o obj-$(CONFIG_$(SPL_)DFU_NAND) += dfu_nand.o obj-$(CONFIG_$(SPL_)DFU_RAM) += dfu_ram.o obj-$(CONFIG_$(SPL_)DFU_SF) += dfu_sf.o -obj-$(CONFIG_$(SPL_)DFU_TFTP) += dfu_tftp.o +obj-$(CONFIG_$(SPL_)DFU_WRITE_ALT) += dfu_alt.o obj-$(CONFIG_$(SPL_)DFU_VIRT) += dfu_virt.o diff --git a/drivers/dfu/dfu_alt.c b/drivers/dfu/dfu_alt.c new file mode 100644 index 0000000000..8870967f4a --- /dev/null +++ b/drivers/dfu/dfu_alt.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2015 + * Lukasz Majewski + */ + +#include +#include +#include +#include +#include + +/** + * dfu_write_by_name() - write data to DFU medium + * @dfu_entity_name: Name of DFU entity to write + * @addr: Address of data buffer to write + * @len: Number of bytes + * @interface: Destination DFU medium (e.g. "mmc") + * @devstring: Instance number of destination DFU medium (e.g. "1") + * + * This function is storing data received on DFU supported medium which + * is specified by @dfu_entity_name. + * + * Return: 0 - on success, error code - otherwise + */ +int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, + unsigned int len, char *interface, char *devstring) +{ + char *s, *sb; + int alt_setting_num, ret; + struct dfu_entity *dfu; + + debug("%s: name: %s addr: 0x%x len: %d device: %s:%s\n", __func__, + dfu_entity_name, addr, len, interface, devstring); + + ret = dfu_init_env_entities(interface, devstring); + if (ret) + goto done; + + /* + * We need to copy name pointed by *dfu_entity_name since this text + * is the integral part of the FDT image. + * Any implicit modification (i.e. done by strsep()) will corrupt + * the FDT image and prevent other images to be stored. + */ + s = strdup(dfu_entity_name); + sb = s; + if (!s) { + ret = -ENOMEM; + goto done; + } + + strsep(&s, "@"); + debug("%s: image name: %s strlen: %zd\n", __func__, sb, strlen(sb)); + + alt_setting_num = dfu_get_alt(sb); + free(sb); + if (alt_setting_num < 0) { + pr_err("Alt setting [%d] to write not found!", + alt_setting_num); + ret = -ENODEV; + goto done; + } + + dfu = dfu_get_entity(alt_setting_num); + if (!dfu) { + pr_err("DFU entity for alt: %d not found!", alt_setting_num); + ret = -ENODEV; + goto done; + } + + ret = dfu_write_from_mem_addr(dfu, (void *)(uintptr_t)addr, len); + +done: + dfu_free_entities(); + + return ret; +} diff --git a/drivers/dfu/dfu_tftp.c b/drivers/dfu/dfu_tftp.c deleted file mode 100644 index ffae4bb54f..0000000000 --- a/drivers/dfu/dfu_tftp.c +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2015 - * Lukasz Majewski - */ - -#include -#include -#include -#include -#include - -int dfu_tftp_write(char *dfu_entity_name, unsigned int addr, unsigned int len, - char *interface, char *devstring) -{ - char *s, *sb; - int alt_setting_num, ret; - struct dfu_entity *dfu; - - debug("%s: name: %s addr: 0x%x len: %d device: %s:%s\n", __func__, - dfu_entity_name, addr, len, interface, devstring); - - ret = dfu_init_env_entities(interface, devstring); - if (ret) - goto done; - - /* - * We need to copy name pointed by *dfu_entity_name since this text - * is the integral part of the FDT image. - * Any implicit modification (i.e. done by strsep()) will corrupt - * the FDT image and prevent other images to be stored. - */ - s = strdup(dfu_entity_name); - sb = s; - if (!s) { - ret = -ENOMEM; - goto done; - } - - strsep(&s, "@"); - debug("%s: image name: %s strlen: %zd\n", __func__, sb, strlen(sb)); - - alt_setting_num = dfu_get_alt(sb); - free(sb); - if (alt_setting_num < 0) { - pr_err("Alt setting [%d] to write not found!", - alt_setting_num); - ret = -ENODEV; - goto done; - } - - dfu = dfu_get_entity(alt_setting_num); - if (!dfu) { - pr_err("DFU entity for alt: %d not found!", alt_setting_num); - ret = -ENODEV; - goto done; - } - - ret = dfu_write_from_mem_addr(dfu, (void *)(uintptr_t)addr, len); - -done: - dfu_free_entities(); - - return ret; -} diff --git a/include/dfu.h b/include/dfu.h index 84abdc79ac..a4cd86c0a6 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -494,27 +494,27 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, #endif /** - * dfu_tftp_write() - write TFTP data to DFU medium + * dfu_write_by_name() - write data to DFU medium + * @dfu_entity_name: Name of DFU entity to write + * @addr: Address of data buffer to write + * @len: Number of bytes + * @interface: Destination DFU medium (e.g. "mmc") + * @devstring: Instance number of destination DFU medium (e.g. "1") * - * This function is storing data received via TFTP on DFU supported medium. + * This function is storing data received on DFU supported medium which + * is specified by @dfu_entity_name. * - * @dfu_entity_name: name of DFU entity to write - * @addr: address of data buffer to write - * @len: number of bytes - * @interface: destination DFU medium (e.g. "mmc") - * @devstring: instance number of destination DFU medium (e.g. "1") - * - * Return: 0 on success, otherwise error code + * Return: 0 - on success, error code - otherwise */ -#if CONFIG_IS_ENABLED(DFU_TFTP) -int dfu_tftp_write(char *dfu_entity_name, unsigned int addr, unsigned int len, - char *interface, char *devstring); +#if CONFIG_IS_ENABLED(DFU_WRITE_ALT) +int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, + unsigned int len, char *interface, char *devstring); #else -static inline int dfu_tftp_write(char *dfu_entity_name, unsigned int addr, - unsigned int len, char *interface, - char *devstring) +static inline int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, + unsigned int len, char *interface, + char *devstring) { - puts("TFTP write support for DFU not available!\n"); + puts("write support for DFU not available!\n"); return -ENOSYS; } #endif -- cgit v1.2.1 From 1c2d1293f608a367488b5dea7250dda8bb8f1d02 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:42 +0900 Subject: dfu: modify an argument type for an address The range of an addressable pointer can go beyond 'integer'. So change the argument type to a void pointer. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt Reviewed-by: Tom Rini --- common/update.c | 3 ++- drivers/dfu/dfu_alt.c | 6 +++--- include/dfu.h | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/common/update.c b/common/update.c index 39946776d7..8dd6ee8b7d 100644 --- a/common/update.c +++ b/common/update.c @@ -324,7 +324,8 @@ got_update_file: } } else if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) { - ret = dfu_write_by_name(fit_image_name, update_addr, + ret = dfu_write_by_name(fit_image_name, + (void *)update_addr, update_size, interface, devstring); if (ret) diff --git a/drivers/dfu/dfu_alt.c b/drivers/dfu/dfu_alt.c index 8870967f4a..53e8489b0e 100644 --- a/drivers/dfu/dfu_alt.c +++ b/drivers/dfu/dfu_alt.c @@ -23,14 +23,14 @@ * * Return: 0 - on success, error code - otherwise */ -int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, +int dfu_write_by_name(char *dfu_entity_name, void *addr, unsigned int len, char *interface, char *devstring) { char *s, *sb; int alt_setting_num, ret; struct dfu_entity *dfu; - debug("%s: name: %s addr: 0x%x len: %d device: %s:%s\n", __func__, + debug("%s: name: %s addr: 0x%p len: %d device: %s:%s\n", __func__, dfu_entity_name, addr, len, interface, devstring); ret = dfu_init_env_entities(interface, devstring); @@ -69,7 +69,7 @@ int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, goto done; } - ret = dfu_write_from_mem_addr(dfu, (void *)(uintptr_t)addr, len); + ret = dfu_write_from_mem_addr(dfu, (void *)addr, len); done: dfu_free_entities(); diff --git a/include/dfu.h b/include/dfu.h index a4cd86c0a6..d3d7e07b60 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -507,10 +507,10 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, * Return: 0 - on success, error code - otherwise */ #if CONFIG_IS_ENABLED(DFU_WRITE_ALT) -int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, +int dfu_write_by_name(char *dfu_entity_name, void *addr, unsigned int len, char *interface, char *devstring); #else -static inline int dfu_write_by_name(char *dfu_entity_name, unsigned int addr, +static inline int dfu_write_by_name(char *dfu_entity_name, void *addr, unsigned int len, char *interface, char *devstring) { -- cgit v1.2.1 From 3149e524fc1e76ec1420cd17588c724d4232a904 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:43 +0900 Subject: common: update: add a generic interface for FIT image The main purpose of this patch is to separate a generic interface for updating firmware using DFU drivers from "auto-update" via tftp. This function will also be used in implementing UEFI capsule update in a later commit. Signed-off-by: AKASHI Takahiro Reviewed-by: Tom Rini --- common/Kconfig | 15 +++++++++++ common/Makefile | 3 +-- common/update.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/dfu/Kconfig | 1 + include/image.h | 12 +++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 318d372a48..2bce8c9ba1 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -599,9 +599,15 @@ endmenu menu "Update support" +config UPDATE_COMMON + bool + default n + select DFU_WRITE_ALT + config UPDATE_TFTP bool "Auto-update using fitImage via TFTP" depends on FIT + select UPDATE_COMMON help This option allows performing update of NOR with data in fitImage sent via TFTP boot. @@ -616,6 +622,15 @@ config UPDATE_TFTP_MSEC_MAX default 100 depends on UPDATE_TFTP +config UPDATE_FIT + bool "Firmware update using fitImage" + depends on FIT + depends on DFU + select UPDATE_COMMON + help + This option allows performing update of DFU-capable storage with + data in fitImage. + config ANDROID_AB bool "Android A/B updates" default n diff --git a/common/Makefile b/common/Makefile index 2e7a090588..bcf352d016 100644 --- a/common/Makefile +++ b/common/Makefile @@ -53,8 +53,7 @@ obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o obj-$(CONFIG_LYNXKDI) += lynxkdi.o obj-$(CONFIG_MENU) += menu.o -obj-$(CONFIG_UPDATE_TFTP) += update.o -obj-$(CONFIG_DFU_TFTP) += update.o +obj-$(CONFIG_UPDATE_COMMON) += update.o obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o obj-$(CONFIG_CMDLINE) += cli_readline.o cli_simple.o diff --git a/common/update.c b/common/update.c index 8dd6ee8b7d..808be0880d 100644 --- a/common/update.c +++ b/common/update.c @@ -29,6 +29,7 @@ #include #include +#ifdef CONFIG_DFU_TFTP /* env variable holding the location of the update file */ #define UPDATE_FILE_ENV "updatefile" @@ -98,6 +99,7 @@ static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr) return rv; } +#endif /* CONFIG_DFU_TFTP */ #ifdef CONFIG_MTD_NOR_FLASH static int update_flash_protect(int prot, ulong addr_first, ulong addr_last) @@ -231,6 +233,7 @@ static int update_fit_getparams(const void *fit, int noffset, ulong *addr, return 0; } +#ifdef CONFIG_DFU_TFTP int update_tftp(ulong addr, char *interface, char *devstring) { char *filename, *env_addr, *fit_image_name; @@ -337,3 +340,71 @@ next_node: return ret; } +#endif /* CONFIG_DFU_UPDATE */ + +#ifdef CONFIG_UPDATE_FIT +/** + * fit_update - update storage with FIT image + * @fit: Pointer to FIT image + * + * Update firmware on storage using FIT image as input. + * The storage area to be update will be identified by the name + * in FIT and matching it to "dfu_alt_info" variable. + * + * Return: 0 - on success, non-zero - otherwise + */ +int fit_update(const void *fit) +{ + char *fit_image_name; + ulong update_addr, update_fladdr, update_size; + int images_noffset, ndepth, noffset; + int ret = 0; + + if (!fit) + return -EINVAL; + + if (!fit_check_format((void *)fit)) { + printf("Bad FIT format of the update file, aborting auto-update\n"); + return -EINVAL; + } + + /* process updates */ + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + + ndepth = 0; + noffset = fdt_next_node(fit, images_noffset, &ndepth); + while (noffset >= 0 && ndepth > 0) { + if (ndepth != 1) + goto next_node; + + fit_image_name = (char *)fit_get_name(fit, noffset, NULL); + printf("Processing update '%s' :", fit_image_name); + + if (!fit_image_verify(fit, noffset)) { + printf("Error: invalid update hash, aborting\n"); + ret = 1; + goto next_node; + } + + printf("\n"); + if (update_fit_getparams(fit, noffset, &update_addr, + &update_fladdr, &update_size)) { + printf("Error: can't get update parameters, aborting\n"); + ret = 1; + goto next_node; + } + + if (fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE)) { + ret = dfu_write_by_name(fit_image_name, + (void *)update_addr, + update_size, NULL, NULL); + if (ret) + return ret; + } +next_node: + noffset = fdt_next_node(fit, noffset, &ndepth); + } + + return ret; +} +#endif /* CONFIG_UPDATE_FIT */ diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 10196f390f..b7427fc4f0 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -22,6 +22,7 @@ config DFU_TFTP bool "DFU via TFTP" select DFU_WRITE_ALT select DFU_OVER_TFTP + select UPDATE_COMMON help This option allows performing update of DFU-managed medium with data sent via TFTP boot. diff --git a/include/image.h b/include/image.h index 4094ee588a..00bc03bebe 100644 --- a/include/image.h +++ b/include/image.h @@ -1602,4 +1602,16 @@ struct fit_loadable_tbl { .handler = _handler, \ } +/** + * fit_update - update storage with FIT image + * @fit: Pointer to FIT image + * + * Update firmware on storage using FIT image as input. + * The storage area to be update will be identified by the name + * in FIT and matching it to "dfu_alt_info" variable. + * + * Return: 0 on success, non-zero otherwise + */ +int fit_update(const void *fit); + #endif /* __IMAGE_H__ */ -- cgit v1.2.1 From 6beaa47d4fe640392f1b7551dcf976fbb676d554 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:44 +0900 Subject: dfu: export dfu_list This variable will be utilized to enumerate all dfu entities for UEFI capsule firmware update in a later commit. Signed-off-by: AKASHI Takahiro Reviewed-by: Tom Rini --- drivers/dfu/dfu.c | 2 +- include/dfu.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index a298c2c439..501a60b344 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -18,7 +18,7 @@ #include #include -static LIST_HEAD(dfu_list); +LIST_HEAD(dfu_list); static int dfu_alt_num; static int alt_num_cnt; static struct hash_algo *dfu_hash_algo; diff --git a/include/dfu.h b/include/dfu.h index d3d7e07b60..eaf4bfc0d5 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -158,6 +158,9 @@ struct dfu_entity { unsigned int inited:1; }; +struct list_head; +extern struct list_head dfu_list; + #ifdef CONFIG_SET_DFU_ALT_INFO /** * set_dfu_alt_info() - set dfu_alt_info environment variable -- cgit v1.2.1 From f234566ef03db4be17fc36bb1a104a70512555f1 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:52 +0900 Subject: dfu: add dfu_write_by_alt() This function is a variant of dfu_write_by_name() and takes a DFU alt setting number for dfu configuration. It will be utilised to implement UEFI capsule management protocol for raw image in a later commit. Signed-off-by: AKASHI Takahiro Reviewed-by: Tom Rini --- drivers/dfu/dfu_alt.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ include/dfu.h | 26 +++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/dfu/dfu_alt.c b/drivers/dfu/dfu_alt.c index 53e8489b0e..ece3d2236f 100644 --- a/drivers/dfu/dfu_alt.c +++ b/drivers/dfu/dfu_alt.c @@ -76,3 +76,50 @@ done: return ret; } + +/** + * dfu_write_by_alt() - write data to DFU medium + * @dfu_alt_num: DFU alt setting number + * @addr: Address of data buffer to write + * @len: Number of bytes + * @interface: Destination DFU medium (e.g. "mmc") + * @devstring: Instance number of destination DFU medium (e.g. "1") + * + * This function is storing data received on DFU supported medium which + * is specified by @dfu_alt_name. + * + * Return: 0 - on success, error code - otherwise + */ +int dfu_write_by_alt(int dfu_alt_num, void *addr, unsigned int len, + char *interface, char *devstring) +{ + struct dfu_entity *dfu; + int ret; + + debug("%s: alt: %d addr: 0x%p len: %d device: %s:%s\n", __func__, + dfu_alt_num, addr, len, interface, devstring); + + ret = dfu_init_env_entities(interface, devstring); + if (ret) + goto done; + + if (dfu_alt_num < 0) { + pr_err("Invalid alt number: %d", dfu_alt_num); + ret = -ENODEV; + goto done; + } + + dfu = dfu_get_entity(dfu_alt_num); + if (!dfu) { + pr_err("DFU entity for alt: %d not found!", dfu_alt_num); + ret = -ENODEV; + goto done; + } + + ret = dfu_write_from_mem_addr(dfu, (void *)(uintptr_t)addr, len); + +done: + dfu_free_entities(); + + return ret; +} diff --git a/include/dfu.h b/include/dfu.h index eaf4bfc0d5..a767adee41 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -496,6 +496,7 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, } #endif +#if CONFIG_IS_ENABLED(DFU_WRITE_ALT) /** * dfu_write_by_name() - write data to DFU medium * @dfu_entity_name: Name of DFU entity to write @@ -509,9 +510,24 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, * * Return: 0 - on success, error code - otherwise */ -#if CONFIG_IS_ENABLED(DFU_WRITE_ALT) int dfu_write_by_name(char *dfu_entity_name, void *addr, unsigned int len, char *interface, char *devstring); + +/** + * dfu_write_by_alt() - write data to DFU medium + * @dfu_alt_num: DFU alt setting number + * @addr: Address of data buffer to write + * @len: Number of bytes + * @interface: Destination DFU medium (e.g. "mmc") + * @devstring: Instance number of destination DFU medium (e.g. "1") + * + * This function is storing data received on DFU supported medium which + * is specified by @dfu_alt_name. + * + * Return: 0 - on success, error code - otherwise + */ +int dfu_write_by_alt(int dfu_alt_num, void *addr, unsigned int len, + char *interface, char *devstring); #else static inline int dfu_write_by_name(char *dfu_entity_name, void *addr, unsigned int len, char *interface, @@ -520,6 +536,14 @@ static inline int dfu_write_by_name(char *dfu_entity_name, void *addr, puts("write support for DFU not available!\n"); return -ENOSYS; } + +static inline int dfu_write_by_alt(int dfu_alt_num, void *addr, + unsigned int len, char *interface, + char *devstring) +{ + puts("write support for DFU not available!\n"); + return -ENOSYS; +} #endif int dfu_add(struct usb_configuration *c); -- cgit v1.2.1 From c57c9439548a58a0c1f0eb2ec7b5ab5d7b7fd801 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:45 +0900 Subject: efi_loader: add option to initialise EFI subsystem early If this option, CONFIG_EFI_SETUP_EARLY, is enabled, the initialisation of UEFI subsystem will be done as part of U-Boot initialisation. Please note that this option won't be enabled explicitly by users, instead, should be enabled implicitly by other configuration options. Specifically, this feature will be utilised in implementing capsule-on-disk feature. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- common/board_r.c | 6 ++++++ lib/efi_loader/Kconfig | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/common/board_r.c b/common/board_r.c index b9217b2e27..2212d981e5 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -73,6 +73,9 @@ #if defined(CONFIG_GPIO_HOG) #include #endif +#ifdef CONFIG_EFI_SETUP_EARLY +#include +#endif DECLARE_GLOBAL_DATA_PTR; @@ -889,6 +892,9 @@ static init_fnc_t init_sequence_r[] = { #endif #if defined(CONFIG_PRAM) initr_mem, +#endif +#ifdef CONFIG_EFI_SETUP_EARLY + (init_fnc_t)efi_init_obj_list, #endif run_main_loop, }; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ab42f3ba75..075481428c 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,6 +27,10 @@ config EFI_LOADER if EFI_LOADER +config EFI_SETUP_EARLY + bool + default n + choice prompt "Store for non-volatile UEFI variables" default EFI_VARIABLE_FILE_STORE -- cgit v1.2.1 From 077153e085b48e7683552667ab2247c991c1e1ff Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 29 Oct 2020 13:47:46 +0900 Subject: efi_loader: add efi_create_indexed_name() This function will be used from several places in UEFI subsystem to generate some specific form of utf-16 variable name. For example, L"Capsule0001" Signed-off-by: AKASHI Takahiro Move function to separate module. Use char * as argument instead of u16 *. Reviewed-by: Heinrich Schuchardt Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 3 +++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_string.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 lib/efi_loader/efi_string.c diff --git a/include/efi_loader.h b/include/efi_loader.h index 7eea5566fd..f550ced568 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -804,6 +804,9 @@ bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, /* runtime implementation of memcpy() */ void efi_memcpy_runtime(void *dest, const void *src, size_t n); +/* commonly used helper function */ +u16 *efi_create_indexed_name(u16 *buffer, const char *name, unsigned int index); + #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 9bad1d159b..8892fb01e1 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -34,6 +34,7 @@ obj-y += efi_memory.o obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_setup.o +obj-y += efi_string.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += efi_unicode_collation.o obj-y += efi_var_common.o obj-y += efi_var_mem.o diff --git a/lib/efi_loader/efi_string.c b/lib/efi_loader/efi_string.c new file mode 100644 index 0000000000..3de721f06c --- /dev/null +++ b/lib/efi_loader/efi_string.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * String functions + * + * Copyright (c) 2020 AKASHI Takahiro, Linaro Limited + */ + +#include +#include + +/** + * efi_create_indexed_name - create a string name with an index + * @buffer: Buffer + * @name: Name string + * @index: Index + * + * Create a utf-16 string with @name, appending @index. + * For example, L"Capsule0001" + * + * The caller must ensure that the buffer has enough space for the resulting + * string including the trailing L'\0'. + * + * 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 *p = buffer; + char index_buf[5]; + + utf8_utf16_strcpy(&p, name); + sprintf(index_buf, "%04X", index); + utf8_utf16_strcpy(&p, index_buf); + + return p; +} -- cgit v1.2.1 From af11423eb06d68784647b879cac57d7b6619d095 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 30 Oct 2020 12:23:59 +0100 Subject: test: unit test for efi_create_indexed_name() Provide a unit test for function efi_create_indexed_name(). Signed-off-by: Heinrich Schuchardt --- test/unicode_ut.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unicode_ut.c b/test/unicode_ut.c index 26d96336f3..33fc8b0ee1 100644 --- a/test/unicode_ut.c +++ b/test/unicode_ut.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -594,6 +595,24 @@ static int unicode_test_u16_strsize(struct unit_test_state *uts) } UNICODE_TEST(unicode_test_u16_strsize); +#ifdef CONFIG_EFI_LOADER +static int unicode_test_efi_create_indexed_name(struct unit_test_state *uts) +{ + u16 buf[16]; + u16 const expected[] = L"Capsule0AF9"; + u16 *pos; + + memset(buf, 0xeb, sizeof(buf)); + pos = efi_create_indexed_name(buf, "Capsule", 0x0af9); + + ut_asserteq_mem(expected, buf, sizeof(expected)); + ut_asserteq(pos - buf, u16_strnlen(buf, SIZE_MAX)); + + return 0; +} +UNICODE_TEST(unicode_test_efi_create_indexed_name); +#endif + int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test); -- cgit v1.2.1