summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-06-02 18:19:45 -0400
committerTom Rini <trini@konsulko.com>2019-06-02 18:19:45 -0400
commit38c2a8a00132b4dcc6a0bb5baf5146b9eb9eb2d2 (patch)
tree60e6171ac74a93fa5d9d393ad17a9530aa5238a9
parent55cae6458d51294f4ded1d9d2339dfed5afa90ed (diff)
parent7950e8e2ebcd0f733ae2b00dbefefe1b742514bc (diff)
Merge tag 'efi-2019-07-rc4' of git://git.denx.de/u-boot-efi
Pull request for UEFI sub-system for v2019.07-rc4 Corrections for boottime services for protocols and for the SetTime() service are provided. Error messages for the 'setenv -e' and 'bootefi bootmgr' commands are added.
-rw-r--r--cmd/nvedit_efi.c10
-rw-r--r--drivers/rtc/rtc-lib.c2
-rw-r--r--include/efi_loader.h28
-rw-r--r--include/rtc.h8
-rw-r--r--lib/efi_loader/Kconfig16
-rw-r--r--lib/efi_loader/efi_bootmgr.c6
-rw-r--r--lib/efi_loader/efi_boottime.c188
-rw-r--r--lib/efi_loader/efi_runtime.c39
-rw-r--r--lib/efi_selftest/Makefile3
-rw-r--r--lib/efi_selftest/efi_selftest_open_protocol.c205
-rw-r--r--lib/efi_selftest/efi_selftest_register_notify.c21
-rw-r--r--lib/efi_selftest/efi_selftest_rtc.c17
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(&notif->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;
}