所有的boot service 都会在进入kernel的最后阶段退出,如果driver想接受这一个event的话,可以参考下面的写法创建一个新的event,注意一定要是 gEfiEventExitBootServicesGuid
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
XhcExitBootService,
Xhc,
&gEfiEventExitBootServicesGuid,
&Xhc->ExitBootServiceEvent
);
if (EFI_ERROR (Status)) {
goto FREE_POOL;
}
这样当调用CoreExitBootServices 是
EFI_STATUS
EFIAPI
CoreExitBootServices (
IN EFI_HANDLE ImageHandle,
IN UINTN MapKey
)
{
EFI_STATUS Status;
//
// Disable Timer
//
gTimer->SetTimerPeriod (gTimer, 0);
//
// Terminate memory services if the MapKey matches
//
Status = CoreTerminateMemoryMap (MapKey);
if (EFI_ERROR (Status)) {
//
// Notify other drivers that ExitBootServices fail
//
CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
return Status;
}
gMemoryMapTerminated = TRUE;
//
// Notify other drivers that we are exiting boot services.
//
CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
//
// Report that ExitBootServices() has been called
//
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
);
//
// Disable interrupt of Debug timer.
//
SaveAndSetDebugTimerInterrupt (FALSE);
//
// Disable CPU Interrupts
//
gCpu->DisableInterrupt (gCpu);
//
// Clear the non-runtime values of the EFI System Table
//
gDxeCoreST->BootServices = NULL;
gDxeCoreST->ConIn = NULL;
gDxeCoreST->ConsoleInHandle = NULL;
gDxeCoreST->ConOut = NULL;
gDxeCoreST->ConsoleOutHandle = NULL;
gDxeCoreST->StdErr = NULL;
gDxeCoreST->StandardErrorHandle = NULL;
//
// Recompute the 32-bit CRC of the EFI System Table
//
CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
//
// Zero out the Boot Service Table
//
ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
gBS = NULL;
//
// Update the AtRuntime field in Runtiem AP.
//
gRuntime->AtRuntime = TRUE;
return Status;
}
在CoreExitBootServices 中调用CoreNotifySignalList 来将要通知的event 添加到queue中
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 ();
}
CoreNotifySignalList 通过CompareGuid来比较guid是否是gEfiEventExitBootServicesGuid。如果是的话,就调用CoreNotifyEvent
VOID
CoreNotifyEvent (
IN IEVENT *Event
)
{
//
// Event database must be locked
//
ASSERT_LOCKED (&gEventQueueLock);
//
// If the event is queued somewhere, remove it
//
if (Event->NotifyLink.ForwardLink != NULL) {
RemoveEntryList (&Event->NotifyLink);
Event->NotifyLink.ForwardLink = NULL;
}
//
// Queue the event to the pending notification list
//
InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
gEventPending |= (UINTN)(1 << Event->NotifyTpl);
}
在CoreNotifyEvent 中就会将event添加到gEventQueue 这个queue中,并在gEventPending 之根据event的tpl 将对应的bit置1.
然后会在下一次time中断中调用CoreRestoreTpl。
VOID
EFIAPI
CoreRestoreTpl (
IN EFI_TPL NewTpl
)
{
while (((-2 << NewTpl) & gEventPending) != 0) {
gEfiCurrentTpl = (UINTN) HighBitSet64 (gEventPending);
if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
CoreSetInterruptState (TRUE);
}
CoreDispatchEventNotifies (gEfiCurrentTpl);
}
}
这个函数中就会检测gEventPending 只能个是否有置位,如果有的话,就调用CoreDispatchEventNotifies
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 &= ~(UINTN)(1 << Priority);
CoreReleaseEventLock ();
}
这个函数中就会遍历整个gEventQueue 分别调用其NotifyFunction函数.
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
XhcExitBootService,
Xhc,
&gEfiEventExitBootServicesGuid,
&Xhc->ExitBootServiceEvent
);
if (EFI_ERROR (Status)) {
goto FREE_POOL;
}
这样当调用CoreExitBootServices 是
EFI_STATUS
EFIAPI
CoreExitBootServices (
IN EFI_HANDLE ImageHandle,
IN UINTN MapKey
)
{
EFI_STATUS Status;
//
// Disable Timer
//
gTimer->SetTimerPeriod (gTimer, 0);
//
// Terminate memory services if the MapKey matches
//
Status = CoreTerminateMemoryMap (MapKey);
if (EFI_ERROR (Status)) {
//
// Notify other drivers that ExitBootServices fail
//
CoreNotifySignalList (&gEventExitBootServicesFailedGuid);
return Status;
}
gMemoryMapTerminated = TRUE;
//
// Notify other drivers that we are exiting boot services.
//
CoreNotifySignalList (&gEfiEventExitBootServicesGuid);
//
// Report that ExitBootServices() has been called
//
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)
);
//
// Disable interrupt of Debug timer.
//
SaveAndSetDebugTimerInterrupt (FALSE);
//
// Disable CPU Interrupts
//
gCpu->DisableInterrupt (gCpu);
//
// Clear the non-runtime values of the EFI System Table
//
gDxeCoreST->BootServices = NULL;
gDxeCoreST->ConIn = NULL;
gDxeCoreST->ConsoleInHandle = NULL;
gDxeCoreST->ConOut = NULL;
gDxeCoreST->ConsoleOutHandle = NULL;
gDxeCoreST->StdErr = NULL;
gDxeCoreST->StandardErrorHandle = NULL;
//
// Recompute the 32-bit CRC of the EFI System Table
//
CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
//
// Zero out the Boot Service Table
//
ZeroMem (gBS, sizeof (EFI_BOOT_SERVICES));
gBS = NULL;
//
// Update the AtRuntime field in Runtiem AP.
//
gRuntime->AtRuntime = TRUE;
return Status;
}
在CoreExitBootServices 中调用CoreNotifySignalList 来将要通知的event 添加到queue中
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 ();
}
CoreNotifySignalList 通过CompareGuid来比较guid是否是gEfiEventExitBootServicesGuid。如果是的话,就调用CoreNotifyEvent
VOID
CoreNotifyEvent (
IN IEVENT *Event
)
{
//
// Event database must be locked
//
ASSERT_LOCKED (&gEventQueueLock);
//
// If the event is queued somewhere, remove it
//
if (Event->NotifyLink.ForwardLink != NULL) {
RemoveEntryList (&Event->NotifyLink);
Event->NotifyLink.ForwardLink = NULL;
}
//
// Queue the event to the pending notification list
//
InsertTailList (&gEventQueue[Event->NotifyTpl], &Event->NotifyLink);
gEventPending |= (UINTN)(1 << Event->NotifyTpl);
}
在CoreNotifyEvent 中就会将event添加到gEventQueue 这个queue中,并在gEventPending 之根据event的tpl 将对应的bit置1.
然后会在下一次time中断中调用CoreRestoreTpl。
VOID
EFIAPI
CoreRestoreTpl (
IN EFI_TPL NewTpl
)
{
while (((-2 << NewTpl) & gEventPending) != 0) {
gEfiCurrentTpl = (UINTN) HighBitSet64 (gEventPending);
if (gEfiCurrentTpl < TPL_HIGH_LEVEL) {
CoreSetInterruptState (TRUE);
}
CoreDispatchEventNotifies (gEfiCurrentTpl);
}
}
这个函数中就会检测gEventPending 只能个是否有置位,如果有的话,就调用CoreDispatchEventNotifies
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 &= ~(UINTN)(1 << Priority);
CoreReleaseEventLock ();
}
这个函数中就会遍历整个gEventQueue 分别调用其NotifyFunction函数.