mirror of
https://github.com/u-boot/u-boot.git
synced 2024-11-29 07:33:29 +08:00
efi_loader: implement event groups
If an event of a group event is signaled all other events of the same group are signaled too. Function efi_signal_event is renamed to efi_queue_event. A new function efi_signal_event is introduced that checks if an event belongs to a group and than signals all events of the group. Event group notifciation is implemented for ExitBootServices, InstallConfigurationTable, and ResetSystem. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
a3a28f5f0c
commit
b095f3c85f
@ -165,6 +165,7 @@ struct efi_object {
|
||||
* @notify_tpl: Task priority level of notifications
|
||||
* @nofify_function: Function to call when the event is triggered
|
||||
* @notify_context: Data to be passed to the notify function
|
||||
* @group: Event group
|
||||
* @trigger_time: Period of the timer
|
||||
* @trigger_next: Next time to trigger the timer
|
||||
* @trigger_type: Type of timer, see efi_set_timer
|
||||
@ -177,6 +178,7 @@ struct efi_event {
|
||||
efi_uintn_t notify_tpl;
|
||||
void (EFIAPI *notify_function)(struct efi_event *event, void *context);
|
||||
void *notify_context;
|
||||
const efi_guid_t *group;
|
||||
u64 trigger_next;
|
||||
u64 trigger_time;
|
||||
enum efi_timer_delay trigger_type;
|
||||
@ -186,6 +188,8 @@ struct efi_event {
|
||||
|
||||
/* This list contains all UEFI objects we know of */
|
||||
extern struct list_head efi_obj_list;
|
||||
/* List of all events */
|
||||
extern struct list_head efi_events;
|
||||
|
||||
/* Called by bootefi to make console interface available */
|
||||
int efi_console_register(void);
|
||||
@ -252,7 +256,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
void (EFIAPI *notify_function) (
|
||||
struct efi_event *event,
|
||||
void *context),
|
||||
void *notify_context, struct efi_event **event);
|
||||
void *notify_context, efi_guid_t *group,
|
||||
struct efi_event **event);
|
||||
/* Call this to set a timer */
|
||||
efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
|
||||
uint64_t trigger_time);
|
||||
|
@ -27,7 +27,7 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION;
|
||||
LIST_HEAD(efi_obj_list);
|
||||
|
||||
/* List of all events */
|
||||
static LIST_HEAD(efi_events);
|
||||
LIST_HEAD(efi_events);
|
||||
|
||||
/*
|
||||
* If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
|
||||
@ -176,7 +176,7 @@ const char *__efi_nesting_dec(void)
|
||||
* @event event to signal
|
||||
* @check_tpl check the TPL level
|
||||
*/
|
||||
void efi_signal_event(struct efi_event *event, bool check_tpl)
|
||||
static void efi_queue_event(struct efi_event *event, bool check_tpl)
|
||||
{
|
||||
if (event->notify_function) {
|
||||
event->is_queued = true;
|
||||
@ -189,6 +189,50 @@ void efi_signal_event(struct efi_event *event, bool check_tpl)
|
||||
event->is_queued = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal an EFI event.
|
||||
*
|
||||
* This function signals an event. If the event belongs to an event group
|
||||
* all events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL
|
||||
* their notification function is queued.
|
||||
*
|
||||
* For the SignalEvent service see efi_signal_event_ext.
|
||||
*
|
||||
* @event event to signal
|
||||
* @check_tpl check the TPL level
|
||||
*/
|
||||
void efi_signal_event(struct efi_event *event, bool check_tpl)
|
||||
{
|
||||
if (event->group) {
|
||||
struct efi_event *evt;
|
||||
|
||||
/*
|
||||
* The signaled state has to set before executing any
|
||||
* notification function
|
||||
*/
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (!evt->group || guidcmp(evt->group, event->group))
|
||||
continue;
|
||||
if (evt->is_signaled)
|
||||
continue;
|
||||
evt->is_signaled = true;
|
||||
if (evt->type & EVT_NOTIFY_SIGNAL &&
|
||||
evt->notify_function)
|
||||
evt->is_queued = true;
|
||||
}
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (!evt->group || guidcmp(evt->group, event->group))
|
||||
continue;
|
||||
if (evt->is_queued)
|
||||
efi_queue_event(evt, check_tpl);
|
||||
}
|
||||
} else if (!event->is_signaled) {
|
||||
event->is_signaled = true;
|
||||
if (event->type & EVT_NOTIFY_SIGNAL)
|
||||
efi_queue_event(event, check_tpl);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Raise the task priority level.
|
||||
*
|
||||
@ -529,7 +573,8 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
void (EFIAPI *notify_function) (
|
||||
struct efi_event *event,
|
||||
void *context),
|
||||
void *notify_context, struct efi_event **event)
|
||||
void *notify_context, efi_guid_t *group,
|
||||
struct efi_event **event)
|
||||
{
|
||||
struct efi_event *evt;
|
||||
|
||||
@ -550,6 +595,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
||||
evt->notify_tpl = notify_tpl;
|
||||
evt->notify_function = notify_function;
|
||||
evt->notify_context = notify_context;
|
||||
evt->group = group;
|
||||
/* Disable timers on bootup */
|
||||
evt->trigger_next = -1ULL;
|
||||
evt->is_queued = false;
|
||||
@ -585,10 +631,8 @@ efi_status_t EFIAPI efi_create_event_ex(uint32_t type, efi_uintn_t notify_tpl,
|
||||
{
|
||||
EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function,
|
||||
notify_context, event_group);
|
||||
if (event_group)
|
||||
return EFI_EXIT(EFI_UNSUPPORTED);
|
||||
return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function,
|
||||
notify_context, event));
|
||||
notify_context, event_group, event));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -615,7 +659,7 @@ static efi_status_t EFIAPI efi_create_event_ext(
|
||||
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));
|
||||
notify_context, NULL, event));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -632,7 +676,7 @@ void efi_timer_check(void)
|
||||
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (evt->is_queued)
|
||||
efi_signal_event(evt, true);
|
||||
efi_queue_event(evt, true);
|
||||
if (!(evt->type & EVT_TIMER) || now < evt->trigger_next)
|
||||
continue;
|
||||
switch (evt->trigger_type) {
|
||||
@ -645,7 +689,7 @@ void efi_timer_check(void)
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
evt->is_signaled = true;
|
||||
evt->is_signaled = false;
|
||||
efi_signal_event(evt, true);
|
||||
}
|
||||
WATCHDOG_RESET();
|
||||
@ -744,7 +788,7 @@ static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events,
|
||||
if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
if (!event[i]->is_signaled)
|
||||
efi_signal_event(event[i], true);
|
||||
efi_queue_event(event[i], true);
|
||||
}
|
||||
|
||||
/* Wait for signal */
|
||||
@ -787,11 +831,7 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
|
||||
EFI_ENTRY("%p", event);
|
||||
if (efi_is_event(event) != EFI_SUCCESS)
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
if (!event->is_signaled) {
|
||||
event->is_signaled = true;
|
||||
if (event->type & EVT_NOTIFY_SIGNAL)
|
||||
efi_signal_event(event, true);
|
||||
}
|
||||
efi_signal_event(event, true);
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
@ -836,7 +876,7 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
|
||||
event->type & EVT_NOTIFY_SIGNAL)
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
if (!event->is_signaled)
|
||||
efi_signal_event(event, true);
|
||||
efi_queue_event(event, true);
|
||||
if (event->is_signaled) {
|
||||
event->is_signaled = false;
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
@ -1333,6 +1373,7 @@ static void efi_remove_configuration_table(int i)
|
||||
efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
||||
void *table)
|
||||
{
|
||||
struct efi_event *evt;
|
||||
int i;
|
||||
|
||||
if (!guid)
|
||||
@ -1345,7 +1386,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
||||
efi_conf_table[i].table = table;
|
||||
else
|
||||
efi_remove_configuration_table(i);
|
||||
return EFI_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1361,6 +1402,15 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
||||
efi_conf_table[i].table = table;
|
||||
systab.nr_tables = i + 1;
|
||||
|
||||
out:
|
||||
/* Notify that the configuration table was changed */
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (evt->group && !guidcmp(evt->group, guid)) {
|
||||
efi_signal_event(evt, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1764,12 +1814,19 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
|
||||
if (!systab.boottime)
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
|
||||
/* Add related events to the event group */
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (evt->type == EVT_SIGNAL_EXIT_BOOT_SERVICES)
|
||||
evt->group = &efi_guid_event_group_exit_boot_services;
|
||||
}
|
||||
/* Notify that ExitBootServices is invoked. */
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
|
||||
continue;
|
||||
evt->is_signaled = true;
|
||||
efi_signal_event(evt, false);
|
||||
if (evt->group &&
|
||||
!guidcmp(evt->group,
|
||||
&efi_guid_event_group_exit_boot_services)) {
|
||||
efi_signal_event(evt, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO Should persist EFI variables here */
|
||||
|
@ -572,14 +572,14 @@ int efi_console_register(void)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Create console events */
|
||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
|
||||
efi_key_notify, NULL, &efi_con_in.wait_for_key);
|
||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
|
||||
NULL, 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,
|
||||
efi_console_timer_notify, NULL, NULL,
|
||||
&console_timer_event);
|
||||
if (r != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to register console event\n");
|
||||
|
@ -341,7 +341,7 @@ efi_status_t efi_net_register(void)
|
||||
* Create WaitForPacket event.
|
||||
*/
|
||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
|
||||
efi_network_timer_notify, NULL,
|
||||
efi_network_timer_notify, NULL, NULL,
|
||||
&wait_for_packet);
|
||||
if (r != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to register network event\n");
|
||||
@ -355,7 +355,7 @@ efi_status_t efi_net_register(void)
|
||||
* has been received.
|
||||
*/
|
||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
efi_network_timer_notify, NULL,
|
||||
efi_network_timer_notify, NULL, NULL,
|
||||
&network_timer_event);
|
||||
if (r != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to register network event\n");
|
||||
|
@ -74,9 +74,20 @@ static void EFIAPI efi_reset_system_boottime(
|
||||
efi_status_t reset_status,
|
||||
unsigned long data_size, void *reset_data)
|
||||
{
|
||||
struct efi_event *evt;
|
||||
|
||||
EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
|
||||
reset_data);
|
||||
|
||||
/* Notify reset */
|
||||
list_for_each_entry(evt, &efi_events, link) {
|
||||
if (evt->group &&
|
||||
!guidcmp(evt->group,
|
||||
&efi_guid_event_group_reset_system)) {
|
||||
efi_signal_event(evt, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (reset_type) {
|
||||
case EFI_RESET_COLD:
|
||||
case EFI_RESET_WARM:
|
||||
|
@ -67,7 +67,7 @@ efi_status_t efi_watchdog_register(void)
|
||||
* Create a timer event.
|
||||
*/
|
||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
efi_watchdog_timer_notify, NULL,
|
||||
efi_watchdog_timer_notify, NULL, NULL,
|
||||
&watchdog_timer_event);
|
||||
if (r != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to register watchdog event\n");
|
||||
|
Loading…
Reference in New Issue
Block a user