diff options
-rw-r--r-- | cmd/nvedit_efi.c | 10 | ||||
-rw-r--r-- | drivers/rtc/rtc-lib.c | 2 | ||||
-rw-r--r-- | include/efi_loader.h | 28 | ||||
-rw-r--r-- | include/rtc.h | 8 | ||||
-rw-r--r-- | lib/efi_loader/Kconfig | 16 | ||||
-rw-r--r-- | lib/efi_loader/efi_bootmgr.c | 6 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 188 | ||||
-rw-r--r-- | lib/efi_loader/efi_runtime.c | 39 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 3 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_open_protocol.c | 205 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_register_notify.c | 21 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_rtc.c | 17 |
12 files changed, 459 insertions, 84 deletions
diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 2805e8182b..ff8eaa1aad 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -373,6 +373,8 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) for ( ; argc > 0; argc--, argv++) if (append_value(&value, &size, argv[0]) < 0) { + printf("## Failed to process an argument, %s\n", + argv[0]); ret = CMD_RET_FAILURE; goto out; } @@ -381,6 +383,7 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) len = utf8_utf16_strnlen(var_name, strlen(var_name)); var_name16 = malloc((len + 1) * 2); if (!var_name16) { + printf("## Out of memory\n"); ret = CMD_RET_FAILURE; goto out; } @@ -392,7 +395,12 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, value)); - ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); + if (ret == EFI_SUCCESS) { + ret = CMD_RET_SUCCESS; + } else { + printf("## Failed to set EFI variable\n"); + ret = CMD_RET_FAILURE; + } out: free(value); free(var_name16); diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 6528ddfebb..1f7bdade29 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -23,7 +23,7 @@ static const unsigned char rtc_days_in_month[] = { /* * The number of days in the month. */ -static int rtc_month_days(unsigned int month, unsigned int year) +int rtc_month_days(unsigned int month, unsigned int year) { return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); } diff --git a/include/efi_loader.h b/include/efi_loader.h index 43d3a08428..23ce732267 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -287,19 +287,37 @@ extern struct list_head efi_obj_list; extern struct list_head efi_events; /** + * struct efi_protocol_notification - handle for notified protocol + * + * When a protocol interface is installed for which an event was registered with + * the RegisterProtocolNotify() service this structure is used to hold the + * handle on which the protocol interface was installed. + * + * @link: link to list of all handles notified for this event + * @handle: handle on which the notified protocol interface was installed + */ +struct efi_protocol_notification { + struct list_head link; + efi_handle_t handle; +}; + +/** * efi_register_notify_event - event registered by RegisterProtocolNotify() * * The address of this structure serves as registration value. * - * @link: link to list of all registered events - * @event: registered event. The same event may registered for - * multiple GUIDs. - * @protocol: protocol for which the event is registered + * @link: link to list of all registered events + * @event: registered event. The same event may registered for multiple + * GUIDs. + * @protocol: protocol for which the event is registered + * @handles: linked list of all handles on which the notified protocol was + * installed */ struct efi_register_notify_event { struct list_head link; struct efi_event *event; efi_guid_t protocol; + struct list_head handles; }; /* List of all events registered by RegisterProtocolNotify() */ @@ -576,6 +594,8 @@ efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities); +efi_status_t __efi_runtime EFIAPI efi_set_time(struct efi_time *time); + #ifdef CONFIG_CMD_BOOTEFI_SELFTEST /* * Entry point for the tests of the EFI API. diff --git a/include/rtc.h b/include/rtc.h index 2c3a5743e3..b255bdc7a3 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -258,4 +258,12 @@ void rtc_to_tm(u64 time_t, struct rtc_time *time); */ unsigned long rtc_mktime(const struct rtc_time *time); +/** + * rtc_month_days() - The number of days in the month + * + * @month: month (January = 0) + * @year: year (4 digits) + */ +int rtc_month_days(unsigned int month, unsigned int year); + #endif /* _RTC_H_ */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index fc04ea39d0..cd5436c576 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -18,6 +18,22 @@ config EFI_LOADER if EFI_LOADER +config EFI_GET_TIME + bool "GetTime() runtime service" + depends on DM_RTC + default y + help + Provide the GetTime() runtime service at boottime. This service + can be used by an EFI application to read the real time clock. + +config EFI_SET_TIME + bool "SetTime() runtime service" + depends on EFI_GET_TIME + default n + help + Provide the SetTime() runtime service at boottime. This service + can be used by an EFI application to adjust the real time clock. + config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 7bf51874c1..43791422c8 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -149,8 +149,11 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle) ret = EFI_CALL(efi_load_image(true, efi_root, lo.file_path, NULL, 0, handle)); - if (ret != EFI_SUCCESS) + if (ret != EFI_SUCCESS) { + printf("Loading from Boot%04X '%ls' failed\n", n, + lo.label); goto error; + } attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; @@ -215,6 +218,7 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle) ret = try_load_entry(bootnext, handle); if (ret == EFI_SUCCESS) return ret; + printf("Loading from BootNext failed, falling back to BootOrder\n"); } } else { printf("Deleting BootNext failed\n"); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 54fff85e64..5c6bc691a5 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -921,6 +921,14 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) list_for_each_entry_safe(item, next, &efi_register_notify_events, link) { if (event == item->event) { + struct efi_protocol_notification *hitem, *hnext; + + /* Remove signaled handles */ + list_for_each_entry_safe(hitem, hnext, &item->handles, + link) { + list_del(&hitem->link); + free(hitem); + } list_del(&item->link); free(item); } @@ -1049,8 +1057,19 @@ efi_status_t efi_add_protocol(const efi_handle_t handle, /* Notify registered events */ list_for_each_entry(event, &efi_register_notify_events, link) { - if (!guidcmp(protocol, &event->protocol)) + if (!guidcmp(protocol, &event->protocol)) { + struct efi_protocol_notification *notif; + + notif = calloc(1, sizeof(*notif)); + if (!notif) { + list_del(&handler->link); + free(handler); + return EFI_OUT_OF_RESOURCES; + } + notif->handle = handle; + list_add_tail(¬if->link, &event->handles); efi_signal_event(event->event, true); + } } if (!guidcmp(&efi_guid_device_path, protocol)) @@ -1241,10 +1260,6 @@ static efi_status_t efi_uninstall_protocol goto out; /* Disconnect controllers */ efi_disconnect_all_drivers(efiobj, protocol, NULL); - if (!list_empty(&handler->open_infos)) { - r = EFI_ACCESS_DENIED; - goto out; - } /* Close protocol */ list_for_each_entry_safe(item, pos, &handler->open_infos, link) { if (item->info.attributes == @@ -1332,6 +1347,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify( item->event = event; memcpy(&item->protocol, protocol, sizeof(efi_guid_t)); + INIT_LIST_HEAD(&item->handles); list_add_tail(&item->link, &efi_register_notify_events); @@ -1359,7 +1375,6 @@ static int efi_search(enum efi_locate_search_type search_type, switch (search_type) { case ALL_HANDLES: return 0; - case BY_REGISTER_NOTIFY: case BY_PROTOCOL: ret = efi_search_protocol(handle, protocol, NULL); return (ret != EFI_SUCCESS); @@ -1370,6 +1385,27 @@ static int efi_search(enum efi_locate_search_type search_type, } /** + * efi_check_register_notify_event() - check if registration key is valid + * + * Check that a pointer is a valid registration key as returned by + * RegisterProtocolNotify(). + * + * @key: registration key + * Return: valid registration key or NULL + */ +static struct efi_register_notify_event *efi_check_register_notify_event + (void *key) +{ + struct efi_register_notify_event *event; + + list_for_each_entry(event, &efi_register_notify_events, link) { + if (event == (struct efi_register_notify_event *)key) + return event; + } + return NULL; +} + +/** * efi_locate_handle() - locate handles implementing a protocol * * @search_type: selection criterion @@ -1390,7 +1426,8 @@ static efi_status_t efi_locate_handle( { struct efi_object *efiobj; efi_uintn_t size = 0; - struct efi_register_notify_event *item, *event = NULL; + struct efi_register_notify_event *event; + struct efi_protocol_notification *handle = NULL; /* Check parameters */ switch (search_type) { @@ -1400,17 +1437,9 @@ static efi_status_t efi_locate_handle( if (!search_key) return EFI_INVALID_PARAMETER; /* Check that the registration key is valid */ - list_for_each_entry(item, &efi_register_notify_events, link) { - if (item == - (struct efi_register_notify_event *)search_key) { - event = item; - break; - } - } + event = efi_check_register_notify_event(search_key); if (!event) return EFI_INVALID_PARAMETER; - - protocol = &event->protocol; break; case BY_PROTOCOL: if (!protocol) @@ -1421,14 +1450,23 @@ static efi_status_t efi_locate_handle( } /* Count how much space we need */ - list_for_each_entry(efiobj, &efi_obj_list, link) { - if (!efi_search(search_type, protocol, efiobj)) - size += sizeof(void *); + if (search_type == BY_REGISTER_NOTIFY) { + if (list_empty(&event->handles)) + return EFI_NOT_FOUND; + handle = list_first_entry(&event->handles, + struct efi_protocol_notification, + link); + efiobj = handle->handle; + size += sizeof(void *); + } else { + list_for_each_entry(efiobj, &efi_obj_list, link) { + if (!efi_search(search_type, protocol, efiobj)) + size += sizeof(void *); + } + if (size == 0) + return EFI_NOT_FOUND; } - if (size == 0) - return EFI_NOT_FOUND; - if (!buffer_size) return EFI_INVALID_PARAMETER; @@ -1444,9 +1482,14 @@ static efi_status_t efi_locate_handle( return EFI_INVALID_PARAMETER; /* Then fill the array */ - list_for_each_entry(efiobj, &efi_obj_list, link) { - if (!efi_search(search_type, protocol, efiobj)) - *buffer++ = efiobj; + if (search_type == BY_REGISTER_NOTIFY) { + *buffer = efiobj; + list_del(&handle->link); + } else { + list_for_each_entry(efiobj, &efi_obj_list, link) { + if (!efi_search(search_type, protocol, efiobj)) + *buffer++ = efiobj; + } } return EFI_SUCCESS; @@ -2013,7 +2056,6 @@ static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle, item->info.controller_handle == controller_handle) { efi_delete_open_info(item); r = EFI_SUCCESS; - break; } } out: @@ -2212,29 +2254,58 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, void *registration, void **protocol_interface) { - struct list_head *lhandle; + struct efi_handler *handler; efi_status_t ret; + struct efi_object *efiobj; EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface); + /* + * The UEFI spec explicitly requires a protocol even if a registration + * key is provided. This differs from the logic in LocateHandle(). + */ if (!protocol || !protocol_interface) return EFI_EXIT(EFI_INVALID_PARAMETER); - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - struct efi_handler *handler; - - efiobj = list_entry(lhandle, struct efi_object, link); + if (registration) { + struct efi_register_notify_event *event; + struct efi_protocol_notification *handle; + event = efi_check_register_notify_event(registration); + if (!event) + return EFI_EXIT(EFI_INVALID_PARAMETER); + /* + * The UEFI spec requires to return EFI_NOT_FOUND if no + * protocol instance matches protocol and registration. + * So let's do the same for a mismatch between protocol and + * registration. + */ + if (guidcmp(&event->protocol, protocol)) + goto not_found; + if (list_empty(&event->handles)) + goto not_found; + handle = list_first_entry(&event->handles, + struct efi_protocol_notification, + link); + efiobj = handle->handle; + list_del(&handle->link); + free(handle); ret = efi_search_protocol(efiobj, protocol, &handler); - if (ret == EFI_SUCCESS) { - *protocol_interface = handler->protocol_interface; - return EFI_EXIT(EFI_SUCCESS); + if (ret == EFI_SUCCESS) + goto found; + } else { + list_for_each_entry(efiobj, &efi_obj_list, link) { + ret = efi_search_protocol(efiobj, protocol, &handler); + if (ret == EFI_SUCCESS) + goto found; } } +not_found: *protocol_interface = NULL; - return EFI_EXIT(EFI_NOT_FOUND); +found: + *protocol_interface = handler->protocol_interface; + return EFI_EXIT(EFI_SUCCESS); } /** @@ -2561,34 +2632,50 @@ static efi_status_t efi_protocol_open( if ((attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) && (item->info.attributes == attributes)) return EFI_ALREADY_STARTED; + } else { + if (item->info.attributes & + EFI_OPEN_PROTOCOL_BY_DRIVER) + opened_by_driver = true; } if (item->info.attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) opened_exclusive = true; } /* Only one controller can open the protocol exclusively */ - if (opened_exclusive && attributes & - (EFI_OPEN_PROTOCOL_EXCLUSIVE | EFI_OPEN_PROTOCOL_BY_DRIVER)) - return EFI_ACCESS_DENIED; + if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { + if (opened_exclusive) + return EFI_ACCESS_DENIED; + } else if (attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) { + if (opened_exclusive || opened_by_driver) + return EFI_ACCESS_DENIED; + } /* Prepare exclusive opening */ if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) { /* Try to disconnect controllers */ +disconnect_next: + opened_by_driver = false; list_for_each_entry(item, &handler->open_infos, link) { + efi_status_t ret; + if (item->info.attributes == - EFI_OPEN_PROTOCOL_BY_DRIVER) - EFI_CALL(efi_disconnect_controller( + EFI_OPEN_PROTOCOL_BY_DRIVER) { + ret = EFI_CALL(efi_disconnect_controller( item->info.controller_handle, item->info.agent_handle, NULL)); + if (ret == EFI_SUCCESS) + /* + * Child controllers may have been + * removed from the open_infos list. So + * let's restart the loop. + */ + goto disconnect_next; + else + opened_by_driver = true; + } } - opened_by_driver = false; - /* Check if all controllers are disconnected */ - list_for_each_entry(item, &handler->open_infos, link) { - if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) - opened_by_driver = true; - } - /* Only one controller can be connected */ + /* Only one driver can be connected */ if (opened_by_driver) return EFI_ACCESS_DENIED; } @@ -2596,7 +2683,8 @@ static efi_status_t efi_protocol_open( /* Find existing entry */ list_for_each_entry(item, &handler->open_infos, link) { if (item->info.agent_handle == agent_handle && - item->info.controller_handle == controller_handle) + item->info.controller_handle == controller_handle && + item->info.attributes == attributes) match = &item->info; } /* None found, create one */ @@ -2985,7 +3073,7 @@ static efi_status_t EFIAPI efi_handle_protocol(efi_handle_t handle, const efi_guid_t *protocol, void **protocol_interface) { - return efi_open_protocol(handle, protocol, protocol_interface, NULL, + return efi_open_protocol(handle, protocol, protocol_interface, efi_root, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL); } diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 058b40a887..9c50955c9b 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -167,7 +167,7 @@ static efi_status_t EFIAPI efi_get_time_boottime( struct efi_time *time, struct efi_time_cap *capabilities) { -#ifdef CONFIG_DM_RTC +#ifdef CONFIG_EFI_GET_TIME efi_status_t ret = EFI_SUCCESS; struct rtc_time tm; struct udevice *dev; @@ -195,9 +195,9 @@ static efi_status_t EFIAPI efi_get_time_boottime( time->hour = tm.tm_hour; time->minute = tm.tm_min; time->second = tm.tm_sec; - time->daylight = EFI_TIME_ADJUST_DAYLIGHT; - if (tm.tm_isdst > 0) - time->daylight |= EFI_TIME_IN_DAYLIGHT; + if (tm.tm_isdst) + time->daylight = + EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT; time->timezone = EFI_UNSPECIFIED_TIMEZONE; if (capabilities) { @@ -214,6 +214,30 @@ out: #endif } +#ifdef CONFIG_EFI_SET_TIME + +/** + * efi_validate_time() - checks if timestamp is valid + * + * @time: timestamp to validate + * Returns: 0 if timestamp is valid, 1 otherwise + */ +static int efi_validate_time(struct efi_time *time) +{ + return (!time || + time->year < 1900 || time->year > 9999 || + !time->month || time->month > 12 || !time->day || + time->day > rtc_month_days(time->month - 1, time->year) || + time->hour > 23 || time->minute > 59 || time->second > 59 || + time->nanosecond > 999999999 || + time->daylight & + ~(EFI_TIME_IN_DAYLIGHT | EFI_TIME_ADJUST_DAYLIGHT) || + ((time->timezone < -1440 || time->timezone > 1440) && + time->timezone != EFI_UNSPECIFIED_TIMEZONE)); +} + +#endif + /** * efi_set_time_boottime() - set current time * @@ -228,14 +252,14 @@ out: */ static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) { -#ifdef CONFIG_DM_RTC +#ifdef CONFIG_EFI_SET_TIME efi_status_t ret = EFI_SUCCESS; struct rtc_time tm; struct udevice *dev; EFI_ENTRY("%p", time); - if (!time) { + if (efi_validate_time(time)) { ret = EFI_INVALID_PARAMETER; goto out; } @@ -252,7 +276,8 @@ static efi_status_t EFIAPI efi_set_time_boottime(struct efi_time *time) tm.tm_hour = time->hour; tm.tm_min = time->minute; tm.tm_sec = time->second; - tm.tm_isdst = time->daylight == EFI_TIME_IN_DAYLIGHT; + tm.tm_isdst = time->daylight == + (EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT); /* Calculate day of week */ rtc_calc_weekday(&tm); diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index cfbb40c891..3bebd0f573 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -26,8 +26,8 @@ efi_selftest_gop.o \ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ efi_selftest_memory.o \ +efi_selftest_open_protocol.o \ efi_selftest_register_notify.o \ -efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ @@ -43,6 +43,7 @@ efi_selftest_unicode_collation.o obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o +obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) obj-y += efi_selftest_fdt.o diff --git a/lib/efi_selftest/efi_selftest_open_protocol.c b/lib/efi_selftest/efi_selftest_open_protocol.c new file mode 100644 index 0000000000..e3f351df72 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_open_protocol.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_open_protocol + * + * Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks that open protocol information is correctly updated + * when calling: + * HandleProtocol, OpenProtocol, OpenProtocolInformation, CloseProtocol. + */ + +#include <efi_selftest.h> + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI *inc)(void); +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x492a0e38, 0x1442, 0xf819, + 0x14, 0xaa, 0x4b, 0x8d, 0x09, 0xfe, 0x5a, 0xb9); +static efi_handle_t handle1; +static struct interface interface1; + +/* + * Setup unit test. + * + * Create a handle and install a protocol interface on it. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (!handle1) { + efi_st_error + ("InstallProtocolInterface failed to create handle\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + if (handle1) { + ret = boottime->uninstall_protocol_interface(handle1, &guid1, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Open the installed protocol twice via HandleProtocol() and once via + * OpenProtocol(EFI_OPEN_PROTOCOL_GET_PROTOCOL). Read the open protocol + * information and check the open counts. Finally close the protocol and + * check again. + */ +static int execute(void) +{ + void *interface; + struct efi_open_protocol_info_entry *entry_buffer; + efi_uintn_t entry_count; + efi_handle_t firmware_handle; + efi_status_t ret; + + ret = boottime->handle_protocol(handle1, &guid1, &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface1) { + efi_st_error("HandleProtocol returned wrong interface\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 1) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 1, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->handle_protocol(handle1, &guid1, &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 1) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 1, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + if (entry_buffer[0].open_count != 2) { + efi_st_error("Incorrect open count: expected 2 got %u\n", + entry_buffer[0].open_count); + return EFI_ST_FAILURE; + } + firmware_handle = entry_buffer[0].agent_handle; + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol(handle1, &guid1, &interface, + firmware_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count != 2) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 2, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + if (entry_buffer[0].open_count + entry_buffer[1].open_count != 3) { + efi_st_error("Incorrect open count: expected 3 got %u\n", + entry_buffer[0].open_count + + entry_buffer[1].open_count); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(entry_buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->close_protocol(handle1, &guid1, firmware_handle, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("CloseProtocol failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->open_protocol_information(handle1, &guid1, + &entry_buffer, &entry_count); + if (ret != EFI_SUCCESS) { + efi_st_error("OpenProtocolInformation failed\n"); + return EFI_ST_FAILURE; + } + if (entry_count) { + efi_st_error("Incorrect OpenProtocolInformation count\n"); + efi_st_printf("Expected 0, got %u\n", + (unsigned int)entry_count); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(openprot) = { + .name = "open protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/lib/efi_selftest/efi_selftest_register_notify.c b/lib/efi_selftest/efi_selftest_register_notify.c index ee0ef395de..ad763dd6cb 100644 --- a/lib/efi_selftest/efi_selftest_register_notify.c +++ b/lib/efi_selftest/efi_selftest_register_notify.c @@ -47,15 +47,20 @@ static void EFIAPI notify(struct efi_event *event, void *context) { struct context *cp = context; efi_status_t ret; + efi_uintn_t handle_count; + efi_handle_t *handles; cp->notify_count++; - ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL, - cp->registration_key, - &cp->handle_count, - &cp->handles); - if (ret != EFI_SUCCESS) - cp->handle_count = 0; + for (;;) { + ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL, + cp->registration_key, + &handle_count, &handles); + if (ret != EFI_SUCCESS) + break; + cp->handle_count += handle_count; + cp->handles = handles; + } } /* @@ -170,7 +175,7 @@ static int execute(void) efi_st_error("reinstall was notified too often\n"); return EFI_ST_FAILURE; } - if (context.handle_count != 1) { + if (context.handle_count != 2) { efi_st_error("LocateHandle failed\n"); return EFI_ST_FAILURE; } @@ -195,7 +200,7 @@ static int execute(void) efi_st_error("install was notified too often\n"); return EFI_ST_FAILURE; } - if (context.handle_count != 2) { + if (context.handle_count != 3) { efi_st_error("LocateHandle failed\n"); return EFI_ST_FAILURE; } diff --git a/lib/efi_selftest/efi_selftest_rtc.c b/lib/efi_selftest/efi_selftest_rtc.c index 9eb29add3b..6f7035dee6 100644 --- a/lib/efi_selftest/efi_selftest_rtc.c +++ b/lib/efi_selftest/efi_selftest_rtc.c @@ -40,7 +40,9 @@ static int setup(const efi_handle_t handle, static int execute(void) { efi_status_t ret; - struct efi_time tm, tm_old, tm_new = { + struct efi_time tm_old; +#ifdef CONFIG_EFI_SET_TIME + struct efi_time tm, tm_new = { .year = 2017, .month = 5, .day = 19, @@ -48,31 +50,23 @@ static int execute(void) .minute = 47, .second = 53, }; +#endif /* Display current time */ ret = runtime->get_time(&tm_old, NULL); if (ret != EFI_SUCCESS) { -#ifdef CONFIG_CMD_DATE efi_st_error(EFI_ST_NO_RTC); return EFI_ST_FAILURE; -#else - efi_st_todo(EFI_ST_NO_RTC); - return EFI_ST_SUCCESS; -#endif } efi_st_printf("Time according to real time clock: " "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n", tm_old.year, tm_old.month, tm_old.day, tm_old.hour, tm_old.minute, tm_old.second); +#ifdef CONFIG_EFI_SET_TIME ret = runtime->set_time(&tm_new); if (ret != EFI_SUCCESS) { -#ifdef CONFIG_CMD_DATE efi_st_error(EFI_ST_NO_RTC_SET); return EFI_ST_FAILURE; -#else - efi_st_todo(EFI_ST_NO_RTC_SET); - return EFI_ST_SUCCESS; -#endif } ret = runtime->get_time(&tm, NULL); if (ret != EFI_SUCCESS) { @@ -95,6 +89,7 @@ static int execute(void) efi_st_error(EFI_ST_NO_RTC_SET); return EFI_ST_FAILURE; } +#endif return EFI_ST_SUCCESS; } |