From: Jeffrey Hugo <jhugo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
To: linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org
Cc: ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
mark.rutland-5wv7dgnIgG8@public.gmane.org,
leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
timur-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
Jeffrey Hugo <jhugo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Subject: [PATCH V3 2/4] efi/libstub: Introduce ExitBootServices helper
Date: Wed, 27 Jul 2016 11:42:23 -0600 [thread overview]
Message-ID: <1469641345-17739-3-git-send-email-jhugo@codeaurora.org> (raw)
In-Reply-To: <1469641345-17739-1-git-send-email-jhugo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
The spec allows ExitBootServices to fail with EFI_INVALID_PARAMETER if a
race condition has occurred where the EFI has updated the memory map after
the stub grabbed a reference to the map. The spec defines a retry
proceedure with specific requirements to handle this scenario.
No current stub implementation correctly follows the spec in this regard,
so add a helper to the stub library that correctly adhears to the spec and
abstracts the complexity from stubs.
Signed-off-by: Jeffrey Hugo <jhugo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
---
drivers/firmware/efi/libstub/efi-stub-helper.c | 93 ++++++++++++++++++++++++++
include/linux/efi.h | 19 ++++++
2 files changed, 112 insertions(+)
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 3071269..d5be0b5 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -720,3 +720,96 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
*cmd_line_len = options_bytes;
return (char *)cmdline_addr;
}
+
+/*
+ * Handle calling ExitBootServices according to the requirements set out by the
+ * spec. Obtains the current memory map, and returns that info after calling
+ * ExitBootServices. Client has the option to specify a function to process the
+ * memory map data. A client specific structure may be passed to the function
+ * via priv. The client function may be called multiple times.
+ */
+efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table,
+ void *handle,
+ efi_memory_desc_t **memory_map,
+ unsigned long *map_size,
+ unsigned long *desc_size,
+ u32 *desc_ver,
+ unsigned long *mmap_key,
+ void *priv,
+ efi_status_t (*priv_func)(
+ efi_system_table_t *sys_table,
+ void *handle,
+ efi_memory_desc_t *memory_map,
+ unsigned long *map_size,
+ unsigned long *desc_size,
+ u32 *desc_ver,
+ unsigned long *mmap_key,
+ unsigned long buff_size,
+ void *priv))
+{
+ efi_status_t status;
+ unsigned long buff_size;
+
+ status = efi_get_memory_map(sys_table, memory_map, map_size,
+ desc_size, desc_ver, mmap_key, &buff_size);
+
+ if (status != EFI_SUCCESS)
+ goto fail;
+
+ if (priv_func) {
+ status = priv_func(sys_table, handle, *memory_map, map_size,
+ desc_size, desc_ver, mmap_key, buff_size,
+ priv);
+ if (status != EFI_SUCCESS)
+ goto free_map;
+ }
+
+ status = sys_table->boottime->exit_boot_services(handle, *mmap_key);
+
+ if (status == EFI_INVALID_PARAMETER) {
+ /*
+ * The memory map changed between efi_get_memory_map() and
+ * exit_boot_services(). Per the spec we need to get the
+ * updated map, and try again. The spec implies one retry
+ * should be sufficent, which is confirmed against the EDK2
+ * implementation. Per the spec, we can only invoke
+ * get_memory_map() and exit_boot_services() - we cannot alloc
+ * so efi_get_memory_map() cannot be used, and we must reuse
+ * the buffer. For all practical purposes, the headroom in the
+ * buffer should account for any changes in the map so the call
+ * to get_memory_map() is expected to succeed here.
+ */
+ *map_size = buff_size;
+ status = sys_table->boottime->get_memory_map(map_size,
+ *memory_map,
+ mmap_key,
+ desc_size,
+ desc_ver);
+ if (status != EFI_SUCCESS)
+ /* exit_boot_services() was called, thus cannot free*/
+ goto fail;
+
+ if (priv_func) {
+ status = priv_func(sys_table, handle, *memory_map,
+ map_size, desc_size, desc_ver,
+ mmap_key, buff_size, priv);
+ if (status != EFI_SUCCESS)
+ /* exit_boot_services() called, cannot free*/
+ goto fail;
+ }
+
+ status = sys_table->boottime->exit_boot_services(handle,
+ *mmap_key);
+ }
+
+ if (status != EFI_SUCCESS)
+ /* exit_boot_services() was called, thus cannot free*/
+ goto fail;
+
+ return EFI_SUCCESS;
+
+free_map:
+ sys_table->boottime->free_pool(*memory_map);
+fail:
+ return status;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index c47fc5f..96f7b74 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1466,4 +1466,23 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
unsigned long size);
bool efi_runtime_disabled(void);
+
+efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table,
+ void *handle,
+ efi_memory_desc_t **memory_map,
+ unsigned long *map_size,
+ unsigned long *desc_size,
+ u32 *desc_ver,
+ unsigned long *mmap_key,
+ void *priv,
+ efi_status_t (*priv_func)(
+ efi_system_table_t *sys_table,
+ void *handle,
+ efi_memory_desc_t *memory_map,
+ unsigned long *map_size,
+ unsigned long *desc_size,
+ u32 *desc_ver,
+ unsigned long *mmap_key,
+ unsigned long buff_size,
+ void *priv));
#endif /* _LINUX_EFI_H */
--
Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
next prev parent reply other threads:[~2016-07-27 17:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-27 17:42 [PATCH V3 0/4] Handle EFI_INVALID_PARAMETER from ExitBootServices Jeffrey Hugo
[not found] ` <1469641345-17739-1-git-send-email-jhugo-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2016-07-27 17:42 ` [PATCH V3 1/4] efi/libstub: Allocate headspace in efi_get_memory_map() Jeffrey Hugo
2016-07-27 17:42 ` Jeffrey Hugo [this message]
2016-07-27 17:42 ` [PATCH V3 3/4] efi/libstub: Use efi_exit_boot_services() in FDT Jeffrey Hugo
2016-07-27 17:42 ` [PATCH V3 4/4] x86/efi: Use efi_exit_boot_services() Jeffrey Hugo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1469641345-17739-3-git-send-email-jhugo@codeaurora.org \
--to=jhugo-sgv2jx0feol9jmxxk+q4oq@public.gmane.org \
--cc=ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
--cc=matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org \
--cc=timur-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).