mirror of
https://github.com/linux-sunxi/u-boot-sunxi.git
synced 2024-02-12 11:16:03 +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:

committed by
Alexander Graf

parent
a3a28f5f0c
commit
b095f3c85f
@ -165,6 +165,7 @@ struct efi_object {
|
|||||||
* @notify_tpl: Task priority level of notifications
|
* @notify_tpl: Task priority level of notifications
|
||||||
* @nofify_function: Function to call when the event is triggered
|
* @nofify_function: Function to call when the event is triggered
|
||||||
* @notify_context: Data to be passed to the notify function
|
* @notify_context: Data to be passed to the notify function
|
||||||
|
* @group: Event group
|
||||||
* @trigger_time: Period of the timer
|
* @trigger_time: Period of the timer
|
||||||
* @trigger_next: Next time to trigger the timer
|
* @trigger_next: Next time to trigger the timer
|
||||||
* @trigger_type: Type of timer, see efi_set_timer
|
* @trigger_type: Type of timer, see efi_set_timer
|
||||||
@ -177,6 +178,7 @@ struct efi_event {
|
|||||||
efi_uintn_t notify_tpl;
|
efi_uintn_t notify_tpl;
|
||||||
void (EFIAPI *notify_function)(struct efi_event *event, void *context);
|
void (EFIAPI *notify_function)(struct efi_event *event, void *context);
|
||||||
void *notify_context;
|
void *notify_context;
|
||||||
|
const efi_guid_t *group;
|
||||||
u64 trigger_next;
|
u64 trigger_next;
|
||||||
u64 trigger_time;
|
u64 trigger_time;
|
||||||
enum efi_timer_delay trigger_type;
|
enum efi_timer_delay trigger_type;
|
||||||
@ -186,6 +188,8 @@ struct efi_event {
|
|||||||
|
|
||||||
/* This list contains all UEFI objects we know of */
|
/* This list contains all UEFI objects we know of */
|
||||||
extern struct list_head efi_obj_list;
|
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 */
|
/* Called by bootefi to make console interface available */
|
||||||
int efi_console_register(void);
|
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) (
|
void (EFIAPI *notify_function) (
|
||||||
struct efi_event *event,
|
struct efi_event *event,
|
||||||
void *context),
|
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 */
|
/* Call this to set a timer */
|
||||||
efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
|
efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
|
||||||
uint64_t trigger_time);
|
uint64_t trigger_time);
|
||||||
|
@ -27,7 +27,7 @@ static efi_uintn_t efi_tpl = TPL_APPLICATION;
|
|||||||
LIST_HEAD(efi_obj_list);
|
LIST_HEAD(efi_obj_list);
|
||||||
|
|
||||||
/* List of all events */
|
/* 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)
|
* 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
|
* @event event to signal
|
||||||
* @check_tpl check the TPL level
|
* @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) {
|
if (event->notify_function) {
|
||||||
event->is_queued = true;
|
event->is_queued = true;
|
||||||
@ -189,6 +189,50 @@ void efi_signal_event(struct efi_event *event, bool check_tpl)
|
|||||||
event->is_queued = false;
|
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.
|
* 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) (
|
void (EFIAPI *notify_function) (
|
||||||
struct efi_event *event,
|
struct efi_event *event,
|
||||||
void *context),
|
void *context),
|
||||||
void *notify_context, struct efi_event **event)
|
void *notify_context, efi_guid_t *group,
|
||||||
|
struct efi_event **event)
|
||||||
{
|
{
|
||||||
struct efi_event *evt;
|
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_tpl = notify_tpl;
|
||||||
evt->notify_function = notify_function;
|
evt->notify_function = notify_function;
|
||||||
evt->notify_context = notify_context;
|
evt->notify_context = notify_context;
|
||||||
|
evt->group = group;
|
||||||
/* Disable timers on bootup */
|
/* Disable timers on bootup */
|
||||||
evt->trigger_next = -1ULL;
|
evt->trigger_next = -1ULL;
|
||||||
evt->is_queued = false;
|
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,
|
EFI_ENTRY("%d, 0x%zx, %p, %p, %pUl", type, notify_tpl, notify_function,
|
||||||
notify_context, event_group);
|
notify_context, event_group);
|
||||||
if (event_group)
|
|
||||||
return EFI_EXIT(EFI_UNSUPPORTED);
|
|
||||||
return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function,
|
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,
|
EFI_ENTRY("%d, 0x%zx, %p, %p", type, notify_tpl, notify_function,
|
||||||
notify_context);
|
notify_context);
|
||||||
return EFI_EXIT(efi_create_event(type, notify_tpl, notify_function,
|
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) {
|
list_for_each_entry(evt, &efi_events, link) {
|
||||||
if (evt->is_queued)
|
if (evt->is_queued)
|
||||||
efi_signal_event(evt, true);
|
efi_queue_event(evt, true);
|
||||||
if (!(evt->type & EVT_TIMER) || now < evt->trigger_next)
|
if (!(evt->type & EVT_TIMER) || now < evt->trigger_next)
|
||||||
continue;
|
continue;
|
||||||
switch (evt->trigger_type) {
|
switch (evt->trigger_type) {
|
||||||
@ -645,7 +689,7 @@ void efi_timer_check(void)
|
|||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
evt->is_signaled = true;
|
evt->is_signaled = false;
|
||||||
efi_signal_event(evt, true);
|
efi_signal_event(evt, true);
|
||||||
}
|
}
|
||||||
WATCHDOG_RESET();
|
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)
|
if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL)
|
||||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||||
if (!event[i]->is_signaled)
|
if (!event[i]->is_signaled)
|
||||||
efi_signal_event(event[i], true);
|
efi_queue_event(event[i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for signal */
|
/* Wait for signal */
|
||||||
@ -787,11 +831,7 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event)
|
|||||||
EFI_ENTRY("%p", event);
|
EFI_ENTRY("%p", event);
|
||||||
if (efi_is_event(event) != EFI_SUCCESS)
|
if (efi_is_event(event) != EFI_SUCCESS)
|
||||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||||
if (!event->is_signaled) {
|
efi_signal_event(event, true);
|
||||||
event->is_signaled = true;
|
|
||||||
if (event->type & EVT_NOTIFY_SIGNAL)
|
|
||||||
efi_signal_event(event, true);
|
|
||||||
}
|
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
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)
|
event->type & EVT_NOTIFY_SIGNAL)
|
||||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||||
if (!event->is_signaled)
|
if (!event->is_signaled)
|
||||||
efi_signal_event(event, true);
|
efi_queue_event(event, true);
|
||||||
if (event->is_signaled) {
|
if (event->is_signaled) {
|
||||||
event->is_signaled = false;
|
event->is_signaled = false;
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
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,
|
efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
||||||
void *table)
|
void *table)
|
||||||
{
|
{
|
||||||
|
struct efi_event *evt;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!guid)
|
if (!guid)
|
||||||
@ -1345,7 +1386,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
|||||||
efi_conf_table[i].table = table;
|
efi_conf_table[i].table = table;
|
||||||
else
|
else
|
||||||
efi_remove_configuration_table(i);
|
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;
|
efi_conf_table[i].table = table;
|
||||||
systab.nr_tables = i + 1;
|
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;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1764,12 +1814,19 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
|
|||||||
if (!systab.boottime)
|
if (!systab.boottime)
|
||||||
return EFI_EXIT(EFI_SUCCESS);
|
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. */
|
/* Notify that ExitBootServices is invoked. */
|
||||||
list_for_each_entry(evt, &efi_events, link) {
|
list_for_each_entry(evt, &efi_events, link) {
|
||||||
if (evt->type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
|
if (evt->group &&
|
||||||
continue;
|
!guidcmp(evt->group,
|
||||||
evt->is_signaled = true;
|
&efi_guid_event_group_exit_boot_services)) {
|
||||||
efi_signal_event(evt, false);
|
efi_signal_event(evt, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Should persist EFI variables here */
|
/* TODO Should persist EFI variables here */
|
||||||
|
@ -572,14 +572,14 @@ int efi_console_register(void)
|
|||||||
goto out_of_memory;
|
goto out_of_memory;
|
||||||
|
|
||||||
/* Create console events */
|
/* Create console events */
|
||||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
|
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
|
||||||
efi_key_notify, NULL, &efi_con_in.wait_for_key);
|
NULL, NULL, &efi_con_in.wait_for_key);
|
||||||
if (r != EFI_SUCCESS) {
|
if (r != EFI_SUCCESS) {
|
||||||
printf("ERROR: Failed to register WaitForKey event\n");
|
printf("ERROR: Failed to register WaitForKey event\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
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);
|
&console_timer_event);
|
||||||
if (r != EFI_SUCCESS) {
|
if (r != EFI_SUCCESS) {
|
||||||
printf("ERROR: Failed to register console event\n");
|
printf("ERROR: Failed to register console event\n");
|
||||||
|
@ -341,7 +341,7 @@ efi_status_t efi_net_register(void)
|
|||||||
* Create WaitForPacket event.
|
* Create WaitForPacket event.
|
||||||
*/
|
*/
|
||||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
|
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
|
||||||
efi_network_timer_notify, NULL,
|
efi_network_timer_notify, NULL, NULL,
|
||||||
&wait_for_packet);
|
&wait_for_packet);
|
||||||
if (r != EFI_SUCCESS) {
|
if (r != EFI_SUCCESS) {
|
||||||
printf("ERROR: Failed to register network event\n");
|
printf("ERROR: Failed to register network event\n");
|
||||||
@ -355,7 +355,7 @@ efi_status_t efi_net_register(void)
|
|||||||
* has been received.
|
* has been received.
|
||||||
*/
|
*/
|
||||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
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);
|
&network_timer_event);
|
||||||
if (r != EFI_SUCCESS) {
|
if (r != EFI_SUCCESS) {
|
||||||
printf("ERROR: Failed to register network event\n");
|
printf("ERROR: Failed to register network event\n");
|
||||||
|
@ -74,9 +74,20 @@ static void EFIAPI efi_reset_system_boottime(
|
|||||||
efi_status_t reset_status,
|
efi_status_t reset_status,
|
||||||
unsigned long data_size, void *reset_data)
|
unsigned long data_size, void *reset_data)
|
||||||
{
|
{
|
||||||
|
struct efi_event *evt;
|
||||||
|
|
||||||
EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
|
EFI_ENTRY("%d %lx %lx %p", reset_type, reset_status, data_size,
|
||||||
reset_data);
|
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) {
|
switch (reset_type) {
|
||||||
case EFI_RESET_COLD:
|
case EFI_RESET_COLD:
|
||||||
case EFI_RESET_WARM:
|
case EFI_RESET_WARM:
|
||||||
|
@ -67,7 +67,7 @@ efi_status_t efi_watchdog_register(void)
|
|||||||
* Create a timer event.
|
* Create a timer event.
|
||||||
*/
|
*/
|
||||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
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);
|
&watchdog_timer_event);
|
||||||
if (r != EFI_SUCCESS) {
|
if (r != EFI_SUCCESS) {
|
||||||
printf("ERROR: Failed to register watchdog event\n");
|
printf("ERROR: Failed to register watchdog event\n");
|
||||||
|
Reference in New Issue
Block a user