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 --- lib/efi_loader/efi_boottime.c | 18 ++++++++++++++---- lib/efi_loader/efi_disk.c | 29 +++-------------------------- lib/efi_loader/efi_gop.c | 2 +- lib/efi_loader/efi_image_loader.c | 8 -------- lib/efi_loader/efi_net.c | 30 +++--------------------------- 5 files changed, 21 insertions(+), 66 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 27e51a253f..5c72f92474 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -442,7 +442,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, .protocols = { { .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, }, }, }; @@ -452,6 +451,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, EFI_ENTRY("%d, %p, %p, %p, %ld, %p", boot_policy, parent_image, file_path, source_buffer, source_size, image_handle); info = malloc(sizeof(*info)); + loaded_image_info_obj.protocols[0].protocol_interface = info; obj = malloc(sizeof(loaded_image_info_obj)); memset(info, 0, sizeof(*info)); memcpy(obj, &loaded_image_info_obj, sizeof(loaded_image_info_obj)); @@ -723,6 +723,13 @@ static efi_status_t EFIAPI efi_open_protocol( EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, protocol_interface, agent_handle, controller_handle, attributes); + + if (!protocol_interface && attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + r = EFI_INVALID_PARAMETER; + goto out; + } + list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; efiobj = list_entry(lhandle, struct efi_object, link); @@ -736,9 +743,12 @@ static efi_status_t EFIAPI efi_open_protocol( if (!hprotocol) break; if (!guidcmp(hprotocol, protocol)) { - r = handler->open(handle, protocol, - protocol_interface, agent_handle, - controller_handle, attributes); + if (attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { + *protocol_interface = + handler->protocol_interface; + } + r = EFI_SUCCESS; goto out; } } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 39e602a868..3ad7706472 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -35,29 +35,6 @@ struct efi_disk_obj { const struct blk_desc *desc; }; -static efi_status_t EFIAPI efi_disk_open_block(void *handle, - efi_guid_t *protocol, void **protocol_interface, - void *agent_handle, void *controller_handle, - uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = &diskobj->ops; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_disk_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_disk_obj *diskobj = handle; - - *protocol_interface = diskobj->dp; - - return EFI_SUCCESS; -} - static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this, char extended_verification) { @@ -210,10 +187,11 @@ static void efi_disk_add_dev(const char *name, diskobj = calloc(1, objlen); /* Fill in object data */ + dp = (void *)&diskobj[1]; diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].open = efi_disk_open_block; + diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; diskobj->parent.protocols[1].guid = &efi_guid_device_path; - diskobj->parent.protocols[1].open = efi_disk_open_dp; + diskobj->parent.protocols[1].protocol_interface = dp; diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename; @@ -230,7 +208,6 @@ static void efi_disk_add_dev(const char *name, diskobj->ops.media = &diskobj->media; /* Fill in device path */ - dp = (void*)&diskobj[1]; diskobj->dp = dp; dp[0].dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE; dp[0].dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH; diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 286ad83097..db1fd18a34 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -172,7 +172,7 @@ int efi_gop_register(void) /* Fill in object data */ gopobj->parent.protocols[0].guid = &efi_gop_guid; - gopobj->parent.protocols[0].open = efi_return_handle; + gopobj->parent.protocols[0].protocol_interface = &gopobj->ops; gopobj->parent.handle = &gopobj->ops; gopobj->ops.query_mode = gop_query_mode; gopobj->ops.set_mode = gop_set_mode; diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index d4c62e677c..f961407f50 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -18,14 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; -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) -{ - *protocol_interface = handle; - return EFI_SUCCESS; -} - static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, unsigned long rel_size, void *efi_reloc) { diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 604ac6e040..0b949d86e8 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -199,30 +199,6 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI efi_net_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->dp_mac; - - return EFI_SUCCESS; -} - -static efi_status_t EFIAPI efi_net_open_pxe(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - struct efi_simple_network *net = handle; - struct efi_net_obj *netobj = container_of(net, struct efi_net_obj, net); - - *protocol_interface = &netobj->pxe; - - return EFI_SUCCESS; -} - void efi_net_set_dhcp_ack(void *pkt, int len) { int maxsize = sizeof(*dhcp_ack); @@ -258,11 +234,11 @@ int efi_net_register(void **handle) /* Fill in object data */ netobj->parent.protocols[0].guid = &efi_net_guid; - netobj->parent.protocols[0].open = efi_return_handle; + netobj->parent.protocols[0].protocol_interface = &netobj->net; netobj->parent.protocols[1].guid = &efi_guid_device_path; - netobj->parent.protocols[1].open = efi_net_open_dp; + netobj->parent.protocols[1].protocol_interface = &netobj->dp_mac; netobj->parent.protocols[2].guid = &efi_pxe_guid; - netobj->parent.protocols[2].open = efi_net_open_pxe; + netobj->parent.protocols[2].protocol_interface = &netobj->pxe; netobj->parent.handle = &netobj->net; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop; -- cgit v1.2.3 From 69baec67816bd2b3d491134f4509707e89054d48 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:15 +0200 Subject: efi_loader: efi_open_protocol: parameter checks Add all parameter checks for function efi_open_protocol that do not depend on a locking table. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5c72f92474..22e9e6001d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -718,15 +718,35 @@ static efi_status_t EFIAPI efi_open_protocol( { struct list_head *lhandle; int i; - efi_status_t r = EFI_UNSUPPORTED; + efi_status_t r = EFI_INVALID_PARAMETER; EFI_ENTRY("%p, %p, %p, %p, %p, 0x%x", handle, protocol, protocol_interface, agent_handle, controller_handle, attributes); - if (!protocol_interface && attributes != - EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { - r = EFI_INVALID_PARAMETER; + if (!handle || !protocol || + (!protocol_interface && attributes != + EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) { + goto out; + } + + switch (attributes) { + case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: + case EFI_OPEN_PROTOCOL_GET_PROTOCOL: + case EFI_OPEN_PROTOCOL_TEST_PROTOCOL: + break; + case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: + if (controller_handle == handle) + goto out; + case EFI_OPEN_PROTOCOL_BY_DRIVER: + case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE: + if (controller_handle == NULL) + goto out; + case EFI_OPEN_PROTOCOL_EXCLUSIVE: + if (agent_handle == NULL) + goto out; + break; + default: goto out; } @@ -752,8 +772,11 @@ static efi_status_t EFIAPI efi_open_protocol( goto out; } } + goto unsupported; } +unsupported: + r = EFI_UNSUPPORTED; out: return EFI_EXIT(r); } -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 54 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 22e9e6001d..a6325ba9d8 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.2.3 From 4b6ed0d7a1d915524dd1ecccf023d519d7022a49 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:17 +0200 Subject: efi_loader: implement UninstallProtocolInterface Without the patch efi_uninstall_protocol_interface always returns an error. With the patch protocols without interface can be uninstalled. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a6325ba9d8..0ad7ade79c 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -371,8 +371,44 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, efi_guid_t *protocol, void *protocol_interface) { + struct list_head *lhandle; + int i; + efi_status_t r = EFI_NOT_FOUND; + EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); - return EFI_EXIT(EFI_NOT_FOUND); + + if (!handle || !protocol) { + r = EFI_INVALID_PARAMETER; + goto out; + } + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != handle) + continue; + + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + struct efi_handler *handler = &efiobj->protocols[i]; + const efi_guid_t *hprotocol = handler->guid; + + if (!hprotocol) + continue; + if (!guidcmp(hprotocol, protocol)) { + if (handler->protocol_interface) { + r = EFI_ACCESS_DENIED; + } else { + handler->guid = 0; + r = EFI_SUCCESS; + } + goto out; + } + } + } + +out: + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, @@ -813,7 +849,7 @@ static efi_status_t EFIAPI efi_open_protocol( struct efi_handler *handler = &efiobj->protocols[i]; const efi_guid_t *hprotocol = handler->guid; if (!hprotocol) - break; + continue; if (!guidcmp(hprotocol, protocol)) { if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { -- cgit v1.2.3 From 8bee5a3c1365098f293305bf6744482cfe85e51d Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:18 +0200 Subject: efi_loader: refactor efi_install_protocol_interface For the implementation of InstallMultipleProtocolInterfaces we need to call efi_install_protocol_interface. In internal calls we should not pass through EFI_EXIT. The patch introduces a wrapper function efi_install_protocol_interface_ext. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0ad7ade79c..0914b71997 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -307,9 +307,6 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, int i; efi_status_t r; - EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, - protocol_interface); - if (!handle || !protocol || protocol_interface_type != EFI_NATIVE_INTERFACE) { r = EFI_INVALID_PARAMETER; @@ -356,7 +353,19 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, } r = EFI_INVALID_PARAMETER; out: - return EFI_EXIT(r); + return r; +} + +static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, + efi_guid_t *protocol, int protocol_interface_type, + void *protocol_interface) +{ + EFI_ENTRY("%p, %p, %d, %p", handle, protocol, protocol_interface_type, + protocol_interface); + + return EFI_EXIT(efi_install_protocol_interface(handle, protocol, + protocol_interface_type, + protocol_interface)); } static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, @@ -894,7 +903,7 @@ static const struct efi_boot_services efi_boot_services = { .signal_event = efi_signal_event, .close_event = efi_close_event, .check_event = efi_check_event, - .install_protocol_interface = efi_install_protocol_interface, + .install_protocol_interface = efi_install_protocol_interface_ext, .reinstall_protocol_interface = efi_reinstall_protocol_interface, .uninstall_protocol_interface = efi_uninstall_protocol_interface, .handle_protocol = efi_handle_protocol, -- cgit v1.2.3 From 3d8e1456086f28d00320bc6da25a3b15ca8616c7 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:19 +0200 Subject: efi_loader: refactor efi_uninstall_protocol_interface For the implementation of UninstallMultipleProtocolInterfaces we need to call efi_uninstall_protocol_interface. In internal calls we should not pass through EFI_EXIT. The patch introduces a wrapper function efi_uninstall_protocol_interface_ext. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0914b71997..91db12e774 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -384,8 +384,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, int i; efi_status_t r = EFI_NOT_FOUND; - EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); - if (!handle || !protocol) { r = EFI_INVALID_PARAMETER; goto out; @@ -417,7 +415,16 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, } out: - return EFI_EXIT(r); + return r; +} + +static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, + efi_guid_t *protocol, void *protocol_interface) +{ + EFI_ENTRY("%p, %p, %p", handle, protocol, protocol_interface); + + return EFI_EXIT(efi_uninstall_protocol_interface(handle, protocol, + protocol_interface)); } static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, @@ -905,7 +912,7 @@ static const struct efi_boot_services efi_boot_services = { .check_event = efi_check_event, .install_protocol_interface = efi_install_protocol_interface_ext, .reinstall_protocol_interface = efi_reinstall_protocol_interface, - .uninstall_protocol_interface = efi_uninstall_protocol_interface, + .uninstall_protocol_interface = efi_uninstall_protocol_interface_ext, .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify, -- cgit v1.2.3 From 58b83586065f9b22b80b5a6ff2c1270715b4128b Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:20 +0200 Subject: efi_loader: implement InstallMultipleProtocolInterfaces Implement InstallMultipleProtocolInterfaces in function efi_install_multiple_protocol_interfaces by repeatedly calling efi_install_protocol_interface. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 91db12e774..08eddbd376 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -783,7 +783,44 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( void **handle, ...) { EFI_ENTRY("%p", handle); - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + + va_list argptr; + efi_guid_t *protocol; + void *protocol_interface; + efi_status_t r = EFI_SUCCESS; + int i = 0; + + if (!handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + va_start(argptr, handle); + for (;;) { + protocol = va_arg(argptr, efi_guid_t*); + if (!protocol) + break; + protocol_interface = va_arg(argptr, void*); + r = efi_install_protocol_interface(handle, protocol, + EFI_NATIVE_INTERFACE, + protocol_interface); + if (r != EFI_SUCCESS) + break; + i++; + } + va_end(argptr); + if (r == EFI_SUCCESS) + return EFI_EXIT(r); + + /* If an error occured undo all changes. */ + va_start(argptr, handle); + for (; i; --i) { + protocol = va_arg(argptr, efi_guid_t*); + protocol_interface = va_arg(argptr, void*); + efi_uninstall_protocol_interface(handle, protocol, + protocol_interface); + } + va_end(argptr); + + return EFI_EXIT(r); } static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( -- cgit v1.2.3 From 26329584f350d2bd2a4125a645a6f5821019808b Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:21 +0200 Subject: efi_loader: refactor efi_locate_handle To implement LocateHandleBuffer we need to call efi_locate_handle internally without running through EFI_EXIT. So put EFI_ENTRY and EFI_EXIT into a new wrapper function efi_locate_handle_ext. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 08eddbd376..1f72efe7c3 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -466,9 +466,6 @@ static efi_status_t EFIAPI efi_locate_handle( struct list_head *lhandle; unsigned long size = 0; - EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, - buffer_size, buffer); - /* Count how much space we need */ list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; @@ -480,7 +477,7 @@ static efi_status_t EFIAPI efi_locate_handle( if (*buffer_size < size) { *buffer_size = size; - return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + return EFI_BUFFER_TOO_SMALL; } /* Then fill the array */ @@ -493,7 +490,19 @@ static efi_status_t EFIAPI efi_locate_handle( } *buffer_size = size; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; +} + +static efi_status_t EFIAPI efi_locate_handle_ext( + enum efi_locate_search_type search_type, + efi_guid_t *protocol, void *search_key, + unsigned long *buffer_size, efi_handle_t *buffer) +{ + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, + buffer_size, buffer); + + return EFI_EXIT(efi_locate_handle(search_type, protocol, search_key, + buffer_size, buffer)); } static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, @@ -953,7 +962,7 @@ static const struct efi_boot_services efi_boot_services = { .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify, - .locate_handle = efi_locate_handle, + .locate_handle = efi_locate_handle_ext, .locate_device_path = efi_locate_device_path, .install_configuration_table = efi_install_configuration_table_ext, .load_image = efi_load_image, -- cgit v1.2.3 From c2e703f903924065ab099385cd2416032526c50a Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 11 Jul 2017 22:06:22 +0200 Subject: efi_loader: implement LocateHandleBuffer UEFI boot service LocateHandleBuffer is implemented by calling efi_allocate_handle and efi_locate_handle. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1f72efe7c3..6f093290eb 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -758,9 +758,32 @@ static efi_status_t EFIAPI efi_locate_handle_buffer( efi_guid_t *protocol, void *search_key, unsigned long *no_handles, efi_handle_t **buffer) { + efi_status_t r; + unsigned long buffer_size = 0; + EFI_ENTRY("%d, %p, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); - return EFI_EXIT(EFI_NOT_FOUND); + + if (!no_handles || !buffer) { + r = EFI_INVALID_PARAMETER; + goto out; + } + *no_handles = 0; + *buffer = NULL; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r != EFI_BUFFER_TOO_SMALL) + goto out; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size, + (void **)buffer); + if (r != EFI_SUCCESS) + goto out; + r = efi_locate_handle(search_type, protocol, search_key, &buffer_size, + *buffer); + if (r == EFI_SUCCESS) + *no_handles = buffer_size / sizeof(void *); +out: + return EFI_EXIT(r); } static struct efi_class_map efi_class_maps[] = { -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6f093290eb..339fe55cde 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.2.3 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 --- lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_device_path_to_text.c | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 lib/efi_loader/efi_device_path_to_text.c (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index fa8b91a526..3fc2371896 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 0000000000..a7a513047f --- /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.2.3 From 70bfcdc6bb6f969babd69efc49e1dc7a1faeca54 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 20 Jun 2017 19:10:27 +0000 Subject: efi_loader: disk: iterate only over valid block devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The efi_loader currently stops iterating over the available block devices stopping at the first device that fails. This may imply that no block device is found. With the patch efi_loader only iterates over valid devices. It is based on patch 06d592bf52f6 (dm: core: Add uclass_first/next_device_check()) which is currently in u-boot-dm.git. For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; }; This device does not exist on the board and cannot be initialized. Without the patch: => bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail mmc_init: -95, time 1806 Found 0 disks Hello, world! ## Application terminated, r = 0 With the patch: => bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail mmc_init: -95, time 1806 Scanning disk mmc@70000.blk... Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Scanning disk mmc@74000.blk... Found 3 disks Hello, world! ## Application terminated, r = 0 Signed-off-by: Heinrich Schuchardt Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 3ad7706472..7f8970496f 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -266,9 +266,9 @@ int efi_disk_register(void) #ifdef CONFIG_BLK struct udevice *dev; - for (uclass_first_device(UCLASS_BLK, &dev); + for (uclass_first_device_check(UCLASS_BLK, &dev); dev; - uclass_next_device(&dev)) { + uclass_next_device_check(&dev)) { struct blk_desc *desc = dev_get_uclass_platdata(dev); const char *if_typename = dev->driver->name; -- cgit v1.2.3 From 71275a3e985db60b53b381f5253fdb15c663e18e Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Fri, 14 Jul 2017 19:12:39 +0200 Subject: efi_memory: avoid NULL dereference in efi_free_pool If efi_free_pool is called with argument NULL an illegal memory access occurs. So let's check the parameter on entry. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index db2ae19f59..5c53aaafdb 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -379,6 +379,9 @@ efi_status_t efi_free_pool(void *buffer) efi_status_t r; struct efi_pool_allocation *alloc; + if (buffer == NULL) + return EFI_INVALID_PARAMETER; + alloc = container_of(buffer, struct efi_pool_allocation, data); /* Sanity check, was the supplied address returned by allocate_pool */ assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 339fe55cde..79eb0d98be 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 195 ++++++++++++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 62 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 79eb0d98be..bdcca38a9f 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index bdcca38a9f..f04d9eb341 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f04d9eb341..30227cc56c 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 30227cc56c..4cd06b3c4c 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 2 +- lib/efi_loader/efi_console.c | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4cd06b3c4c..b8dfceae0c 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 8ef7326fef..dbe98ac08b 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.2.3 From 8787b02e32dc8bcf7ed432adcb0d246c5c844985 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 18 Jul 2017 20:17:23 +0200 Subject: efi_loader: correctly implement 100ns conversion In efi_set_timer we receive the trigger time in intervals of 100 ns. We should convert it to intervals of 1000 ns by 64bit division. The patch supplies function efi_div10 that uses multiplication to implement the missing 64 bit division. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 49 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b8dfceae0c..a89a629406 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -81,6 +81,39 @@ efi_status_t efi_exit_func(efi_status_t ret) return ret; } +/* Low 32 bit */ +#define EFI_LOW32(a) (a & 0xFFFFFFFFULL) +/* High 32 bit */ +#define EFI_HIGH32(a) (a >> 32) + +/* + * 64bit division by 10 implemented as multiplication by 1 / 10 + * + * Decimals of one tenth: 0x1 / 0xA = 0x0.19999... + */ +#define EFI_TENTH 0x199999999999999A +static u64 efi_div10(u64 a) +{ + u64 prod; + u64 rem; + u64 ret; + + ret = EFI_HIGH32(a) * EFI_HIGH32(EFI_TENTH); + prod = EFI_HIGH32(a) * EFI_LOW32(EFI_TENTH); + rem = EFI_LOW32(prod); + ret += EFI_HIGH32(prod); + prod = EFI_LOW32(a) * EFI_HIGH32(EFI_TENTH); + rem += EFI_LOW32(prod); + ret += EFI_HIGH32(prod); + prod = EFI_LOW32(a) * EFI_LOW32(EFI_TENTH); + rem += EFI_HIGH32(prod); + ret += EFI_HIGH32(rem); + /* Round to nearest integer */ + if (rem >= (1 << 31)) + ++ret; + return ret; +} + void efi_signal_event(struct efi_event *event) { if (event->signaled) @@ -244,7 +277,7 @@ void efi_timer_check(void) continue; if (efi_events[i].trigger_type == EFI_TIMER_PERIODIC) { efi_events[i].trigger_next += - efi_events[i].trigger_time / 10; + efi_events[i].trigger_time; efi_events[i].signaled = 0; } efi_signal_event(&efi_events[i]); @@ -255,15 +288,13 @@ void efi_timer_check(void) 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; - if (trigger32 < trigger_time) { - printf("WARNING: Truncating timer from %"PRIx64" to %x\n", - trigger_time, trigger32); - } + /* + * The parameter defines a multiple of 100ns. + * We use multiples of 1000ns. So divide by 10. + */ + trigger_time = efi_div10(trigger_time); for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { if (event != &efi_events[i]) @@ -278,7 +309,7 @@ efi_status_t efi_set_timer(struct efi_event *event, int type, case EFI_TIMER_PERIODIC: case EFI_TIMER_RELATIVE: event->trigger_next = - timer_get_us() + (trigger32 / 10); + timer_get_us() + trigger_time; break; default: return EFI_INVALID_PARAMETER; -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a89a629406..e09f9dac5c 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.2.3 From ca9193d2b163cd274144edddd29be20cdb5f99a3 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Fri, 21 Jul 2017 15:00:27 -0400 Subject: efi_loader: gop: fixes for CONFIG_DM_VIDEO without CONFIG_LCD Make EFI GOP support work with DM_VIDEO but without legacy LCD. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_gop.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 3fc2371896..30bf343a36 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -17,6 +17,7 @@ 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 efi_device_path_to_text.o obj-$(CONFIG_LCD) += efi_gop.o +obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index db1fd18a34..806cfaeea1 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -28,6 +28,7 @@ struct efi_gop_obj { struct efi_gop_mode mode; /* Fields we only have acces to during init */ u32 bpix; + void *fb; }; static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, @@ -71,7 +72,7 @@ static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, if (operation != EFI_BLT_BUFFER_TO_VIDEO) return EFI_EXIT(EFI_INVALID_PARAMETER); - fb = (void*)gd->fb_base; + fb = gopobj->fb; line_len16 = gopobj->info.width * sizeof(u16); line_len32 = gopobj->info.width * sizeof(u32); @@ -130,6 +131,7 @@ int efi_gop_register(void) struct efi_gop_obj *gopobj; u32 bpix, col, row; u64 fb_base, fb_size; + void *fb; #ifdef CONFIG_DM_VIDEO struct udevice *vdev; @@ -144,6 +146,7 @@ int efi_gop_register(void) row = video_get_ysize(vdev); fb_base = (uintptr_t)priv->fb; fb_size = priv->fb_size; + fb = priv->fb; #else int line_len; @@ -152,6 +155,7 @@ int efi_gop_register(void) row = panel_info.vl_row; fb_base = gd->fb_base; fb_size = lcd_get_size(&line_len); + fb = gd->fb_base; #endif switch (bpix) { @@ -200,6 +204,7 @@ int efi_gop_register(void) gopobj->info.pixels_per_scanline = col; gopobj->bpix = bpix; + gopobj->fb = fb; /* Hook up to the device list */ list_add_tail(&gopobj->parent.link, &efi_obj_list); -- cgit v1.2.3 From 0ecba5db85fb566bcbb3ba96fda85f26f78be22d Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Fri, 21 Jul 2017 19:04:33 +0200 Subject: efi_memory: do parameter checks first The parameter checks should be done first. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5c53aaafdb..c56653f497 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -407,6 +407,9 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, map_size = map_entries * sizeof(struct efi_mem_desc); + if (provided_map_size < map_size) + return EFI_BUFFER_TOO_SMALL; + *memory_map_size = map_size; if (descriptor_size) @@ -415,9 +418,6 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (provided_map_size < map_size) - return EFI_BUFFER_TOO_SMALL; - /* Copy list into array */ if (memory_map) { /* Return the list in ascending order */ -- cgit v1.2.3 From c6e3c3e68a240e7d503b7e4fee9ea6002e33f6a0 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Fri, 21 Jul 2017 19:05:44 +0200 Subject: efi_memory: return MapKey efi_get_memory_map should set a defined value for map_key. We later can introduce the test against this value in efi_exit_boot_services as required by the UEFI standard. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index c56653f497..f59e3ea327 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -431,6 +431,8 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, } } + *map_key = 0; + return EFI_SUCCESS; } -- cgit v1.2.3 From 09c5ab909c8abfe6a0ee654149345254c0dda13d Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Fri, 21 Jul 2017 19:12:08 +0200 Subject: efi_loader: implement ConvertDeviceNodeToText Move the logic for converting a node to text from efi_convert_device_path_to_text to convert_device_node_to_text. Provide a wrapper function convert_device_node_to_text_ext. As we use only shallow device paths so we can call directly call efi_device_node_to_text from efi_device_path_to_text. Add output for MAC addresses. Add output for not yet supported types/subtypes. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 121 +++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index a7a513047f..612e380617 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -9,59 +9,120 @@ #include #include -#define MEDIA_DEVICE_PATH 4 -#define FILE_PATH_MEDIA_DEVICE_PATH 4 +#define MAC_OUTPUT_LEN 22 +#define UNKNOWN_OUTPUT_LEN 23 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( +static 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; + int i; + + switch (device_node->type) { + case DEVICE_PATH_TYPE_END: + return NULL; + case DEVICE_PATH_TYPE_MESSAGING_DEVICE: + switch (device_node->sub_type) { + case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: { + struct efi_device_path_mac_addr *dp = + (struct efi_device_path_mac_addr *)device_node; - 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; + if (dp->if_type != 0 && dp->if_type != 1) + break; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + 2 * MAC_OUTPUT_LEN, + (void **)&buffer); + if (r != EFI_SUCCESS) + return NULL; + sprintf((char *)buffer, + "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", + dp->mac.addr[0], dp->mac.addr[1], + dp->mac.addr[2], dp->mac.addr[3], + dp->mac.addr[4], dp->mac.addr[5], + dp->if_type); + for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i) + buffer[i] = ((uint8_t *)buffer)[i]; + break; + } + } + case DEVICE_PATH_TYPE_MEDIA_DEVICE: + switch (device_node->sub_type) { + case DEVICE_PATH_SUB_TYPE_FILE_PATH: + buffer_size = device_node->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); + if (r != EFI_SUCCESS) + return NULL; + memcpy(buffer, device_node->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); + /* + * For all node types that we do not yet support return + * 'UNKNOWN(type,subtype)'. + */ + if (!buffer) { + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + 2 * UNKNOWN_OUTPUT_LEN, + (void **)&buffer); + if (r != EFI_SUCCESS) + return NULL; + sprintf((char *)buffer, + "UNKNOWN(%04x,%04x)", + device_node->type, + device_node->sub_type); + for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i) + buffer[i] = ((uint8_t *)buffer)[i]; } return buffer; } +static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( + struct efi_device_path_protocol *device_node, + bool display_only, + bool allow_shortcuts) +{ + uint16_t *buffer; + + EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts); + + buffer = efi_convert_device_node_to_text(device_node, display_only, + allow_shortcuts); + + EFI_EXIT(EFI_SUCCESS); + return buffer; +} + +static uint16_t EFIAPI *efi_convert_device_path_to_text( + struct efi_device_path_protocol *device_path, + bool display_only, + bool allow_shortcuts) +{ + uint16_t *buffer; + + EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts); + + /* + * Our device paths are all of depth one. So its is sufficient to + * to convert the first node. + */ + buffer = efi_convert_device_node_to_text(device_path, display_only, + allow_shortcuts); + + EFI_EXIT(EFI_SUCCESS); + 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_node_to_text = efi_convert_device_node_to_text_ext, .convert_device_path_to_text = efi_convert_device_path_to_text, }; -- cgit v1.2.3 From 661c8327a6a0d8738473aaa79ab165b9e4b0b714 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 20 Jul 2017 07:59:39 -0400 Subject: efi_loader: workaround for grub lsefi bug Patch has also been sent to fix grub to not ignore the error returned and treat protocol_buffer_count as valid. But that that might take a while to trickle into distro's, so this workaround might be useful. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e09f9dac5c..7d45c18ff7 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -866,6 +866,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, { EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, protocol_buffer_count); + *protocol_buffer_count = 0; return EFI_EXIT(EFI_OUT_OF_RESOURCES); } -- cgit v1.2.3 From ff925938c8bc38b4aa5a1d4f42effee36e7a4097 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Thu, 20 Jul 2017 05:26:07 +0200 Subject: efi_console: use EFIAPI for callback functions The call to efi_create_event requires notification functions flagged as EFIAPI. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_console.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index dbe98ac08b..95e632394f 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -429,11 +429,12 @@ struct efi_simple_input_interface efi_con_in = { static struct efi_event *console_timer_event; -static void efi_key_notify(struct efi_event *event, void *context) +static void EFIAPI efi_key_notify(struct efi_event *event, void *context) { } -static void efi_console_timer_notify(struct efi_event *event, void *context) +static void EFIAPI efi_console_timer_notify(struct efi_event *event, + void *context) { EFI_ENTRY("%p, %p", event, context); if (tstc()) -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 7d45c18ff7..e0aead47c9 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.2.3 From c0ebfc8664d9b533ce956547abb4377188bf7f07 Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Thu, 13 Jul 2017 23:24:32 +0200 Subject: efi_loader: implement ProtocolsPerHandle Boot service ProtocolsPerHandle is implemented in efi_protocols_per_handle. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 45 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e0aead47c9..97be7b82e4 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -865,10 +865,53 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, efi_guid_t ***protocol_buffer, unsigned long *protocol_buffer_count) { + unsigned long buffer_size; + struct efi_object *efiobj; + unsigned long i, j; + struct list_head *lhandle; + efi_status_t r; + EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, protocol_buffer_count); + + if (!handle || !protocol_buffer || !protocol_buffer_count) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + *protocol_buffer = NULL; *protocol_buffer_count = 0; - return EFI_EXIT(EFI_OUT_OF_RESOURCES); + list_for_each(lhandle, &efi_obj_list) { + efiobj = list_entry(lhandle, struct efi_object, link); + + if (efiobj->handle != handle) + continue; + + /* Count protocols */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + if (efiobj->protocols[i].guid) + ++*protocol_buffer_count; + } + /* Copy guids */ + if (*protocol_buffer_count) { + buffer_size = sizeof(efi_guid_t *) * + *protocol_buffer_count; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + buffer_size, + (void **)protocol_buffer); + if (r != EFI_SUCCESS) + return EFI_EXIT(r); + j = 0; + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) { + if (efiobj->protocols[i].guid) { + (*protocol_buffer)[j] = (void *) + efiobj->protocols[i].guid; + ++j; + } + } + } + break; + } + + return EFI_EXIT(EFI_SUCCESS); } static efi_status_t EFIAPI efi_locate_handle_buffer( -- cgit v1.2.3 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 --- lib/efi_loader/efi_console.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 95e632394f..5ebce4b544 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.2.3 From b5104821c1b7c084f908afd0f1d3fc3c506df3d0 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 25 Jul 2017 20:17:59 -0400 Subject: efi_loader: remove double EFI_EXIT() with efi_unsupported Probably this went unnoticed before, but it causes problems with addition of 804b1d73 ("efi_loader: log EFI return values too") Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 97be7b82e4..9a1a93fade 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -141,7 +141,7 @@ static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) static void EFIAPI efi_restore_tpl(UINTN old_tpl) { EFI_ENTRY("0x%zx", old_tpl); - EFI_EXIT(efi_unsupported(__func__)); + efi_unsupported(__func__); } static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, @@ -818,7 +818,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, { EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code, data_size, watchdog_data); - return EFI_EXIT(efi_unsupported(__func__)); + return efi_unsupported(__func__); } static efi_status_t EFIAPI efi_connect_controller( -- cgit v1.2.3 From 3304990ba4d4a4347d19f3c10cfeb2c69eb5fa05 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 25 Jul 2017 20:28:29 -0400 Subject: efi_loader: remove more double EFI_EXIT() in efi_disk.c Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 7f8970496f..ed06485e33 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -68,7 +68,7 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, /* We only support full block access */ if (buffer_size & (blksz - 1)) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; if (direction == EFI_DISK_READ) n = blk_dread(desc, lba, blocks, buffer); @@ -81,9 +81,9 @@ static efi_status_t EFIAPI efi_disk_rw_blocks(struct efi_block_io *this, debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks); if (n != blocks) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; - return EFI_EXIT(EFI_SUCCESS); + return EFI_SUCCESS; } static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this, -- cgit v1.2.3 From d98cdf6a9212ab2727eedb6781a46acaf23f9786 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 26 Jul 2017 13:41:04 +0200 Subject: efi_loader: Improve install_configuration_table The INSTALL_CONFIGURATION_TABLE callback also provides the ability to remove table entries. This patch adds that functionality. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9a1a93fade..17c531a480 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -630,6 +630,17 @@ static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, return EFI_EXIT(EFI_NOT_FOUND); } +/* Collapses configuration table entries, removing index i */ +static void efi_remove_configuration_table(int i) +{ + struct efi_configuration_table *this = &efi_conf_table[i]; + struct efi_configuration_table *next = &efi_conf_table[i+1]; + struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables]; + + memmove(this, next, (ulong)end - (ulong)next); + systab.nr_tables--; +} + efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table) { int i; @@ -637,11 +648,17 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table /* Check for guid override */ for (i = 0; i < systab.nr_tables; i++) { if (!guidcmp(guid, &efi_conf_table[i].guid)) { - efi_conf_table[i].table = table; + if (table) + efi_conf_table[i].table = table; + else + efi_remove_configuration_table(i); return EFI_SUCCESS; } } + if (!table) + return EFI_NOT_FOUND; + /* No override, check for overflow */ if (i >= ARRAY_SIZE(efi_conf_table)) return EFI_OUT_OF_RESOURCES; -- cgit v1.2.3 From a1b24823b6c22ede11d311b05ea862965ea86b0b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 26 Jul 2017 14:34:05 -0400 Subject: efi_loader: fix bug in efi_get_memory_map When booting shim -> fallback -> shim -> grub -> linux the memory map is a bit larger than the size linux passes in on the first call. But in the EFI_BUFFER_TOO_SMALL case we were not passing back the updated size to linux so it would loop forever. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index f59e3ea327..9e079f1fa3 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -407,11 +407,11 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, map_size = map_entries * sizeof(struct efi_mem_desc); + *memory_map_size = map_size; + if (provided_map_size < map_size) return EFI_BUFFER_TOO_SMALL; - *memory_map_size = map_size; - if (descriptor_size) *descriptor_size = sizeof(struct efi_mem_desc); -- cgit v1.2.3 From 6cfd5f133ac11becc0dd2c9b93e275af45ea384f Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 27 Jul 2017 11:28:33 -0400 Subject: efi_loader: add some missing breaks Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 612e380617..4b2f43f0c8 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -52,6 +52,7 @@ static uint16_t *efi_convert_device_node_to_text( break; } } + break; case DEVICE_PATH_TYPE_MEDIA_DEVICE: switch (device_node->sub_type) { case DEVICE_PATH_SUB_TYPE_FILE_PATH: @@ -63,6 +64,7 @@ static uint16_t *efi_convert_device_node_to_text( memcpy(buffer, device_node->data, buffer_size); break; } + break; } /* -- cgit v1.2.3 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 --- lib/efi_loader/efi_boottime.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 17c531a480..849d229821 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 45 +++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 849d229821..aa8d0d12d0 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.2.3 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 --- lib/efi_loader/efi_boottime.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index aa8d0d12d0..59479eddb9 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.2.3