uefi 调用ExitBootServices

所有的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函数.
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值