diff options
author | Tom Rini <trini@konsulko.com> | 2020-11-01 10:56:37 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-11-01 10:56:37 -0500 |
commit | 41cab8edbcf38bce5cddf54957618dd4205d008f (patch) | |
tree | efe29a6e552133360d8303fc44b025ecf2cc1b95 | |
parent | 2c31d7e746766f47a007f39c030706e493a9cc77 (diff) | |
parent | af11423eb06d68784647b879cac57d7b6619d095 (diff) | |
download | u-boot-41cab8edbcf38bce5cddf54957618dd4205d008f.tar.gz |
Merge tag 'efi-2020-01-rc2-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/01Nov2020
Pull request for UEFI sub-system for efi-2021-01-rc2 (2)
The series contains the following enhancements
* preparatory patches for UEFI capsule updates
* initialization of the emulated RTC using an environment variable
and a bug fix
* If DisconnectController() is called for a child controller that is the
only child of the driver, the driver must be disconnected.
-rw-r--r-- | common/Kconfig | 15 | ||||
-rw-r--r-- | common/Makefile | 3 | ||||
-rw-r--r-- | common/board_r.c | 6 | ||||
-rw-r--r-- | common/update.c | 77 | ||||
-rw-r--r-- | drivers/dfu/Kconfig | 6 | ||||
-rw-r--r-- | drivers/dfu/Makefile | 2 | ||||
-rw-r--r-- | drivers/dfu/dfu.c | 2 | ||||
-rw-r--r-- | drivers/dfu/dfu_alt.c | 125 | ||||
-rw-r--r-- | drivers/dfu/dfu_tftp.c | 65 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 13 | ||||
-rw-r--r-- | drivers/rtc/emul_rtc.c | 28 | ||||
-rw-r--r-- | include/charset.h | 2 | ||||
-rw-r--r-- | include/dfu.h | 57 | ||||
-rw-r--r-- | include/efi_loader.h | 3 | ||||
-rw-r--r-- | include/image.h | 12 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 4 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 19 | ||||
-rw-r--r-- | lib/efi_loader/efi_string.c | 36 | ||||
-rw-r--r-- | test/unicode_ut.c | 19 |
20 files changed, 389 insertions, 106 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/board_r.c b/common/board_r.c index 0829622d0d..29dd7d26d9 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -73,6 +73,9 @@ #if defined(CONFIG_GPIO_HOG) #include <asm/gpio.h> #endif +#ifdef CONFIG_EFI_SETUP_EARLY +#include <efi_loader.h> +#endif DECLARE_GLOBAL_DATA_PTR; @@ -889,6 +892,9 @@ static init_fnc_t init_sequence_r[] = { #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/common/update.c b/common/update.c index 36b6b7523d..808be0880d 100644 --- a/common/update.c +++ b/common/update.c @@ -29,6 +29,7 @@ #include <errno.h> #include <mtd/cfi_flash.h> +#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; @@ -324,8 +327,10 @@ 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, + (void *)update_addr, + update_size, interface, + devstring); if (ret) return ret; } @@ -335,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 0eec00ba73..b7427fc4f0 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -14,9 +14,15 @@ 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 + select UPDATE_COMMON help This option allows performing update of DFU-managed medium with data sent via TFTP boot. 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.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 <linux/list.h> #include <linux/compiler.h> -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/drivers/dfu/dfu_alt.c b/drivers/dfu/dfu_alt.c new file mode 100644 index 0000000000..ece3d2236f --- /dev/null +++ b/drivers/dfu/dfu_alt.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2015 + * Lukasz Majewski <l.majewski@majess.pl> + */ + +#include <common.h> +#include <log.h> +#include <malloc.h> +#include <errno.h> +#include <dfu.h> + +/** + * 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, 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%p 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 *)addr, len); + +done: + dfu_free_entities(); + + 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/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 <l.majewski@majess.pl> - */ - -#include <common.h> -#include <log.h> -#include <malloc.h> -#include <errno.h> -#include <dfu.h> - -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/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 c98c24bbb3..7e522103fd 100644 --- a/drivers/rtc/emul_rtc.c +++ b/drivers/rtc/emul_rtc.c @@ -8,6 +8,7 @@ #include <common.h> #include <div64.h> #include <dm.h> +#include <env.h> #include <generated/timestamp_autogenerated.h> #include <rtc.h> @@ -30,12 +31,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 +58,26 @@ 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); + 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; +} + static const struct rtc_ops emul_rtc_ops = { .get = emul_rtc_get, .set = emul_rtc_set, @@ -72,6 +87,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), }; 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. diff --git a/include/dfu.h b/include/dfu.h index 84abdc79ac..a767adee41 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 @@ -493,28 +496,52 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, } #endif +#if CONFIG_IS_ENABLED(DFU_WRITE_ALT) /** - * 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 on DFU supported medium which + * is specified by @dfu_entity_name. * - * This function is storing data received via TFTP on DFU supported medium. + * Return: 0 - on success, error code - otherwise + */ +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") * - * @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_alt_name. * - * 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); +int dfu_write_by_alt(int dfu_alt_num, void *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, void *addr, + unsigned int len, char *interface, + char *devstring) +{ + 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("TFTP write support for DFU not available!\n"); + puts("write support for DFU not available!\n"); return -ENOSYS; } #endif 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/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__ */ 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 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_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)); 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 <common.h> +#include <charset.h> + +/** + * 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; +} 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 <common.h> #include <charset.h> #include <command.h> +#include <efi_loader.h> #include <errno.h> #include <log.h> #include <malloc.h> @@ -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); |