From 1da0b6ab2a2183b1c9e4cf3623d3e796931c861f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 23 Sep 2021 11:06:16 +0200 Subject: doc: add system reset to API documentation Complete the Sphinx documentation in include/sysreset.h Add the include to the generated HTML documentation of the U-Boot API. Signed-off-by: Heinrich Schuchardt --- include/sysreset.h | 53 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/sysreset.h b/include/sysreset.h index 701e4f5c86e..9d4ed87ceaf 100644 --- a/include/sysreset.h +++ b/include/sysreset.h @@ -9,43 +9,55 @@ struct udevice; +/** + * enum sysreset_t - system reset types + */ enum sysreset_t { - SYSRESET_WARM, /* Reset CPU, keep GPIOs active */ - SYSRESET_COLD, /* Reset CPU and GPIOs */ - SYSRESET_POWER, /* Reset PMIC (remove and restore power) */ - SYSRESET_POWER_OFF, /* Turn off power */ - + /** @SYSRESET_WARM: reset CPU, keep GPIOs active */ + SYSRESET_WARM, + /** @SYSRESET_COLD: reset CPU and GPIOs */ + SYSRESET_COLD, + /** @SYSRESET_POWER: reset PMIC (remove and restore power) */ + SYSRESET_POWER, + /** @SYSRESET_POWER_OFF: turn off power */ + SYSRESET_POWER_OFF, + /** @SYSRESET_COUNT: number of available reset types */ SYSRESET_COUNT, }; +/** + * struct sysreset_ops - operations of system reset drivers + */ struct sysreset_ops { /** - * request() - request a sysreset of the given type + * @request: request a sysreset of the given type * * Note that this function may return before the reset takes effect. * + * @dev: Device to be used for system reset * @type: Reset type to request - * @return -EINPROGRESS if the reset has been started and - * will complete soon, -EPROTONOSUPPORT if not supported - * by this device, 0 if the reset has already happened - * (in which case this method will not actually return) + * Return: + * -EINPROGRESS if the reset has been started and + * will complete soon, -EPROTONOSUPPORT if not supported + * by this device, 0 if the reset has already happened + * (in which case this method will not actually return) */ int (*request)(struct udevice *dev, enum sysreset_t type); /** - * get_status() - get printable reset status information + * @get_status: get printable reset status information * * @dev: Device to check * @buf: Buffer to receive the textual reset information * @size: Size of the passed buffer - * @return 0 if OK, -ve on error + * Return: 0 if OK, -ve on error */ int (*get_status)(struct udevice *dev, char *buf, int size); /** - * get_last() - get information on the last reset + * @get_last: get information on the last reset * * @dev: Device to check - * @return last reset state (enum sysreset_t) or -ve error + * Return: last reset state (enum :enum:`sysreset_t`) or -ve error */ int (*get_last)(struct udevice *dev); }; @@ -55,8 +67,9 @@ struct sysreset_ops { /** * sysreset_request() - request a sysreset * + * @dev: Device to be used for system reset * @type: Reset type to request - * @return 0 if OK, -EPROTONOSUPPORT if not supported by this device + * Return: 0 if OK, -EPROTONOSUPPORT if not supported by this device */ int sysreset_request(struct udevice *dev, enum sysreset_t type); @@ -66,7 +79,7 @@ int sysreset_request(struct udevice *dev, enum sysreset_t type); * @dev: Device to check * @buf: Buffer to receive the textual reset information * @size: Size of the passed buffer - * @return 0 if OK, -ve on error + * Return: 0 if OK, -ve on error */ int sysreset_get_status(struct udevice *dev, char *buf, int size); @@ -74,7 +87,7 @@ int sysreset_get_status(struct udevice *dev, char *buf, int size); * sysreset_get_last() - get information on the last reset * * @dev: Device to check - * @return last reset state (enum sysreset_t) or -ve error + * Return: last reset state (enum sysreset_t) or -ve error */ int sysreset_get_last(struct udevice *dev); @@ -88,7 +101,7 @@ int sysreset_get_last(struct udevice *dev); * If this function fails to reset, it will display a message and halt * * @type: Reset type to request - * @return -EINPROGRESS if a reset is in progress, -ENOSYS if not available + * Return: -EINPROGRESS if a reset is in progress, -ENOSYS if not available */ int sysreset_walk(enum sysreset_t type); @@ -101,7 +114,7 @@ int sysreset_walk(enum sysreset_t type); * * If no device prives the information, this function returns -ENOENT * - * @return last reset state (enum sysreset_t) or -ve error + * Return: last reset state (enum sysreset_t) or -ve error */ int sysreset_get_last_walk(void); @@ -110,6 +123,8 @@ int sysreset_get_last_walk(void); * * This calls sysreset_walk(). If it returns, indicating that reset is not * supported, it prints a message and halts. + * + * @type: Reset type to request */ void sysreset_walk_halt(enum sysreset_t type); -- cgit v1.3.1 From ebdea88d57d5e67b8f6e6cf615300eedbc7200a9 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Mon, 11 Oct 2021 15:10:23 +0300 Subject: efi_loader: Fix loaded image alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are ignoring the alignment communicated via the PE/COFF header. Starting 5.10 the Linux kernel will loudly complain about it. For more details look at [1] (in linux kernel). So add a function that can allocate aligned EFI memory and use it for our relocated loaded image. [1] c32ac11da3f83 ("efi/libstub: arm64: Double check image alignment at entry") Signed-off-by: Ilias Apalodimas Tested-by: Vincent Stehlé Acked-by: Ard Biesheuvel Reviewed-by: Heinrich Schuchardt --- include/efi_loader.h | 2 ++ lib/efi_loader/efi_image_loader.c | 12 ++++----- lib/efi_loader/efi_memory.c | 52 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index c440962fe52..5cdc72345e5 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -675,6 +675,8 @@ struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid); #define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); +/* Allocate pages on the specified alignment */ +void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align); /* More specific EFI memory allocator, called by EFI payloads */ efi_status_t efi_allocate_pages(enum efi_allocate_type type, enum efi_memory_type memory_type, diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index e9572d4d5db..eb95580538c 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -898,9 +898,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, image_base = opt->ImageBase; efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); handle->image_type = opt->Subsystem; - virt_size = ALIGN(virt_size, opt->SectionAlignment); - efi_reloc = efi_alloc(virt_size, - loaded_image_info->image_code_type); + efi_reloc = efi_alloc_aligned_pages(virt_size, + loaded_image_info->image_code_type, + opt->SectionAlignment); if (!efi_reloc) { log_err("Out of memory\n"); ret = EFI_OUT_OF_RESOURCES; @@ -914,9 +914,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, image_base = opt->ImageBase; efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); handle->image_type = opt->Subsystem; - virt_size = ALIGN(virt_size, opt->SectionAlignment); - efi_reloc = efi_alloc(virt_size, - loaded_image_info->image_code_type); + efi_reloc = efi_alloc_aligned_pages(virt_size, + loaded_image_info->image_code_type, + opt->SectionAlignment); if (!efi_reloc) { log_err("Out of memory\n"); ret = EFI_OUT_OF_RESOURCES; diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index f4acbee4f9b..7f0b5072819 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -549,6 +549,58 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) return ret; } +/** + * efi_alloc_aligned_pages - allocate + * + * @len: len in bytes + * @memory_type: usage type of the allocated memory + * @align: alignment in bytes + * Return: aligned memory or NULL + */ +void *efi_alloc_aligned_pages(u64 len, int memory_type, size_t align) +{ + u64 req_pages = efi_size_in_pages(len); + u64 true_pages = req_pages + efi_size_in_pages(align) - 1; + u64 free_pages; + u64 aligned_mem; + efi_status_t r; + u64 mem; + + /* align must be zero or a power of two */ + if (align & (align - 1)) + return NULL; + + /* Check for overflow */ + if (true_pages < req_pages) + return NULL; + + if (align < EFI_PAGE_SIZE) { + r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, + req_pages, &mem); + return (r == EFI_SUCCESS) ? (void *)(uintptr_t)mem : NULL; + } + + r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, + true_pages, &mem); + if (r != EFI_SUCCESS) + return NULL; + + aligned_mem = ALIGN(mem, align); + /* Free pages before alignment */ + free_pages = efi_size_in_pages(aligned_mem - mem); + if (free_pages) + efi_free_pages(mem, free_pages); + + /* Free trailing pages */ + free_pages = true_pages - (req_pages + free_pages); + if (free_pages) { + mem = aligned_mem + req_pages * EFI_PAGE_SIZE; + efi_free_pages(mem, free_pages); + } + + return (void *)(uintptr_t)aligned_mem; +} + /** * efi_allocate_pool - allocate memory from pool * -- cgit v1.3.1 From 0421735dd8ffc82db22c3767e7aa38c65fc7298e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Oct 2021 01:31:02 +0200 Subject: efi_loader: efi_dp_from_lo() don't copy GUID Instead of copying a GUID and then using a pointer to the copy for calling guidcmp(), just pass the pointer to the orginal GUID. Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 2 +- include/efi_loader.h | 3 ++- lib/efi_loader/efi_device_path.c | 5 +++-- lib/efi_loader/efi_helper.c | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 67ab06aefc1..5235dbb7c1b 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1169,7 +1169,7 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) printf(" file_path: %ls\n", dp_str); efi_free_pool(dp_str); - initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, lf2_initrd_guid); + initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, &lf2_initrd_guid); if (initrd_path) { dp_str = efi_dp_str(initrd_path); printf(" initrd_path: %ls\n", dp_str); diff --git a/include/efi_loader.h b/include/efi_loader.h index 5cdc72345e5..6e806f9b0db 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -842,7 +842,8 @@ struct efi_load_option { }; struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, - efi_uintn_t *size, efi_guid_t guid); + efi_uintn_t *size, + const efi_guid_t *guid); struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, const struct efi_device_path *dp2); efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index a09090a32e4..a588712ef14 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -1218,7 +1218,8 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp, */ struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, - efi_uintn_t *size, efi_guid_t guid) + efi_uintn_t *size, + const efi_guid_t *guid) { struct efi_device_path *fp = lo->file_path; struct efi_device_path_vendor *vendor; @@ -1233,7 +1234,7 @@ efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, continue; vendor = (struct efi_device_path_vendor *)fp; - if (!guidcmp(&vendor->guid, &guid)) + if (!guidcmp(&vendor->guid, guid)) return efi_dp_dup(fp); } log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label); diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index d03a7364615..4c5b7cd2e12 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -83,7 +83,7 @@ struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid) if (ret != EFI_SUCCESS) goto out; - tmp = efi_dp_from_lo(&lo, &size, guid); + tmp = efi_dp_from_lo(&lo, &size, &guid); if (!tmp) goto out; -- cgit v1.3.1 From 05345425cab4202b356085afcac485614a9b52a9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Oct 2021 02:03:55 +0200 Subject: efi_loader: efi_dp_from_lo() unused parameter size Parameter size is never used in function efi_dp_from_lo(). Remove it. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- cmd/efidebug.c | 3 +-- include/efi_loader.h | 1 - lib/efi_loader/efi_device_path.c | 2 -- lib/efi_loader/efi_helper.c | 2 +- 4 files changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 70a46580129..33a5135ee19 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1144,7 +1144,6 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) struct efi_device_path *initrd_path = NULL; struct efi_load_option lo; efi_status_t ret; - efi_uintn_t initrd_dp_size; const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; ret = efi_deserialize_load_option(&lo, data, size); @@ -1166,7 +1165,7 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) printf(" file_path: %pD\n", lo.file_path); - initrd_path = efi_dp_from_lo(&lo, &initrd_dp_size, &lf2_initrd_guid); + initrd_path = efi_dp_from_lo(&lo, &lf2_initrd_guid); if (initrd_path) { printf(" initrd_path: %pD\n", initrd_path); efi_free_pool(initrd_path); diff --git a/include/efi_loader.h b/include/efi_loader.h index 6e806f9b0db..3e5ac380424 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -842,7 +842,6 @@ struct efi_load_option { }; struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, - efi_uintn_t *size, const efi_guid_t *guid); struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1, const struct efi_device_path *dp2); diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index a588712ef14..58fff81a2d2 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -1209,7 +1209,6 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp, * initrd location * * @lo: EFI_LOAD_OPTION containing a valid device path - * @size: size of the discovered device path * @guid: guid to search for * * Return: @@ -1218,7 +1217,6 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp, */ struct efi_device_path *efi_dp_from_lo(struct efi_load_option *lo, - efi_uintn_t *size, const efi_guid_t *guid) { struct efi_device_path *fp = lo->file_path; diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 4c5b7cd2e12..89833de2228 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -83,7 +83,7 @@ struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid) if (ret != EFI_SUCCESS) goto out; - tmp = efi_dp_from_lo(&lo, &size, &guid); + tmp = efi_dp_from_lo(&lo, &guid); if (!tmp) goto out; -- cgit v1.3.1 From 9ad37fe405a6fccba3555892ac9e64dbd37b0581 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Oct 2021 02:33:33 +0200 Subject: efi_loader: avoid multiple local copies of lf2_initrd_guid Create the GUID as a global variable. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- cmd/efidebug.c | 3 +-- include/efi_load_initrd.h | 1 + lib/efi_loader/efi_helper.c | 5 +++++ lib/efi_loader/efi_load_initrd.c | 3 +-- 4 files changed, 8 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 33a5135ee19..a977ca9c72f 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1144,7 +1144,6 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) struct efi_device_path *initrd_path = NULL; struct efi_load_option lo; efi_status_t ret; - const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; ret = efi_deserialize_load_option(&lo, data, size); if (ret != EFI_SUCCESS) { @@ -1165,7 +1164,7 @@ static void show_efi_boot_opt_data(u16 *varname16, void *data, size_t *size) printf(" file_path: %pD\n", lo.file_path); - initrd_path = efi_dp_from_lo(&lo, &lf2_initrd_guid); + initrd_path = efi_dp_from_lo(&lo, &efi_lf2_initrd_guid); if (initrd_path) { printf(" initrd_path: %pD\n", initrd_path); efi_free_pool(initrd_path); diff --git a/include/efi_load_initrd.h b/include/efi_load_initrd.h index 478ae807c68..be5d5a7acbe 100644 --- a/include/efi_load_initrd.h +++ b/include/efi_load_initrd.h @@ -16,6 +16,7 @@ #define EFI_INITRD_MEDIA_GUID \ EFI_GUID(0x5568e427, 0x68fc, 0x4f3d, \ 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68) +extern const efi_guid_t efi_lf2_initrd_guid; struct efi_initrd_dp { struct efi_device_path_vendor vendor; diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 89833de2228..485384b7ee1 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -13,6 +13,11 @@ #include #include +#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD) +/* GUID used by Linux to identify the LoadFile2 protocol with the initrd */ +const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; +#endif + /** * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by * the value of BootCurrent diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index e2a80630230..c5e6652e664 100644 --- a/lib/efi_loader/efi_load_initrd.c +++ b/lib/efi_loader/efi_load_initrd.c @@ -52,7 +52,6 @@ static efi_handle_t efi_initrd_handle; */ static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp) { - const efi_guid_t lf2_initrd_guid = EFI_INITRD_MEDIA_GUID; struct efi_device_path *dp = NULL; /* @@ -65,7 +64,7 @@ static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp) * We can then use this specific return value and not install the * protocol, while allowing the boot to continue */ - dp = efi_get_dp_from_boot(lf2_initrd_guid); + dp = efi_get_dp_from_boot(efi_lf2_initrd_guid); if (!dp) return EFI_INVALID_PARAMETER; -- cgit v1.3.1