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 diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 771300e..2a56ad7 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -54,14 +54,6 @@ static struct efi_device_path_file_path bootefi_device_path[] = { } }; -static efi_status_t EFIAPI bootefi_open_dp(void *handle, efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) -{ - *protocol_interface = bootefi_device_path; - return EFI_SUCCESS; -} - /* The EFI loaded_image interface for the image executed via "bootefi" */ static struct efi_loaded_image loaded_image_info = { .device_handle = bootefi_device_path, @@ -78,7 +70,7 @@ static struct efi_object loaded_image_info_obj = { * return handle which points to loaded_image_info */ .guid = &efi_guid_loaded_image, - .open = &efi_return_handle, + .protocol_interface = &loaded_image_info, }, { /* @@ -86,7 +78,7 @@ static struct efi_object loaded_image_info_obj = { * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path, }, }, }; @@ -99,7 +91,7 @@ static struct efi_object bootefi_device_obj = { /* When asking for the device path interface, return * bootefi_device_path */ .guid = &efi_guid_device_path, - .open = &bootefi_open_dp, + .protocol_interface = bootefi_device_path } }, }; diff --git a/include/efi_loader.h b/include/efi_loader.h index 99619f5..c620652 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 */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 27e51a2..5c72f92 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 39e602a..3ad7706 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 286ad83..db1fd18 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 d4c62e6..f961407 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 604ac6e..0b949d8 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5c72f92..22e9e60 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 v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index f071b36..42cd47f 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 22e9e60..a6325ba 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index a6325ba..0ad7ade 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0ad7ade..0914b71 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0914b71..91db12e 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 91db12e..08eddbd 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 08eddbd..1f72efe 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1f72efe..6f09329 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index c620652..989e580 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 v0.10.2 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 diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2a56ad7..8453d90 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 989e580..6ea6e9e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -37,16 +37,6 @@ 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 * protocol GUID to the respective protocol interface */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6f09329..339fe55 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 v0.10.2 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 diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 8453d90..dcae253 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 42cd47f..ea63e80 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 6ea6e9e..d7847d2 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 fa8b91a..3fc2371 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 0000000..a7a5130 --- /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 v0.10.2 From b06d8ac39e0f36db4221367623f1908317daa60f Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 4 Jul 2017 23:15:21 +0200 Subject: bootefi: allow return without EFI_BOOT_SERVICES.Exit The Unified Extensible Firmware Interface Specification, version 2.7, defines in chapter 2.1.2 - UEFI Application that an EFI application may either directly return or call EFI_BOOT_SERVICES.Exit(). Unfortunately U-Boot makes the incorrect assumption that EFI_BOOT_SERVICES.Exit() is always called. So the following application leads to a memory exception on the aarch64 architecture when returning: EFI_STATUS efi_main( EFI_HANDLE handle, EFI_SYSTEM_TABlE systable) { return EFI_SUCCESS; } With this patch the entry point is stored in the image handle. The new wrapper function do_enter is used to call the EFI entry point. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index dcae253..e6487da 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -147,15 +147,28 @@ static void *copy_fdt(void *fdt) return new_fdt; } +static ulong efi_do_enter(void *image_handle, + struct efi_system_table *st, + asmlinkage ulong (*entry)(void *image_handle, + struct efi_system_table *st)) +{ + efi_status_t ret = EFI_LOAD_ERROR; + + if (entry) + ret = entry(image_handle, st); + st->boottime->exit(image_handle, ret, 0, NULL); + return ret; +} + #ifdef CONFIG_ARM64 -static unsigned long efi_run_in_el2(ulong (*entry)(void *image_handle, - struct efi_system_table *st), void *image_handle, - struct efi_system_table *st) +static unsigned long efi_run_in_el2(asmlinkage ulong (*entry)( + void *image_handle, struct efi_system_table *st), + void *image_handle, struct efi_system_table *st) { /* Enable caches again */ dcache_enable(); - return entry(image_handle, st); + return efi_do_enter(image_handle, st, entry); } #endif @@ -260,7 +273,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) } #endif - return entry(&loaded_image_info, &systab); + return efi_do_enter(&loaded_image_info, &systab, entry); } -- cgit v0.10.2 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 diff --git a/include/efi.h b/include/efi.h index 3d58780..02b78b3 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 v0.10.2 From 1da1bac477581fdb8aa093b6ed842874ffc5916d Mon Sep 17 00:00:00 2001 From: "xypron.glpk@gmx.de" Date: Tue, 4 Jul 2017 23:15:23 +0200 Subject: efi_loader: provide meaningful status code Currenty any EFI status other than EFI_SUCCESS is reported as Application terminated, r = -22 With the patch the status code returned by the EFI application is printed. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index e6487da..08c60e6 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -253,8 +253,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); if (setjmp(&loaded_image_info.exit_jmp)) { - efi_status_t status = loaded_image_info.exit_status; - return status == EFI_SUCCESS ? 0 : -EINVAL; + return loaded_image_info.exit_status; } #ifdef CONFIG_ARM64 @@ -282,7 +281,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *saddr, *sfdt; unsigned long addr, fdt_addr = 0; - int r = 0; + unsigned long r; if (argc < 2) return CMD_RET_USAGE; @@ -307,12 +306,13 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("## Starting EFI application at %08lx ...\n", addr); r = do_bootefi_exec((void *)addr, (void*)fdt_addr); - printf("## Application terminated, r = %d\n", r); + printf("## Application terminated, r = %lu\n", + r & ~EFI_ERROR_MASK); - if (r != 0) - r = 1; - - return r; + if (r != EFI_SUCCESS) + return 1; + else + return 0; } #ifdef CONFIG_SYS_LONGHELP -- cgit v0.10.2 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 diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 3ad7706..7f89704 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index db2ae19..5c53aaa 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 v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index ea63e80..a1f8221 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 339fe55..79eb0d9 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 v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index a1f8221..a3b8e04 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 d7847d2..3d18bfb 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 79eb0d9..bdcca38 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 v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index a3b8e04..d52eea4 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 3d18bfb..b922720 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 bdcca38..f04d9eb 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index b922720..c364015 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 f04d9eb..30227cc 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index c364015..342e960 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 30227cc..4cd06b3 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 v0.10.2 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 diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 08c60e6..e9f14d5 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 342e960..2abb6b8 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 4cd06b3..b8dfcea 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 8ef7326..dbe98ac 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b8dfcea..a89a629 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 v0.10.2 From 3e433e960887a480f520d4b82ff8d3df3e037ffb Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jul 2017 07:59:09 -0400 Subject: efi_loader: EFI file paths should be DOS style shim.efi, for example, actually tries to parse this, but is expecting backslashes. Signed-off-by: Rob Clark Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index e9f14d5..9542457 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -339,7 +339,7 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) { __maybe_unused struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ - char *colon; + char *colon, *s; #if defined(CONFIG_BLK) || CONFIG_IS_ENABLED(ISO_PARTITION) desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); @@ -384,5 +384,9 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) } else { snprintf(devname, sizeof(devname), "%s", path); } + /* DOS style file path: */ + s = devname; + while ((s = strchr(s, '/'))) + *s++ = '\\'; ascii2unicode(bootefi_image_path[0].str, devname); } -- cgit v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 2abb6b8..7818e1c 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 a89a629..e09f9da 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 v0.10.2 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 diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 9542457..b6dedec 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -230,7 +230,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) #ifdef CONFIG_PARTITIONS efi_disk_register(); #endif -#ifdef CONFIG_LCD +#if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO) efi_gop_register(); #endif #ifdef CONFIG_NET diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 3fc2371..30bf343 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 db1fd18..806cfae 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5c53aaa..c56653f 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index c56653f..f59e3ea 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index a7a5130..612e380 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e09f9da..7d45c18 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index dbe98ac..95e6323 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 v0.10.2 From 7cbc12415dad707b94d755311126059e5cdc65e3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 19 Jul 2017 19:37:22 +0200 Subject: efi_loader: initalize EFI object list only once If several EFI applications are executed in sequence we want to keep the content of the EFI object list. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index b6dedec..9526f6c 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -20,6 +20,8 @@ DECLARE_GLOBAL_DATA_PTR; +static uint8_t efi_obj_list_initalized; + /* * When booting using the "bootefi" command, we don't know which * physical device the file came from. So we create a pseudo-device @@ -104,6 +106,38 @@ static struct efi_object bootefi_device_obj = { }, }; +/* Initialize and populate EFI object list */ +static void efi_init_obj_list(void) +{ + efi_obj_list_initalized = 1; + + 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 +#if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO) + efi_gop_register(); +#endif +#ifdef CONFIG_NET + void *nethandle = loaded_image_info.device_handle; + efi_net_register(&nethandle); + + if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) + loaded_image_info.device_handle = nethandle; + else + loaded_image_info.device_handle = bootefi_device_path; +#endif +#ifdef CONFIG_GENERATE_SMBIOS_TABLE + efi_smbios_register(); +#endif + + /* Initialize EFI runtime services */ + efi_reset_system_init(); + efi_get_time_init(); +} + static void *copy_fdt(void *fdt) { u64 fdt_size = fdt_totalsize(fdt); @@ -223,32 +257,8 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) return -ENOENT; /* Initialize and populate EFI object list */ - 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 -#if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO) - efi_gop_register(); -#endif -#ifdef CONFIG_NET - void *nethandle = loaded_image_info.device_handle; - efi_net_register(&nethandle); - - if (!memcmp(bootefi_device_path[0].str, "N\0e\0t", 6)) - loaded_image_info.device_handle = nethandle; - else - loaded_image_info.device_handle = bootefi_device_path; -#endif -#ifdef CONFIG_GENERATE_SMBIOS_TABLE - efi_smbios_register(); -#endif - - /* Initialize EFI runtime services */ - efi_reset_system_init(); - efi_get_time_init(); + if (!efi_obj_list_initalized) + efi_init_obj_list(); /* Call our payload! */ debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); -- cgit v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index d52eea4..8f881d2 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 7818e1c..4bcd35a 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 7d45c18..e0aead4 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e0aead4..97be7b8 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 4bcd35a..40f6c89 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 40f6c89..f384cbb 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 v0.10.2 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 diff --git a/include/efi_api.h b/include/efi_api.h index 8f881d2..ec1b321 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 95e6323..5ebce4b 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 97be7b8..9a1a93f 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 7f89704..ed06485 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9a1a93f..17c531a 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 v0.10.2 From f4f9993f7ed0384f110324bb048a6cafb535378a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 26 Jul 2017 13:41:05 +0200 Subject: efi_loader: Fix configuration table override Before commit 7cbc12415d ("efi_loader: initalize EFI object list only once") we recreated the world on every bootefi invocation. That included the object tree as well as the configuration tables. Now however we don't recreate them, which means we must not explicitly override the configuration tables, as otherwise we may lose our SMBIOS table from the configuration table list on second bootefi invocation. This patch makes bootefi call our normal configuration table modification APIs to add/remove the FDT instead of recreating all tables from scratch. That way the SMBIOS table gets preserved across multiple invocations. Signed-off-by: Alexander Graf diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 9526f6c..d20775e 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -215,6 +215,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) ulong (*entry)(void *image_handle, struct efi_system_table *st) asmlinkage; ulong fdt_pages, fdt_size, fdt_start, fdt_end; + const efi_guid_t fdt_guid = EFI_FDT_GUID; bootm_headers_t img = { 0 }; /* @@ -233,9 +234,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) } /* Link to it in the efi tables */ - systab.tables[0].guid = EFI_FDT_GUID; - systab.tables[0].table = fdt; - systab.nr_tables = 1; + efi_install_configuration_table(&fdt_guid, fdt); /* And reserve the space in the memory map */ fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; @@ -248,7 +247,7 @@ static unsigned long do_bootefi_exec(void *efi, void *fdt) EFI_BOOT_SERVICES_DATA, true); } else { printf("WARNING: Invalid device tree, expect boot to fail\n"); - systab.nr_tables = 0; + efi_install_configuration_table(&fdt_guid, NULL); } /* Load the EFI payload */ -- cgit v0.10.2 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 diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index f59e3ea..9e079f1 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 v0.10.2 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 diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 612e380..4b2f43f 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index f384cbb..9700a88 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 9700a88..eb16c14 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 17c531a..849d229 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index eb16c14..4262d0a 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 849d229..aa8d0d1 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 v0.10.2 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 4262d0a..037cc7c 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 aa8d0d1..59479ed 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 v0.10.2