From b5349f742a7684aabd3fb8f0e20c67ba033deec7 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:14 +0200 Subject: efi_loader: refactor efi_open_protocol efi_open_protocol was implemented to call a protocol specific open function to retrieve the protocol interface. The UEFI specification does not know of such a function. It is not possible to implement InstallProtocolInterface with the current design. With the patch the protocol interface itself is stored in the list of installed protocols of an efi_object instead of an open function. Signed-off-by: Heinrich Schuchardt [agraf: fix efi gop support] Signed-off-by: Alexander Graf --- include/efi_loader.h | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 99619f53a94..c620652307e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -49,15 +49,10 @@ struct efi_class_map { /* * When the UEFI payload wants to open a protocol on an object to get its * interface (usually a struct with callback functions), this struct maps the - * protocol GUID to the respective protocol handler open function for that - * object protocol combination. - */ + * protocol GUID to the respective protocol interface */ struct efi_handler { const efi_guid_t *guid; - efi_status_t (EFIAPI *open)(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); + void *protocol_interface; }; /* @@ -91,14 +86,6 @@ void efi_smbios_register(void); /* Called by networking code to memorize the dhcp ack package */ void efi_net_set_dhcp_ack(void *pkt, int len); -/* - * Stub implementation for a protocol opener that just returns the handle as - * interface - */ -efi_status_t EFIAPI efi_return_handle(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ -- cgit v1.3.1 From e0549f8a174be5cf9526ec2d072cadc17a54a3e5 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:16 +0200 Subject: efi_loader: implement InstallProtocolInterface efi_install_protocol_interface up to now only returned an error code. The patch implements the UEFI specification for InstallProtocolInterface with the exception that it will not create new handles. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 2 +- lib/efi_loader/efi_boottime.c | 54 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index f071b36b536..42cd47ff080 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -58,7 +58,7 @@ struct efi_boot_services { efi_status_t (EFIAPI *signal_event)(void *event); efi_status_t (EFIAPI *close_event)(void *event); efi_status_t (EFIAPI *check_event)(void *event); - +#define EFI_NATIVE_INTERFACE 0x00000000 efi_status_t (EFIAPI *install_protocol_interface)( void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 22e9e6001d1..a6325ba9d87 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -303,10 +303,62 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r; + EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, protocol_interface); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + if (!handle || !protocol || + protocol_interface_type != EFI_NATIVE_INTERFACE) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + /* Create new handle if requested. */ + if (!*handle) { + r = EFI_OUT_OF_RESOURCES; + goto out; + } + /* Find object. */ + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != *handle) + continue; + /* Check if protocol is already installed on the handle. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (!handler->guid) + continue; + if (!guidcmp(handler->guid, protocol)) { + r = EFI_INVALID_PARAMETER; + goto out; + } + } + /* Install protocol in first empty slot. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (handler->guid) + continue; + + handler->guid = protocol; + handler->protocol_interface = protocol_interface; + r = EFI_SUCCESS; + goto out; + } + r = EFI_OUT_OF_RESOURCES; + goto out; + } + r = EFI_INVALID_PARAMETER; +out: + return EFI_EXIT(r); } + static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, efi_guid_t *protocol, void *old_interface, void *new_interface) -- cgit v1.3.1 From 011f432745ae7fdb645e16c03382a4181d262619 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:23 +0200 Subject: efi_loader: provide a sufficient number of protocols Four protocols per object is too few to run iPXE. Let's raise the number of protocols per object to eight. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index c620652307e..989e5809ba7 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -65,8 +65,8 @@ struct efi_handler { struct efi_object { /* Every UEFI object is part of a global object list */ struct list_head link; - /* We support up to 4 "protocols" an object can be accessed through */ - struct efi_handler protocols[4]; + /* We support up to 8 "protocols" an object can be accessed through */ + struct efi_handler protocols[8]; /* The object spawner can either use this for data or as identifier */ void *handle; }; -- cgit v1.3.1 From 88adae5ef057845f6bc69c63123df4332fe835b1 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:24 +0200 Subject: efi_loader: reimplement efi_locate_protocol The UEFI specification requires that LocateProtol finds the first handle supporting the protocol and to return a pointer to its interface. So we have to assign the protocols to an efi_object and not use any separate storage. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 4 ++++ include/efi_loader.h | 10 ---------- lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++++++------------ 3 files changed, 24 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2a56ad7f58e..8453d90b2c0 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -80,6 +80,10 @@ static struct efi_object loaded_image_info_obj = { .guid = &efi_guid_device_path, .protocol_interface = bootefi_device_path, }, + { + .guid = &efi_guid_console_control, + .protocol_interface = (void *) &efi_console_control + }, }, }; diff --git a/include/efi_loader.h b/include/efi_loader.h index 989e5809ba7..6ea6e9ee4dc 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -36,16 +36,6 @@ extern const efi_guid_t efi_guid_loaded_image; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; -/* - * While UEFI objects can have callbacks, you can also call functions on - * protocols (classes) themselves. This struct maps a protocol GUID to its - * interface (usually a struct with callback functions). - */ -struct efi_class_map { - const efi_guid_t *guid; - const void *interface; -}; - /* * When the UEFI payload wants to open a protocol on an object to get its * interface (usually a struct with callback functions), this struct maps the diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6f093290eb6..339fe55cde9 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -786,27 +786,35 @@ out: return EFI_EXIT(r); } -static struct efi_class_map efi_class_maps[] = { - { - .guid = &efi_guid_console_control, - .interface = &efi_console_control - }, -}; - static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, void *registration, void **protocol_interface) { + struct list_head *lhandle; int i; EFI_ENTRY("%p, %p, %p", protocol, registration, protocol_interface); - for (i = 0; i < ARRAY_SIZE(efi_class_maps); i++) { - struct efi_class_map *curmap = &efi_class_maps[i]; - if (!guidcmp(protocol, curmap->guid)) { - *protocol_interface = (void*)curmap->interface; - return EFI_EXIT(EFI_SUCCESS); + + if (!protocol || !protocol_interface) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + + efiobj = list_entry(lhandle, struct efi_object, link); + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + + if (!handler->guid) + continue; + if (!guidcmp(handler->guid, protocol)) { + *protocol_interface = + handler->protocol_interface; + return EFI_EXIT(EFI_SUCCESS); + } } } + *protocol_interface = NULL; return EFI_EXIT(EFI_NOT_FOUND); } -- cgit v1.3.1 From cc5b70812f5e3b13ea9072c2dacc939818ef8e66 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:25 +0200 Subject: efi_loader: implement EFI_DEVICE_PATH_TO_TEXT_PROTOCOL ConvertPathToText is implemented for * type 4 - media device path * subtype 4 - file path This is the kind of device path we hand out for block devices. All other cases may be implemented later. Signed-off-by: Heinrich Schuchardt [agraf: fix whitespace] Signed-off-by: Alexander Graf --- cmd/bootefi.c | 4 ++ include/efi_api.h | 24 ++++++++++++ include/efi_loader.h | 2 + lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_device_path_to_text.c | 67 ++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_device_path_to_text.c (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 8453d90b2c0..dcae2531638 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -84,6 +84,10 @@ static struct efi_object loaded_image_info_obj = { .guid = &efi_guid_console_control, .protocol_interface = (void *) &efi_console_control }, + { + .guid = &efi_guid_device_path_to_text_protocol, + .protocol_interface = (void *) &efi_device_path_to_text + }, }, }; diff --git a/include/efi_api.h b/include/efi_api.h index 42cd47ff080..ea63e80b47c 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -395,6 +395,30 @@ struct efi_console_control_protocol uint16_t *password); }; +#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + EFI_GUID(0x8b843e20, 0x8132, 0x4852, \ + 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c) + +struct efi_device_path_protocol +{ + uint8_t type; + uint8_t sub_type; + uint16_t length; + uint8_t data[]; +}; + +struct efi_device_path_to_text_protocol +{ + uint16_t *(EFIAPI *convert_device_node_to_text)( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts); + uint16_t *(EFIAPI *convert_device_path_to_text)( + struct efi_device_path_protocol *device_path, + bool display_only, + bool allow_shortcuts); +}; + #define EFI_GOP_GUID \ EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) diff --git a/include/efi_loader.h b/include/efi_loader.h index 6ea6e9ee4dc..d7847d23e53 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -28,10 +28,12 @@ extern struct efi_system_table systab; extern const struct efi_simple_text_output_protocol efi_con_out; extern const struct efi_simple_input_interface efi_con_in; extern const struct efi_console_control_protocol efi_console_control; +extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; extern const efi_guid_t efi_guid_loaded_image; +extern const efi_guid_t efi_guid_device_path_to_text_protocol; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index fa8b91a5269..3fc2371896c 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -15,7 +15,7 @@ always := $(efiprogs-y) obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o -obj-y += efi_memory.o +obj-y += efi_memory.o efi_device_path_to_text.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c new file mode 100644 index 00000000000..a7a513047fe --- /dev/null +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -0,0 +1,67 @@ +/* + * EFI device path interface + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#define MEDIA_DEVICE_PATH 4 +#define FILE_PATH_MEDIA_DEVICE_PATH 4 + +const efi_guid_t efi_guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + +uint16_t *efi_convert_device_node_to_text( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts) +{ + EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts); + + EFI_EXIT(EFI_UNSUPPORTED); + return NULL; +} + +uint16_t *efi_convert_device_path_to_text( + struct efi_device_path_protocol *device_path, + bool display_only, + bool allow_shortcuts) +{ + EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts); + + unsigned long buffer_size; + efi_status_t r; + uint16_t *buffer = NULL; + + switch (device_path->type) { + case MEDIA_DEVICE_PATH: + switch (device_path->sub_type) { + case FILE_PATH_MEDIA_DEVICE_PATH: + buffer_size = device_path->length - 4; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + buffer_size, (void **) &buffer); + if (r == EFI_SUCCESS) + memcpy(buffer, device_path->data, buffer_size); + break; + } + } + + if (buffer) { + EFI_EXIT(EFI_SUCCESS); + } else { + debug("type %d, subtype %d\n", + device_path->type, device_path->sub_type); + EFI_EXIT(EFI_UNSUPPORTED); + } + + return buffer; +} + +const struct efi_device_path_to_text_protocol efi_device_path_to_text = { + .convert_device_node_to_text = efi_convert_device_node_to_text, + .convert_device_path_to_text = efi_convert_device_path_to_text, +}; -- cgit v1.3.1 From 3c8ffb68753d03a74e680a9a493828da517eeeb7 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 4 Jul 2017 23:15:22 +0200 Subject: efi_loader: define all known status codes efi.h held only a few EFI status codes. The patch adds the missing definitions for later usage. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi.h | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/efi.h b/include/efi.h index 3d587807e8c..02b78b31b12 100644 --- a/include/efi.h +++ b/include/efi.h @@ -39,19 +39,43 @@ struct efi_device_path; #define EFI_BITS_PER_LONG 64 #endif -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR (1 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_INVALID_PARAMETER (2 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_UNSUPPORTED (3 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_BAD_BUFFER_SIZE (4 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_BUFFER_TOO_SMALL (5 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_NOT_READY (6 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_DEVICE_ERROR (7 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_WRITE_PROTECTED (8 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_OUT_OF_RESOURCES (9 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_NOT_FOUND (14 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_ACCESS_DENIED (15 | (1UL << (EFI_BITS_PER_LONG - 1))) -#define EFI_SECURITY_VIOLATION (26 | (1UL << (EFI_BITS_PER_LONG - 1))) +/* Bit mask for EFI status code with error */ +#define EFI_ERROR_MASK (1UL << (EFI_BITS_PER_LONG - 1)) +/* Status codes returned by EFI protocols */ +#define EFI_SUCCESS 0 +#define EFI_LOAD_ERROR (EFI_ERROR_MASK | 1) +#define EFI_INVALID_PARAMETER (EFI_ERROR_MASK | 2) +#define EFI_UNSUPPORTED (EFI_ERROR_MASK | 3) +#define EFI_BAD_BUFFER_SIZE (EFI_ERROR_MASK | 4) +#define EFI_BUFFER_TOO_SMALL (EFI_ERROR_MASK | 5) +#define EFI_NOT_READY (EFI_ERROR_MASK | 6) +#define EFI_DEVICE_ERROR (EFI_ERROR_MASK | 7) +#define EFI_WRITE_PROTECTED (EFI_ERROR_MASK | 8) +#define EFI_OUT_OF_RESOURCES (EFI_ERROR_MASK | 9) +#define EFI_VOLUME_CORRUPTED (EFI_ERROR_MASK | 10) +#define EFI_VOLUME_FULL (EFI_ERROR_MASK | 11) +#define EFI_NO_MEDIA (EFI_ERROR_MASK | 12) +#define EFI_MEDIA_CHANGED (EFI_ERROR_MASK | 13) +#define EFI_NOT_FOUND (EFI_ERROR_MASK | 14) +#define EFI_ACCESS_DENIED (EFI_ERROR_MASK | 15) +#define EFI_NO_RESPONSE (EFI_ERROR_MASK | 16) +#define EFI_NO_MAPPING (EFI_ERROR_MASK | 17) +#define EFI_TIMEOUT (EFI_ERROR_MASK | 18) +#define EFI_NOT_STARTED (EFI_ERROR_MASK | 19) +#define EFI_ALREADY_STARTED (EFI_ERROR_MASK | 20) +#define EFI_ABORTED (EFI_ERROR_MASK | 21) +#define EFI_ICMP_ERROR (EFI_ERROR_MASK | 22) +#define EFI_TFTP_ERROR (EFI_ERROR_MASK | 23) +#define EFI_PROTOCOL_ERROR (EFI_ERROR_MASK | 24) +#define EFI_INCOMPATIBLE_VERSION (EFI_ERROR_MASK | 25) +#define EFI_SECURITY_VIOLATION (EFI_ERROR_MASK | 26) +#define EFI_CRC_ERROR (EFI_ERROR_MASK | 27) +#define EFI_END_OF_MEDIA (EFI_ERROR_MASK | 28) +#define EFI_END_OF_FILE (EFI_ERROR_MASK | 31) +#define EFI_INVALID_LANGUAGE (EFI_ERROR_MASK | 32) +#define EFI_COMPROMISED_DATA (EFI_ERROR_MASK | 33) +#define EFI_IP_ADDRESS_CONFLICT (EFI_ERROR_MASK | 34) +#define EFI_HTTP_ERROR (EFI_ERROR_MASK | 35) typedef unsigned long efi_status_t; typedef u64 efi_physical_addr_t; -- cgit v1.3.1 From 2fd945fe7287a15a29051242c9d021647a6f52dc Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:17 +0200 Subject: efi_loader: use struct efi_event * instead of void * In our implementation the internal structure of events is known. So use the known type instead of void. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 23 +++++++++++++---------- lib/efi_loader/efi_boottime.c | 25 ++++++++++++++----------- 2 files changed, 27 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index ea63e80b47c..a1f8221111a 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -31,6 +31,8 @@ enum efi_event_type { #define EVT_NOTIFY_WAIT 0x00000100 #define EVT_NOTIFY_SIGNAL 0x00000200 +struct efi_event; + /* EFI Boot Services table */ struct efi_boot_services { struct efi_table_hdr hdr; @@ -48,16 +50,17 @@ struct efi_boot_services { efi_status_t (EFIAPI *create_event)(enum efi_event_type type, unsigned long notify_tpl, - void (EFIAPI *notify_function) (void *event, - void *context), - void *notify_context, void **event); - efi_status_t (EFIAPI *set_timer)(void *event, int type, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event); + efi_status_t (EFIAPI *set_timer)(struct efi_event *event, int type, uint64_t trigger_time); efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events, - void *event, unsigned long *index); - efi_status_t (EFIAPI *signal_event)(void *event); - efi_status_t (EFIAPI *close_event)(void *event); - efi_status_t (EFIAPI *check_event)(void *event); + struct efi_event **event, unsigned long *index); + efi_status_t (EFIAPI *signal_event)(struct efi_event *event); + efi_status_t (EFIAPI *close_event)(struct efi_event *event); + efi_status_t (EFIAPI *check_event)(struct efi_event *event); #define EFI_NATIVE_INTERFACE 0x00000000 efi_status_t (EFIAPI *install_protocol_interface)( void **handle, efi_guid_t *protocol, @@ -71,7 +74,7 @@ struct efi_boot_services { void **); void *reserved; efi_status_t (EFIAPI *register_protocol_notify)( - efi_guid_t *protocol, void *event, + efi_guid_t *protocol, struct efi_event *event, void **registration); efi_status_t (EFIAPI *locate_handle)( enum efi_locate_search_type search_type, @@ -374,7 +377,7 @@ struct efi_simple_input_interface { efi_status_t(EFIAPI *read_key_stroke)( struct efi_simple_input_interface *this, struct efi_input_key *key); - void *wait_for_key; + struct efi_event *wait_for_key; }; #define CONSOLE_CONTROL_GUID \ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 339fe55cde9..79eb0d98be5 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -165,13 +165,14 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) * Our event capabilities are very limited. Only support a single * event to exist, so we don't need to maintain lists. */ -static struct { +static struct efi_event { enum efi_event_type type; u32 trigger_type; u32 trigger_time; u64 trigger_next; unsigned long notify_tpl; - void (EFIAPI *notify_function) (void *event, void *context); + void (EFIAPI *notify_function) (struct efi_event *event, + void *context); void *notify_context; } efi_event = { /* Disable timers on bootup */ @@ -180,9 +181,10 @@ static struct { static efi_status_t EFIAPI efi_create_event( enum efi_event_type type, ulong notify_tpl, - void (EFIAPI *notify_function) (void *event, - void *context), - void *notify_context, void **event) + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event) { EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function, notify_context); @@ -230,7 +232,7 @@ void efi_timer_check(void) WATCHDOG_RESET(); } -static efi_status_t EFIAPI efi_set_timer(void *event, int type, +static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, uint64_t trigger_time) { /* We don't have 64bit division available everywhere, so limit timer @@ -267,7 +269,8 @@ static efi_status_t EFIAPI efi_set_timer(void *event, int type, } static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, - void *event, unsigned long *index) + struct efi_event **event, + unsigned long *index) { u64 now; @@ -280,20 +283,20 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_signal_event(void *event) +static efi_status_t EFIAPI efi_signal_event(struct efi_event *event) { EFI_ENTRY("%p", event); return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_close_event(void *event) +static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { EFI_ENTRY("%p", event); efi_event.trigger_next = -1ULL; return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_check_event(void *event) +static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { EFI_ENTRY("%p", event); return EFI_EXIT(EFI_NOT_READY); @@ -428,7 +431,7 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, } static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, - void *event, + struct efi_event *event, void **registration) { EFI_ENTRY("%p, %p, %p", protocol, event, registration); -- cgit v1.3.1 From c68415922b340c6b26f94326a6899977a67d61c9 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:18 +0200 Subject: efi_loader: implement multiple event support Up to now the boot time supported only a single event. This patch now allows four events. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 13 ++- include/efi_loader.h | 24 ++++++ lib/efi_loader/efi_boottime.c | 195 ++++++++++++++++++++++++++++-------------- 3 files changed, 168 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index a1f8221111a..a3b8e045762 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -28,8 +28,17 @@ enum efi_event_type { EFI_TIMER_RELATIVE = 2 }; -#define EVT_NOTIFY_WAIT 0x00000100 -#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define TPL_APPLICATION 0x04 +#define TPL_CALLBACK 0x08 +#define TPL_NOTIFY 0x10 +#define TPL_HIGH_LEVEL 0x1F struct efi_event; diff --git a/include/efi_loader.h b/include/efi_loader.h index d7847d23e53..3d18bfbd2e9 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -63,6 +63,30 @@ struct efi_object { void *handle; }; +/** + * struct efi_event + * + * @type: Type of event, see efi_create_event + * @notify_tpl: Task priority level of notifications + * @trigger_time: Period of the timer + * @trigger_next: Next time to trigger the timer + * @nofify_function: Function to call when the event is triggered + * @notify_context: Data to be passed to the notify function + * @trigger_type: Type of timer, see efi_set_timer + * @signaled: The notify function was already called + */ +struct efi_event { + u32 type; + unsigned long notify_tpl; + void (EFIAPI *notify_function)(struct efi_event *event, void *context); + void *notify_context; + u64 trigger_next; + u64 trigger_time; + enum efi_event_type trigger_type; + int signaled; +}; + + /* This list contains all UEFI objects we know of */ extern struct list_head efi_obj_list; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 79eb0d98be5..bdcca38a9f2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -81,6 +81,18 @@ efi_status_t efi_exit_func(efi_status_t ret) return ret; } +static void efi_signal_event(struct efi_event *event) +{ + if (event->signaled) + return; + event->signaled = 1; + if (event->type & EVT_NOTIFY_SIGNAL) { + EFI_EXIT(EFI_SUCCESS); + event->notify_function(event, event->notify_context); + EFI_ENTRY("returning from notification function"); + } +} + static efi_status_t efi_unsupported(const char *funcname) { debug("EFI: App called into unimplemented function %s\n", funcname); @@ -162,22 +174,10 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) } /* - * Our event capabilities are very limited. Only support a single - * event to exist, so we don't need to maintain lists. + * Our event capabilities are very limited. Only a small limited + * number of events is allowed to coexist. */ -static struct efi_event { - enum efi_event_type type; - u32 trigger_type; - u32 trigger_time; - u64 trigger_next; - unsigned long notify_tpl; - void (EFIAPI *notify_function) (struct efi_event *event, - void *context); - void *notify_context; -} efi_event = { - /* Disable timers on bootup */ - .trigger_next = -1ULL, -}; +static struct efi_event efi_events[16]; static efi_status_t EFIAPI efi_create_event( enum efi_event_type type, ulong notify_tpl, @@ -186,13 +186,10 @@ static efi_status_t EFIAPI efi_create_event( void *context), void *notify_context, struct efi_event **event) { + int i; + EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function, notify_context); - if (efi_event.notify_function) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_OUT_OF_RESOURCES); - } - if (event == NULL) return EFI_EXIT(EFI_INVALID_PARAMETER); @@ -203,13 +200,20 @@ static efi_status_t EFIAPI efi_create_event( notify_function == NULL) return EFI_EXIT(EFI_INVALID_PARAMETER); - efi_event.type = type; - efi_event.notify_tpl = notify_tpl; - efi_event.notify_function = notify_function; - efi_event.notify_context = notify_context; - *event = &efi_event; - - return EFI_EXIT(EFI_SUCCESS); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (efi_events[i].type) + continue; + efi_events[i].type = type; + efi_events[i].notify_tpl = notify_tpl; + efi_events[i].notify_function = notify_function; + efi_events[i].notify_context = notify_context; + /* Disable timers on bootup */ + efi_events[i].trigger_next = -1ULL; + efi_events[i].signaled = 0; + *event = &efi_events[i]; + return EFI_EXIT(EFI_SUCCESS); + } + return EFI_EXIT(EFI_OUT_OF_RESOURCES); } /* @@ -218,17 +222,22 @@ static efi_status_t EFIAPI efi_create_event( */ void efi_timer_check(void) { + int i; u64 now = timer_get_us(); - if (now >= efi_event.trigger_next) { - /* Triggering! */ - if (efi_event.trigger_type == EFI_TIMER_PERIODIC) - efi_event.trigger_next += efi_event.trigger_time / 10; - if (efi_event.type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) - efi_event.notify_function(&efi_event, - efi_event.notify_context); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (!efi_events[i].type || + !(efi_events[i].type & EVT_TIMER) || + efi_events[i].trigger_type == EFI_TIMER_STOP || + now < efi_events[i].trigger_next) + continue; + if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) { + efi_events[i].trigger_next += + efi_events[i].trigger_time / 10; + efi_events[i].signaled = 0; + } + efi_signal_event(&efi_events[i]); } - WATCHDOG_RESET(); } @@ -238,6 +247,7 @@ static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, /* We don't have 64bit division available everywhere, so limit timer * distances to 32bit bits. */ u32 trigger32 = trigger_time; + int i; EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); @@ -246,60 +256,121 @@ static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, trigger_time, trigger32); } - if (event != &efi_event) { - /* We only support one event at a time */ - return EFI_EXIT(EFI_INVALID_PARAMETER); - } + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; - switch (type) { - case EFI_TIMER_STOP: - efi_event.trigger_next = -1ULL; - break; - case EFI_TIMER_PERIODIC: - case EFI_TIMER_RELATIVE: - efi_event.trigger_next = timer_get_us() + (trigger32 / 10); - break; - default: - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!(event->type & EVT_TIMER)) + break; + switch (type) { + case EFI_TIMER_STOP: + event->trigger_next = -1ULL; + break; + case EFI_TIMER_PERIODIC: + case EFI_TIMER_RELATIVE: + event->trigger_next = + timer_get_us() + (trigger32 / 10); + break; + default: + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + event->trigger_type = type; + event->trigger_time = trigger_time; + return EFI_EXIT(EFI_SUCCESS); } - efi_event.trigger_type = type; - efi_event.trigger_time = trigger_time; - - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, unsigned long *index) { - u64 now; + int i, j; EFI_ENTRY("%ld, %p, %p", num_events, event, index); - now = timer_get_us(); - while (now < efi_event.trigger_next) { } - efi_timer_check(); + /* Check parameters */ + if (!num_events || !event) + return EFI_EXIT(EFI_INVALID_PARAMETER); + for (i = 0; i < num_events; ++i) { + for (j = 0; j < ARRAY_SIZE(efi_events); ++j) { + if (event[i] == &efi_events[j]) + goto known_event; + } + return EFI_EXIT(EFI_INVALID_PARAMETER); +known_event: + if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) + return EFI_EXIT(EFI_INVALID_PARAMETER); + } + + /* Wait for signal */ + for (;;) { + for (i = 0; i < num_events; ++i) { + if (event[i]->signaled) + goto out; + } + /* Allow events to occur. */ + efi_timer_check(); + } + +out: + /* + * Reset the signal which is passed to the caller to allow periodic + * events to occur. + */ + event[i]->signaled = 0; + if (index) + *index = i; return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_signal_event(struct efi_event *event) +static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; + efi_signal_event(event); + break; + } return EFI_EXIT(EFI_SUCCESS); } static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - efi_event.trigger_next = -1ULL; - return EFI_EXIT(EFI_SUCCESS); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event == &efi_events[i]) { + event->type = 0; + event->trigger_next = -1ULL; + event->signaled = 0; + return EFI_EXIT(EFI_SUCCESS); + } + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { + int i; + EFI_ENTRY("%p", event); - return EFI_EXIT(EFI_NOT_READY); + efi_timer_check(); + for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { + if (event != &efi_events[i]) + continue; + if (!event->type || event->type & EVT_NOTIFY_SIGNAL) + break; + if (event->signaled) + return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_NOT_READY); + } + return EFI_EXIT(EFI_INVALID_PARAMETER); } static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, @@ -987,7 +1058,7 @@ static const struct efi_boot_services efi_boot_services = { .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, - .signal_event = efi_signal_event, + .signal_event = efi_signal_event_ext, .close_event = efi_close_event, .check_event = efi_check_event, .install_protocol_interface = efi_install_protocol_interface_ext, -- cgit v1.3.1 From 503f26955489af052c0c01eaf7bdc6ae3ecc3aa2 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:19 +0200 Subject: efi_loader: correct size for tpl level The UEFI standard defines the type for the tpl level as EFI_TPL alias UINTN. UINTN is an integer is defined as an unsigned integer of native width. So we can use size_t for the definition. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 8 +++++--- include/efi_loader.h | 2 +- lib/efi_loader/efi_boottime.c | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index a3b8e045762..d52eea40866 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -28,6 +28,8 @@ enum efi_event_type { EFI_TIMER_RELATIVE = 2 }; +#define UINTN size_t + #define EVT_TIMER 0x80000000 #define EVT_RUNTIME 0x40000000 #define EVT_NOTIFY_WAIT 0x00000100 @@ -45,8 +47,8 @@ struct efi_event; /* EFI Boot Services table */ struct efi_boot_services { struct efi_table_hdr hdr; - efi_status_t (EFIAPI *raise_tpl)(unsigned long new_tpl); - void (EFIAPI *restore_tpl)(unsigned long old_tpl); + efi_status_t (EFIAPI *raise_tpl)(UINTN new_tpl); + void (EFIAPI *restore_tpl)(UINTN old_tpl); efi_status_t (EFIAPI *allocate_pages)(int, int, unsigned long, efi_physical_addr_t *); @@ -58,7 +60,7 @@ struct efi_boot_services { efi_status_t (EFIAPI *free_pool)(void *); efi_status_t (EFIAPI *create_event)(enum efi_event_type type, - unsigned long notify_tpl, + UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), diff --git a/include/efi_loader.h b/include/efi_loader.h index 3d18bfbd2e9..b9227200683 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -77,7 +77,7 @@ struct efi_object { */ struct efi_event { u32 type; - unsigned long notify_tpl; + UINTN notify_tpl; void (EFIAPI *notify_function)(struct efi_event *event, void *context); void *notify_context; u64 trigger_next; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bdcca38a9f2..f04d9eb3419 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -104,15 +104,15 @@ static int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) return memcmp(g1, g2, sizeof(efi_guid_t)); } -static unsigned long EFIAPI efi_raise_tpl(unsigned long new_tpl) +static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) { - EFI_ENTRY("0x%lx", new_tpl); + EFI_ENTRY("0x%zx", new_tpl); return EFI_EXIT(0); } -static void EFIAPI efi_restore_tpl(unsigned long old_tpl) +static void EFIAPI efi_restore_tpl(UINTN old_tpl) { - EFI_ENTRY("0x%lx", old_tpl); + EFI_ENTRY("0x%zx", old_tpl); EFI_EXIT(efi_unsupported(__func__)); } @@ -180,7 +180,7 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) static struct efi_event efi_events[16]; static efi_status_t EFIAPI efi_create_event( - enum efi_event_type type, ulong notify_tpl, + enum efi_event_type type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), @@ -188,7 +188,7 @@ static efi_status_t EFIAPI efi_create_event( { int i; - EFI_ENTRY("%d, 0x%lx, %p, %p", type, notify_tpl, notify_function, + EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function, notify_context); if (event == NULL) return EFI_EXIT(EFI_INVALID_PARAMETER); -- cgit v1.3.1 From 49deb455e6e650124c4e6ab1006f5450d2282be8 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:20 +0200 Subject: efi_loader: refactor efi_create_event efi_create_event is refactored to make it possible to call it internally. For EFI applications wrapper function efi_create_event_ext is created. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 6 ++++++ lib/efi_loader/efi_boottime.c | 35 +++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index b9227200683..c3640153e13 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -116,6 +116,12 @@ efi_status_t efi_exit_func(efi_status_t ret); void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); /* Call this to set the current device name */ void efi_set_bootdev(const char *dev, const char *devnr, const char *path); +/* Call this to create an event */ +efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event); /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f04d9eb3419..30227cc56c1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -179,26 +179,23 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) */ static struct efi_event efi_events[16]; -static efi_status_t EFIAPI efi_create_event( - enum efi_event_type type, UINTN notify_tpl, - void (EFIAPI *notify_function) ( +efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( struct efi_event *event, void *context), - void *notify_context, struct efi_event **event) + void *notify_context, struct efi_event **event) { int i; - EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function, - notify_context); if (event == NULL) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT)) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; if ((type & (EVT_NOTIFY_SIGNAL|EVT_NOTIFY_WAIT)) && notify_function == NULL) - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { if (efi_events[i].type) @@ -211,11 +208,25 @@ static efi_status_t EFIAPI efi_create_event( efi_events[i].trigger_next = -1ULL; efi_events[i].signaled = 0; *event = &efi_events[i]; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; } - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + return EFI_OUT_OF_RESOURCES; } +static efi_status_t EFIAPI efi_create_event_ext( + enum efi_event_type type, UINTN notify_tpl, + void (EFIAPI *notify_function) ( + struct efi_event *event, + void *context), + void *notify_context, struct efi_event **event) +{ + EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function, + notify_context); + return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function, + notify_context, event)); +} + + /* * Our timers have to work without interrupts, so we check whenever keyboard * input or disk accesses happen if enough time elapsed for it to fire. @@ -1055,7 +1066,7 @@ static const struct efi_boot_services efi_boot_services = { .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool_ext, - .create_event = efi_create_event, + .create_event = efi_create_event_ext, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, .signal_event = efi_signal_event_ext, -- cgit v1.3.1 From bfc724625f73f80321945fee306d0c4dc3015898 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:21 +0200 Subject: efi_loader: refactor efi_set_timer efi_set_timer is refactored to make the function callable internally. Wrapper function efi_set_timer_ext is provided for EFI applications. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 21 +++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index c3640153e13..342e960d145 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -122,6 +122,9 @@ efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, struct efi_event *event, void *context), void *notify_context, struct efi_event **event); +/* Call this to set a timer */ +efi_status_t efi_set_timer(struct efi_event *event, int type, + uint64_t trigger_time); /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 30227cc56c1..4cd06b3c4c2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -252,16 +252,14 @@ void efi_timer_check(void) WATCHDOG_RESET(); } -static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, - uint64_t trigger_time) +efi_status_t efi_set_timer(struct efi_event *event, int type, + uint64_t trigger_time) { /* We don't have 64bit division available everywhere, so limit timer * distances to 32bit bits. */ u32 trigger32 = trigger_time; int i; - EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); - if (trigger32 < trigger_time) { printf("WARNING: Truncating timer from %"PRIx64" to %x\n", trigger_time, trigger32); @@ -283,13 +281,20 @@ static efi_status_t EFIAPI efi_set_timer(struct efi_event *event, int type, timer_get_us() + (trigger32 / 10); break; default: - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; } event->trigger_type = type; event->trigger_time = trigger_time; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; } - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_INVALID_PARAMETER; +} + +static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, int type, + uint64_t trigger_time) +{ + EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); + return EFI_EXIT(efi_set_timer(event, type, trigger_time)); } static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, @@ -1067,7 +1072,7 @@ static const struct efi_boot_services efi_boot_services = { .allocate_pool = efi_allocate_pool_ext, .free_pool = efi_free_pool_ext, .create_event = efi_create_event_ext, - .set_timer = efi_set_timer, + .set_timer = efi_set_timer_ext, .wait_for_event = efi_wait_for_event, .signal_event = efi_signal_event_ext, .close_event = efi_close_event, -- cgit v1.3.1 From 91be9a77b758f5c785787260a1ed8f1b751ff49a Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:22 +0200 Subject: efi_console: set up events Set up a timer event and the WaitForKey event. In the notify function of the timer event check for console input and signal the WaitForKey event accordingly. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 1 + include/efi_loader.h | 6 +++++- lib/efi_loader/efi_boottime.c | 2 +- lib/efi_loader/efi_console.c | 40 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 08c60e6fa9d..e9f14d54af3 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -226,6 +226,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) INIT_LIST_HEAD(&efi_obj_list); list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); list_add_tail(&bootefi_device_obj.link, &efi_obj_list); + efi_console_register(); #ifdef CONFIG_PARTITIONS efi_disk_register(); #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 342e960d145..2abb6b87e17 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -26,7 +26,7 @@ extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; extern const struct efi_simple_text_output_protocol efi_con_out; -extern const struct efi_simple_input_interface efi_con_in; +extern struct efi_simple_input_interface efi_con_in; extern const struct efi_console_control_protocol efi_console_control; extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; @@ -90,6 +90,8 @@ struct efi_event { /* This list contains all UEFI objects we know of */ extern struct list_head efi_obj_list; +/* Called by bootefi to make console interface available */ +int efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ int efi_disk_register(void); /* Called by bootefi to make GOP (graphical) interface available */ @@ -125,6 +127,8 @@ efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, /* Call this to set a timer */ efi_status_t efi_set_timer(struct efi_event *event, int type, uint64_t trigger_time); +/* Call this to signal an event */ +void efi_signal_event(struct efi_event *event); /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4cd06b3c4c2..b8dfceae0c0 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -81,7 +81,7 @@ efi_status_t efi_exit_func(efi_status_t ret) return ret; } -static void efi_signal_event(struct efi_event *event) +void efi_signal_event(struct efi_event *event) { if (event->signaled) return; diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 8ef7326fef2..dbe98ac08b8 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -421,8 +421,46 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke( return EFI_EXIT(EFI_SUCCESS); } -const struct efi_simple_input_interface efi_con_in = { +struct efi_simple_input_interface efi_con_in = { .reset = efi_cin_reset, .read_key_stroke = efi_cin_read_key_stroke, .wait_for_key = NULL, }; + +static struct efi_event *console_timer_event; + +static void efi_key_notify(struct efi_event *event, void *context) +{ +} + +static void efi_console_timer_notify(struct efi_event *event, void *context) +{ + EFI_ENTRY("%p, %p", event, context); + if (tstc()) + efi_signal_event(efi_con_in.wait_for_key); + EFI_EXIT(EFI_SUCCESS); +} + +/* This gets called from do_bootefi_exec(). */ +int efi_console_register(void) +{ + efi_status_t r; + r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, + efi_key_notify, NULL, &efi_con_in.wait_for_key); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register WaitForKey event\n"); + return r; + } + r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + efi_console_timer_notify, NULL, + &console_timer_event); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register console event\n"); + return r; + } + /* 5000 ns cycle is sufficient for 2 MBaud */ + r = efi_set_timer(console_timer_event, EFI_TIMER_PERIODIC, 50); + if (r != EFI_SUCCESS) + printf("ERROR: Failed to set console timer\n"); + return r; +} -- cgit v1.3.1 From 3e094c592bc1dc19bb706379458f6be4e9500287 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jul 2017 07:59:11 -0400 Subject: efi_loader: move guidcmp to header Want to re-use this for file protocol, which I'm working on. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- include/efi_loader.h | 5 +++++ lib/efi_loader/efi_boottime.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 2abb6b87e17..7818e1cebb4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -168,6 +168,11 @@ static inline void ascii2unicode(u16 *unicode, const char *ascii) *(unicode++) = *(ascii++); } +static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) +{ + return memcmp(g1, g2, sizeof(efi_guid_t)); +} + /* * Use these to indicate that your code / data should go into the EFI runtime * section and thus still be available when the OS is running diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a89a6294062..e09f9dac5c8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -132,11 +132,6 @@ static efi_status_t efi_unsupported(const char *funcname) return EFI_EXIT(EFI_UNSUPPORTED); } -static int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) -{ - return memcmp(g1, g2, sizeof(efi_guid_t)); -} - static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) { EFI_ENTRY("0x%zx", new_tpl); -- cgit v1.3.1 From b521d29eb1b0dd7be8ee306729f93d964c4c0288 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Wed, 19 Jul 2017 19:22:34 +0200 Subject: efi_loader: parameter types for CreateEvent, SetTimer The first argument 'type' of CreateEvent is an 32bit unsigned integer bitmap and not an enum. The second argument 'type' of SetTimer take values of an enum which is called EFI_TIMER_DELAY in the UEFI standard. To avoid confusion rename efi_event_type to efi_timer_delay. Reported-by: Alexander Graf Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 9 +++++---- include/efi_loader.h | 8 ++++---- lib/efi_loader/efi_boottime.c | 11 ++++++----- 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index d52eea40866..8f881d2903b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -22,7 +22,7 @@ #endif /* Types and defines for EFI CreateEvent */ -enum efi_event_type { +enum efi_timer_delay { EFI_TIMER_STOP = 0, EFI_TIMER_PERIODIC = 1, EFI_TIMER_RELATIVE = 2 @@ -59,14 +59,15 @@ struct efi_boot_services { efi_status_t (EFIAPI *allocate_pool)(int, unsigned long, void **); efi_status_t (EFIAPI *free_pool)(void *); - efi_status_t (EFIAPI *create_event)(enum efi_event_type type, + efi_status_t (EFIAPI *create_event)(uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), void *notify_context, struct efi_event **event); - efi_status_t (EFIAPI *set_timer)(struct efi_event *event, int type, - uint64_t trigger_time); + efi_status_t (EFIAPI *set_timer)(struct efi_event *event, + enum efi_timer_delay type, + uint64_t trigger_time); efi_status_t (EFIAPI *wait_for_event)(unsigned long number_of_events, struct efi_event **event, unsigned long *index); efi_status_t (EFIAPI *signal_event)(struct efi_event *event); diff --git a/include/efi_loader.h b/include/efi_loader.h index 7818e1cebb4..4bcd35ac772 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -76,13 +76,13 @@ struct efi_object { * @signaled: The notify function was already called */ struct efi_event { - u32 type; + uint32_t type; UINTN notify_tpl; void (EFIAPI *notify_function)(struct efi_event *event, void *context); void *notify_context; u64 trigger_next; u64 trigger_time; - enum efi_event_type trigger_type; + enum efi_timer_delay trigger_type; int signaled; }; @@ -119,13 +119,13 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); /* Call this to set the current device name */ void efi_set_bootdev(const char *dev, const char *devnr, const char *path); /* Call this to create an event */ -efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, +efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), void *notify_context, struct efi_event **event); /* Call this to set a timer */ -efi_status_t efi_set_timer(struct efi_event *event, int type, +efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time); /* Call this to signal an event */ void efi_signal_event(struct efi_event *event); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7d45c18ff77..e0aead47c9b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -207,7 +207,7 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) */ static struct efi_event efi_events[16]; -efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, +efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), @@ -242,7 +242,7 @@ efi_status_t efi_create_event(enum efi_event_type type, UINTN notify_tpl, } static efi_status_t EFIAPI efi_create_event_ext( - enum efi_event_type type, UINTN notify_tpl, + uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), @@ -280,7 +280,7 @@ void efi_timer_check(void) WATCHDOG_RESET(); } -efi_status_t efi_set_timer(struct efi_event *event, int type, +efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) { int i; @@ -316,8 +316,9 @@ efi_status_t efi_set_timer(struct efi_event *event, int type, return EFI_INVALID_PARAMETER; } -static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, int type, - uint64_t trigger_time) +static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, + enum efi_timer_delay type, + uint64_t trigger_time) { EFI_ENTRY("%p, %d, %"PRIx64, event, type, trigger_time); return EFI_EXIT(efi_set_timer(event, type, trigger_time)); -- cgit v1.3.1 From 804b1d737a366604eacd527ef9c5896a8a13b7f5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jul 2017 10:31:52 -0400 Subject: efi_loader: log EFI return values too Turns out this is rather useful to tracking down where things fail. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- include/efi_loader.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 4bcd35ac772..40f6c89e656 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -20,7 +20,10 @@ debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ } while(0) -#define EFI_EXIT(ret) efi_exit_func(ret); +#define EFI_EXIT(ret) ({ \ + debug("EFI: Exit: %s: %u\n", __func__, (u32)((ret) & ~EFI_ERROR_MASK)); \ + efi_exit_func(ret); \ + }) extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; -- cgit v1.3.1 From 641833db4a3bc417e991e7d37ce7cb99657beee0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jul 2017 10:39:00 -0400 Subject: efi_loader: add helper macro to construct protocol objects There are a bunch of protocols which should be exposed by GUID but are not. Add a helper macro to create an efi_object, to avoid much typing. Note that using the pointer for efiobj->handle is semi-arbitrary. We just need a unique value to match the efiobj supporting the protocol with the handle that LocateHandle() returns.. See LibLocateProtocol() in gnu-efi. It does LocateHandle() to find all the handles, and then loops over them calling HandleProtocol() with the GUID of the protocol it is trying to find. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- include/efi_loader.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 40f6c89e656..f384cbbe771 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -66,6 +66,14 @@ struct efi_object { void *handle; }; +#define EFI_PROTOCOL_OBJECT(_guid, _protocol) (struct efi_object){ \ + .protocols = {{ \ + .guid = &(_guid), \ + .protocol_interface = (void *)(_protocol), \ + }}, \ + .handle = (void *)(_protocol), \ +} + /** * struct efi_event * -- cgit v1.3.1 From a17e62cc533b8eb59616fc21001be90685770a06 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jul 2017 10:39:01 -0400 Subject: efi_loader: expose protocols via GUID shim.efi (or rather gnu-efi's LibLocateProtocol() which shim.efi uses) resolves protocols via efi_locate_handle() so the console protocols need to be added to the efi object list. Signed-off-by: Rob Clark [agraf: whitespace fixes] Signed-off-by: Alexander Graf --- include/efi_api.h | 9 +++++++++ lib/efi_loader/efi_console.c | 14 ++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 8f881d2903b..ec1b321e8e7 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -349,6 +349,11 @@ struct simple_text_output_mode { bool cursor_visible; }; + +#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \ + 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + struct efi_simple_text_output_protocol { void *reset; efi_status_t (EFIAPI *output_string)( @@ -383,6 +388,10 @@ struct efi_input_key { s16 unicode_char; }; +#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \ + 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b) + struct efi_simple_input_interface { efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this, bool ExtendedVerification); diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 95e632394fa..5ebce4b544d 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -442,10 +442,24 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event, EFI_EXIT(EFI_SUCCESS); } + +static struct efi_object efi_console_control_obj = + EFI_PROTOCOL_OBJECT(efi_guid_console_control, &efi_console_control); +static struct efi_object efi_console_output_obj = + EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, &efi_con_out); +static struct efi_object efi_console_input_obj = + EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, &efi_con_in); + /* This gets called from do_bootefi_exec(). */ int efi_console_register(void) { efi_status_t r; + + /* Hook up to the device list */ + list_add_tail(&efi_console_control_obj.link, &efi_obj_list); + list_add_tail(&efi_console_output_obj.link, &efi_obj_list); + list_add_tail(&efi_console_input_obj.link, &efi_obj_list); + r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify, NULL, &efi_con_in.wait_for_key); if (r != EFI_SUCCESS) { -- cgit v1.3.1 From 3f1aa97577b75ee2f4f13d2b9fbaf68ce89f42be Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 27 Jul 2017 08:04:16 -0400 Subject: efi_loader: only evaluate EFI_EXIT()'s ret once There are a couple spots doing things like: return EFI_EXIT(some_fxn(...)); which I handn't noticed before. With addition of printing return value in the EFI_EXIT() macro, now the fxn call was getting evaluated twice. Which we didn't really want. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- include/efi_loader.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index f384cbbe771..9700a88d699 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -21,8 +21,9 @@ } while(0) #define EFI_EXIT(ret) ({ \ - debug("EFI: Exit: %s: %u\n", __func__, (u32)((ret) & ~EFI_ERROR_MASK)); \ - efi_exit_func(ret); \ + efi_status_t _r = ret; \ + debug("EFI: Exit: %s: %u\n", __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ + efi_exit_func(_r); \ }) extern struct efi_runtime_services efi_runtime_services; -- cgit v1.3.1 From a095aadffa96f3814d5605792674a6d64951db51 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 27 Jul 2017 08:04:17 -0400 Subject: efi_loader: Add an EFI_CALL() macro Rather than open-coding EFI_EXIT() + callback + EFI_ENTRY(), introduce an EFI_CALL() macro. This makes callbacks into UEFI world (of which there will be more in the future) more concise and easier to locate in the code. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- include/efi_loader.h | 17 +++++++++++++++++ lib/efi_loader/efi_boottime.c | 4 +--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 9700a88d699..eb16c14b699 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -15,17 +15,34 @@ #include +/* + * Enter the u-boot world from UEFI: + */ #define EFI_ENTRY(format, ...) do { \ efi_restore_gd(); \ debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ } while(0) +/* + * Exit the u-boot world back to UEFI: + */ #define EFI_EXIT(ret) ({ \ efi_status_t _r = ret; \ debug("EFI: Exit: %s: %u\n", __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ efi_exit_func(_r); \ }) +/* + * Callback into UEFI world from u-boot: + */ +#define EFI_CALL(exp) do { \ + debug("EFI: Call: %s\n", #exp); \ + efi_exit_func(EFI_SUCCESS); \ + exp; \ + efi_restore_gd(); \ + debug("EFI: Return From: %s\n", #exp); \ + } while(0) + extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 17c531a480e..849d2298213 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -120,9 +120,7 @@ void efi_signal_event(struct efi_event *event) return; event->signaled = 1; if (event->type & EVT_NOTIFY_SIGNAL) { - EFI_EXIT(EFI_SUCCESS); - event->notify_function(event, event->notify_context); - EFI_ENTRY("returning from notification function"); + EFI_CALL(event->notify_function(event, event->notify_context)); } } -- cgit v1.3.1 From c160d2f5ec9298d545a6e0fab0a68cc1a3e93759 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 27 Jul 2017 08:04:18 -0400 Subject: efi_loader: add checking for incorrect use of EFI_ENTRY/EXIT Missing an EFI_ENTRY() or doubling up EFI_EXIT() leads to non-obvious crashes. Let's add some error checking. Signed-off-by: Rob Clark [agraf: fix bogus assert() and fix app_gd breakage] Signed-off-by: Alexander Graf --- include/efi_loader.h | 17 +++++++++------- lib/efi_loader/efi_boottime.c | 45 +++++++++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index eb16c14b699..4262d0ac6b9 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -15,11 +15,14 @@ #include +int __efi_entry_check(void); +int __efi_exit_check(void); + /* * Enter the u-boot world from UEFI: */ #define EFI_ENTRY(format, ...) do { \ - efi_restore_gd(); \ + assert(__efi_entry_check()); \ debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ } while(0) @@ -29,7 +32,8 @@ #define EFI_EXIT(ret) ({ \ efi_status_t _r = ret; \ debug("EFI: Exit: %s: %u\n", __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ - efi_exit_func(_r); \ + assert(__efi_exit_check()); \ + _r; \ }) /* @@ -37,9 +41,9 @@ */ #define EFI_CALL(exp) do { \ debug("EFI: Call: %s\n", #exp); \ - efi_exit_func(EFI_SUCCESS); \ + assert(__efi_exit_check()); \ exp; \ - efi_restore_gd(); \ + assert(__efi_entry_check()); \ debug("EFI: Return From: %s\n", #exp); \ } while(0) @@ -139,10 +143,9 @@ void efi_timer_check(void); void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info); /* Called once to store the pristine gd pointer */ void efi_save_gd(void); -/* Called from EFI_ENTRY on callback entry to put gd into the gd register */ +/* Special case handler for error/abort that just tries to dtrt to get + * back to u-boot world */ void efi_restore_gd(void); -/* Called from EFI_EXIT on callback exit to restore the gd register */ -efi_status_t efi_exit_func(efi_status_t ret); /* Call this to relocate the runtime section to an address space */ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); /* Call this to set the current device name */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 849d2298213..aa8d0d12d01 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -49,6 +49,30 @@ static struct efi_configuration_table __efi_runtime_data efi_conf_table[2]; static volatile void *efi_gd, *app_gd; #endif +static int entry_count; + +/* Called on every callback entry */ +int __efi_entry_check(void) +{ + int ret = entry_count++ == 0; +#ifdef CONFIG_ARM + assert(efi_gd); + app_gd = gd; + gd = efi_gd; +#endif + return ret; +} + +/* Called on every callback exit */ +int __efi_exit_check(void) +{ + int ret = --entry_count == 0; +#ifdef CONFIG_ARM + gd = app_gd; +#endif + return ret; +} + /* Called from do_bootefi_exec() */ void efi_save_gd(void) { @@ -57,30 +81,21 @@ void efi_save_gd(void) #endif } -/* Called on every callback entry */ +/* + * Special case handler for error/abort that just forces things back + * to u-boot world so we can dump out an abort msg, without any care + * about returning back to UEFI world. + */ void efi_restore_gd(void) { #ifdef CONFIG_ARM /* Only restore if we're already in EFI context */ if (!efi_gd) return; - - if (gd != efi_gd) - app_gd = gd; gd = efi_gd; #endif } -/* Called on every callback exit */ -efi_status_t efi_exit_func(efi_status_t ret) -{ -#ifdef CONFIG_ARM - gd = app_gd; -#endif - - return ret; -} - /* Low 32 bit */ #define EFI_LOW32(a) (a & 0xFFFFFFFFULL) /* High 32 bit */ @@ -733,7 +748,9 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(info->exit_status); } + __efi_exit_check(); entry(image_handle, &systab); + __efi_entry_check(); /* Should usually never get here */ return EFI_EXIT(EFI_SUCCESS); -- cgit v1.3.1 From af65db85b82b161f037e0889ae58bf461217b3f1 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 27 Jul 2017 08:04:19 -0400 Subject: efi_loader: indent entry/exit prints to show nesting level This should make it easier to see when a callback back to UEFI world calls back in to the u-boot world, and generally match up EFI_ENTRY() and EFI_EXIT() calls. Signed-off-by: Rob Clark [agraf: remove static from const var] Signed-off-by: Alexander Graf --- include/efi_loader.h | 12 ++++++++---- lib/efi_loader/efi_boottime.c | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/efi_loader.h b/include/efi_loader.h index 4262d0ac6b9..037cc7c5434 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -17,13 +17,16 @@ int __efi_entry_check(void); int __efi_exit_check(void); +const char *__efi_nesting_inc(void); +const char *__efi_nesting_dec(void); /* * Enter the u-boot world from UEFI: */ #define EFI_ENTRY(format, ...) do { \ assert(__efi_entry_check()); \ - debug("EFI: Entry %s(" format ")\n", __func__, ##__VA_ARGS__); \ + debug("%sEFI: Entry %s(" format ")\n", __efi_nesting_inc(), \ + __func__, ##__VA_ARGS__); \ } while(0) /* @@ -31,7 +34,8 @@ int __efi_exit_check(void); */ #define EFI_EXIT(ret) ({ \ efi_status_t _r = ret; \ - debug("EFI: Exit: %s: %u\n", __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ + debug("%sEFI: Exit: %s: %u\n", __efi_nesting_dec(), \ + __func__, (u32)(_r & ~EFI_ERROR_MASK)); \ assert(__efi_exit_check()); \ _r; \ }) @@ -40,11 +44,11 @@ int __efi_exit_check(void); * Callback into UEFI world from u-boot: */ #define EFI_CALL(exp) do { \ - debug("EFI: Call: %s\n", #exp); \ + debug("%sEFI: Call: %s\n", __efi_nesting_inc(), #exp); \ assert(__efi_exit_check()); \ exp; \ assert(__efi_entry_check()); \ - debug("EFI: Return From: %s\n", #exp); \ + debug("%sEFI: Return From: %s\n", __efi_nesting_dec(), #exp); \ } while(0) extern struct efi_runtime_services efi_runtime_services; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index aa8d0d12d01..59479eddb9d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -50,6 +50,7 @@ static volatile void *efi_gd, *app_gd; #endif static int entry_count; +static int nesting_level; /* Called on every callback entry */ int __efi_entry_check(void) @@ -96,6 +97,28 @@ void efi_restore_gd(void) #endif } +/* + * Two spaces per indent level, maxing out at 10.. which ought to be + * enough for anyone ;-) + */ +static const char *indent_string(int level) +{ + const char *indent = " "; + const int max = strlen(indent); + level = min(max, level * 2); + return &indent[max - level]; +} + +const char *__efi_nesting_inc(void) +{ + return indent_string(nesting_level++); +} + +const char *__efi_nesting_dec(void) +{ + return indent_string(--nesting_level); +} + /* Low 32 bit */ #define EFI_LOW32(a) (a & 0xFFFFFFFFULL) /* High 32 bit */ @@ -748,9 +771,11 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(info->exit_status); } + __efi_nesting_dec(); __efi_exit_check(); entry(image_handle, &systab); __efi_entry_check(); + __efi_nesting_inc(); /* Should usually never get here */ return EFI_EXIT(EFI_SUCCESS); -- cgit v1.3.1