/** Check the status of an event. @param UserEvent The event to check @retval EFI_SUCCESS The event is in the signaled state @retval EFI_NOT_READY The event is not in the signaled state @retval EFI_INVALID_PARAMETER Event is of type EVT_NOTIFY_SIGNAL **/ EFI_STATUS EFIAPI CoreCheckEvent ( IN EFI_EVENT UserEvent ) { IEVENT *Event; EFI_STATUS Status; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { return EFI_INVALID_PARAMETER; } Status = EFI_NOT_READY; if ((Event->SignalCount == 0) && ((Event->Type & EVT_NOTIFY_WAIT) != 0)) { // // Queue the wait notify function // CoreAcquireEventLock (); if (Event->SignalCount == 0) { CoreNotifyEvent (Event); } CoreReleaseEventLock (); } // // If the even looks signalled, get the lock and clear it // if (Event->SignalCount != 0) { CoreAcquireEventLock (); if (Event->SignalCount != 0) { Event->SignalCount = 0; Status = EFI_SUCCESS; } CoreReleaseEventLock (); } return Status; }
/** Signals the event. Queues the event to be notified if needed. @param UserEvent The event to signal . @retval EFI_INVALID_PARAMETER Parameters are not valid. @retval EFI_SUCCESS The event was signaled. **/ EFI_STATUS EFIAPI CoreSignalEvent ( IN EFI_EVENT UserEvent ) { IEVENT *Event; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } CoreAcquireEventLock (); // // If the event is not already signalled, do so // if (Event->SignalCount == 0x00000000) { Event->SignalCount++; // // If signalling type is a notify function, queue it // if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { if (Event->ExFlag) { // // The CreateEventEx() style requires all members of the Event Group // to be signaled. // CoreReleaseEventLock (); CoreNotifySignalList (&Event->EventGroup); CoreAcquireEventLock (); } else { CoreNotifyEvent (Event); } } } CoreReleaseEventLock (); return EFI_SUCCESS; }
/** Dispatches all pending events. @param Priority The task priority level of event notifications to dispatch **/ VOID CoreDispatchEventNotifies ( IN EFI_TPL Priority ) { IEVENT *Event; LIST_ENTRY *Head; CoreAcquireEventLock (); ASSERT (gEventQueueLock.OwnerTpl == Priority); Head = &gEventQueue[Priority]; // // Dispatch all the pending notifications // while (!IsListEmpty (Head)) { Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE); RemoveEntryList (&Event->NotifyLink); Event->NotifyLink.ForwardLink = NULL; // // Only clear the SIGNAL status if it is a SIGNAL type event. // WAIT type events are only cleared in CheckEvent() // if ((Event->Type & EVT_NOTIFY_SIGNAL) != 0) { Event->SignalCount = 0; } CoreReleaseEventLock (); // // Notify this event // ASSERT (Event->NotifyFunction != NULL); Event->NotifyFunction (Event, Event->NotifyContext); // // Check for next pending event // CoreAcquireEventLock (); } gEventPending &= ~(1 << Priority); CoreReleaseEventLock (); }
/** Closes an event and frees the event structure. @param UserEvent Event to close @retval EFI_INVALID_PARAMETER Parameters are not valid. @retval EFI_SUCCESS The event has been closed **/ EFI_STATUS EFIAPI CoreCloseEvent ( IN EFI_EVENT UserEvent ) { EFI_STATUS Status; IEVENT *Event; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } // // If it's a timer event, make sure it's not pending // if ((Event->Type & EVT_TIMER) != 0) { CoreSetTimer (Event, TimerCancel, 0); } CoreAcquireEventLock (); // // If the event is queued somewhere, remove it // if (Event->RuntimeData.Link.ForwardLink != NULL) { RemoveEntryList (&Event->RuntimeData.Link); } if (Event->NotifyLink.ForwardLink != NULL) { RemoveEntryList (&Event->NotifyLink); } if (Event->SignalLink.ForwardLink != NULL) { RemoveEntryList (&Event->SignalLink); } CoreReleaseEventLock (); // // If the event is registered on a protocol notify, then remove it from the protocol database // CoreUnregisterProtocolNotify (Event); Status = CoreFreePool (Event); ASSERT_EFI_ERROR (Status); return Status; }
/** Signals all events in the EventGroup. @param EventGroup The list to signal **/ VOID CoreNotifySignalList ( IN EFI_GUID *EventGroup ) { LIST_ENTRY *Link; LIST_ENTRY *Head; IEVENT *Event; CoreAcquireEventLock (); Head = &gEventSignalQueue; for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE); if (CompareGuid (&Event->EventGroup, EventGroup)) { CoreNotifyEvent (Event); } } CoreReleaseEventLock (); }
VOID CoreNotifySignalList ( IN EFI_GUID *EventGroup ) /*++ Routine Description: Signals all events on the requested list Arguments: SignalType - The list to signal Returns: None --*/ { EFI_LIST_ENTRY *Link; EFI_LIST_ENTRY *Head; IEVENT *Event; CoreAcquireEventLock (); Head = &gEventSignalQueue; for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) { Event = CR (Link, IEVENT, SignalLink, EVENT_SIGNATURE); if ((Event->ExFlag) && EfiCompareGuid (&Event->EventGroup, EventGroup)) { CoreNotifyEvent (Event); } } CoreReleaseEventLock (); }
/** Creates a general-purpose event structure @param Type The type of event to create and its mode and attributes @param NotifyTpl The task priority level of event notifications @param NotifyFunction Pointer to the events notification function @param NotifyContext Pointer to the notification functions context; corresponds to parameter "Context" in the notification function @param EventGroup GUID for EventGroup if NULL act the same as gBS->CreateEvent(). @param Event Pointer to the newly created event if the call succeeds; undefined otherwise @retval EFI_SUCCESS The event structure was created @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value @retval EFI_OUT_OF_RESOURCES The event could not be allocated **/ EFI_STATUS EFIAPI CoreCreateEventInternal ( IN UINT32 Type, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL IN CONST VOID *NotifyContext, OPTIONAL IN CONST EFI_GUID *EventGroup, OPTIONAL OUT EFI_EVENT *Event ) { EFI_STATUS Status; IEVENT *IEvent; INTN Index; if (Event == NULL) { return EFI_INVALID_PARAMETER; } // // Check to make sure no reserved flags are set // Status = EFI_INVALID_PARAMETER; for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) { if (Type == mEventTable[Index]) { Status = EFI_SUCCESS; break; } } if(EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } // // Convert Event type for pre-defined Event groups // if (EventGroup != NULL) { // // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE // are not valid // if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) { return EFI_INVALID_PARAMETER; } if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) { Type = EVT_SIGNAL_EXIT_BOOT_SERVICES; } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) { Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE; } } else { // // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping // if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) { EventGroup = &gEfiEventExitBootServicesGuid; } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { EventGroup = &gEfiEventVirtualAddressChangeGuid; } } // // If it's a notify type of event, check its parameters // if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) { // // Check for an invalid NotifyFunction or NotifyTpl // if ((NotifyFunction == NULL) || (NotifyTpl <= TPL_APPLICATION) || (NotifyTpl >= TPL_HIGH_LEVEL)) { return EFI_INVALID_PARAMETER; } } else { // // No notification needed, zero ignored values // NotifyTpl = 0; NotifyFunction = NULL; NotifyContext = NULL; } // // Allocate and initialize a new event structure. // if ((Type & EVT_RUNTIME) != 0) { IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT)); } else { IEvent = AllocateZeroPool (sizeof (IEVENT)); } if (IEvent == NULL) { return EFI_OUT_OF_RESOURCES; } IEvent->Signature = EVENT_SIGNATURE; IEvent->Type = Type; IEvent->NotifyTpl = NotifyTpl; IEvent->NotifyFunction = NotifyFunction; IEvent->NotifyContext = (VOID *)NotifyContext; if (EventGroup != NULL) { CopyGuid (&IEvent->EventGroup, EventGroup); IEvent->ExFlag = TRUE; } *Event = IEvent; if ((Type & EVT_RUNTIME) != 0) { // // Keep a list of all RT events so we can tell the RT AP. // IEvent->RuntimeData.Type = Type; IEvent->RuntimeData.NotifyTpl = NotifyTpl; IEvent->RuntimeData.NotifyFunction = NotifyFunction; IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext; IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent; InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); } CoreAcquireEventLock (); if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) { // // The Event's NotifyFunction must be queued whenever the event is signaled // InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); } CoreReleaseEventLock (); // // Done // return EFI_SUCCESS; }
EFI_BOOTSERVICE EFI_STATUS EFIAPI CoreCloseEvent ( IN EFI_EVENT UserEvent ) /*++ Routine Description: Closes an event and frees the event structure. Arguments: UserEvent - Event to close Returns: EFI_INVALID_PARAMETER - Parameters are not valid. EFI_SUCCESS - The event has been closed --*/ { EFI_STATUS Status; IEVENT *Event; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } // // If it's a timer event, make sure it's not pending // if (Event->Type & EFI_EVENT_TIMER) { CoreSetTimer (Event, TimerCancel, 0); } CoreAcquireEventLock (); // // If the event is queued somewhere, remove it // if (Event->RuntimeData.Link.ForwardLink != NULL) { RemoveEntryList (&Event->RuntimeData.Link); } if (Event->NotifyLink.ForwardLink != NULL) { RemoveEntryList (&Event->NotifyLink); } if (Event->SignalLink.ForwardLink != NULL) { RemoveEntryList (&Event->SignalLink); } CoreReleaseEventLock (); // // If the event is registered on a protocol notify, // then remove it from the protocol database // CoreUnregisterProtocolNotify (Event); Status = CoreFreePool (Event); ASSERT_EFI_ERROR (Status); return Status; }
EFI_BOOTSERVICE EFI_STATUS EFIAPI CoreCheckEvent ( IN EFI_EVENT UserEvent ) /*++ Routine Description: Check the status of an event Arguments: UserEvent - The event to check Returns: EFI_SUCCESS - The event is in the signaled state EFI_NOT_READY - The event is not in the signaled state EFI_INVALID_PARAMETER - Event is of type EVT_NOTIFY_SIGNAL --*/ { IEVENT *Event; EFI_STATUS Status; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { return EFI_INVALID_PARAMETER; } Status = EFI_NOT_READY; if (!Event->SignalCount && (Event->Type & EFI_EVENT_NOTIFY_WAIT)) { // // Queue the wait notify function // CoreAcquireEventLock (); if (!Event->SignalCount) { CoreNotifyEvent (Event); } CoreReleaseEventLock (); } // // If the even looks signalled, get the lock and clear it // if (Event->SignalCount) { CoreAcquireEventLock (); if (Event->SignalCount) { Event->SignalCount = 0; Status = EFI_SUCCESS; } CoreReleaseEventLock (); } return Status; }
EFI_BOOTSERVICE EFI_STATUS EFIAPI CoreSignalEvent ( IN EFI_EVENT UserEvent ) /*++ Routine Description: Signals the event. Queues the event to be notified if needed Arguments: UserEvent - The event to signal Returns: EFI_INVALID_PARAMETER - Parameters are not valid. EFI_SUCCESS - The event was signaled. --*/ { IEVENT *Event; Event = UserEvent; if (Event == NULL) { return EFI_INVALID_PARAMETER; } if (Event->Signature != EVENT_SIGNATURE) { return EFI_INVALID_PARAMETER; } CoreAcquireEventLock (); // // If the event is not already signalled, do so // if (Event->SignalCount == 0x00000000) { Event->SignalCount ++; // // If signalling type is a notify function, queue it // if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { if (Event->ExFlag) { // // The CreateEventEx() style requires all members of the Event Group // to be signaled. // CoreReleaseEventLock (); CoreNotifySignalList (&Event->EventGroup); CoreAcquireEventLock (); } else { CoreNotifyEvent (Event); } } } CoreReleaseEventLock (); return EFI_SUCCESS; }
EFI_BOOTSERVICE EFI_STATUS EFIAPI CoreCreateEventEx ( IN UINT32 Type, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *NotifyContext, IN CONST EFI_GUID *EventGroup, OPTIONAL OUT EFI_EVENT *Event ) /*++ Routine Description: Creates a general-purpose event structure Arguments: Type - The type of event to create and its mode and attributes NotifyTpl - The task priority level of event notifications NotifyFunction - Pointer to the events notification function NotifyContext - Pointer to the notification functions context; corresponds to parameter "Context" in the notification function EventGroup - GUID for EventGroup if NULL act the same as gBS->CreateEvent(). Event - Pointer to the newly created event if the call succeeds; undefined otherwise Returns: EFI_SUCCESS - The event structure was created EFI_INVALID_PARAMETER - One of the parameters has an invalid value EFI_OUT_OF_RESOURCES - The event could not be allocated --*/ { EFI_STATUS Status; IEVENT *IEvent; INTN Index; if ((Event == NULL) || (NotifyTpl == EFI_TPL_APPLICATION)) { return EFI_INVALID_PARAMETER; } // // For event group, type EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES and EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE // are not valid // if (EventGroup != NULL) { if ((Type == EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) { return EFI_INVALID_PARAMETER; } } // // Check to make sure no reserved flags are set // Status = EFI_INVALID_PARAMETER; for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) { if (Type == mEventTable[Index]) { Status = EFI_SUCCESS; break; } } if(EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } // // Convert Event type for pre-defined Event groups // if (EventGroup != NULL) { if (EfiCompareGuid ((VOID *) EventGroup, &gEfiEventExitBootServicesGuid)) { Type = EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES; } else if (EfiCompareGuid ((VOID *) EventGroup, &gEfiEventVirtualAddressChangeGuid)) { Type = EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE; } } // // If it's a notify type of event, check its parameters // if ((Type & (EFI_EVENT_NOTIFY_WAIT | EFI_EVENT_NOTIFY_SIGNAL))) { // // Check for an invalid NotifyFunction or NotifyTpl // if ((NotifyFunction == NULL) || (NotifyTpl < EFI_TPL_APPLICATION) || (NotifyTpl >= EFI_TPL_HIGH_LEVEL)) { return EFI_INVALID_PARAMETER; } } else { // // No notification needed, zero ignored values // NotifyTpl = 0; NotifyFunction = NULL; NotifyContext = NULL; } // // Allcoate and initialize a new event structure. // Status = CoreAllocatePool ( (Type & EFI_EVENT_RUNTIME) ? EfiRuntimeServicesData: EfiBootServicesData, sizeof (IEVENT), (VOID **)&IEvent ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } EfiCommonLibSetMem (IEvent, sizeof (IEVENT), 0); IEvent->Signature = EVENT_SIGNATURE; IEvent->Type = Type; IEvent->NotifyTpl = NotifyTpl; IEvent->NotifyFunction = NotifyFunction; IEvent->NotifyContext = (VOID *)NotifyContext; if (EventGroup != NULL) { EfiCommonLibCopyMem (&IEvent->EventGroup, (VOID*)EventGroup, sizeof (EFI_GUID)); IEvent->ExFlag = TRUE; } *Event = IEvent; if (Type & EFI_EVENT_RUNTIME) { // // Keep a list of all RT events so we can tell the RT AP. // IEvent->RuntimeData.Type = Type; IEvent->RuntimeData.NotifyTpl = NotifyTpl; IEvent->RuntimeData.NotifyFunction = NotifyFunction; IEvent->RuntimeData.NotifyContext = NotifyContext; IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent; InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); } CoreAcquireEventLock (); if ((Type & EFI_EVENT_NOTIFY_SIGNAL) != 0x00000000) { // // The Event's NotifyFunction must be queued whenever the event is signaled // InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); } CoreReleaseEventLock (); // // Done // return EFI_SUCCESS; }
VOID CoreDispatchEventNotifies ( IN EFI_TPL Priority ) /*++ Routine Description: Dispatches all pending events. Arguments: Priority - The task priority level of event notifications to dispatch Returns: None --*/ { IEVENT *Event; EFI_LIST_ENTRY *Head; CoreAcquireEventLock (); ASSERT (gEventQueueLock.OwnerTpl == Priority); Head = &gEventQueue[Priority]; // // Dispatch all the pending notifications // while (!IsListEmpty (Head)) { Event = CR (Head->ForwardLink, IEVENT, NotifyLink, EVENT_SIGNATURE); RemoveEntryList (&Event->NotifyLink); Event->NotifyLink.ForwardLink = NULL; // // Only clear the SIGNAL status if it is a SIGNAL type event. // WAIT type events are only cleared in CheckEvent() // if (Event->Type & EFI_EVENT_NOTIFY_SIGNAL) { Event->SignalCount = 0; } CoreReleaseEventLock (); // // Notify this event // Event->NotifyFunction (Event, Event->NotifyContext); // // Check for next pending event // CoreAcquireEventLock (); } gEventPending &= ~(1 << Priority); CoreReleaseEventLock (); }