我的BIOS之行6-事件的使用

前言

UEFI已经不再支持中断了,所有的异步操作都是要通过事件来完成的,所以我在这一章节会教如何使用事件来完成一个非常简单的事件处理。

上一章节我们说到了hob,那么继续在这个上面来完善我们的code,需要做的是,在dex阶段通过event事件来驱动读取hob。

简介

一个来说事件会提供用于操作事件、定时器以及TPL(任务优先级)

UEFI事件服务

  • CreateEvent(生成一个事件对象)
  • CreateEventEx(生成一个事件对象并将改事件加入到一个组内)
  • CloseEvent(关闭事件对象)
  • SignalEvent(触发事件对象)
  • WaitForEvent(等待事件数组中的任一事件触发)
  • CheckEvent(检查事件状态)
  • SetTimer(设置定时器属性)
  • RaiseTPL(提升任务优先级)
  • RestoreTPL(恢复任务优先级)

一般你可以直接在uefispec.h中找到这个原型,而且在spec中也有详细的介绍,因此在这边我就以CreateEvent为例,简单介绍一下,spec应该会比我解释得更加清晰

  //
  // Event & Timer Services
  //
  EFI_CREATE_EVENT                  CreateEvent;
  EFI_SET_TIMER                     SetTimer;
  EFI_WAIT_FOR_EVENT                WaitForEvent;
  EFI_SIGNAL_EVENT                  SignalEvent;
  EFI_CLOSE_EVENT                   CloseEvent;
  EFI_CHECK_EVENT                   CheckEvent;

而EFI_CREATE_EVENT又可以找到,具体解释可以看上面的注释,也可以参考我的注释

/**
  Creates an event.
  @param[in]   Type             The type of event to create and its mode and attributes.
  @param[in]   NotifyTpl        The task priority level of event notifications, if needed.
  @param[in]   NotifyFunction   The pointer to the event's notification function, if any.
  @param[in]   NotifyContext    The pointer to the notification function's context; corresponds to parameter
                                Context in the notification function.
  @param[out]  Event            The 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 or more parameters are invalid.
  @retval EFI_OUT_OF_RESOURCES  The event could not be allocated.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_CREATE_EVENT)(
  IN  UINT32                       Type,//事件类型
  IN  EFI_TPL                      NotifyTpl,//事件Notification函数的优先级
  IN  EFI_EVENT_NOTIFY             NotifyFunction,//事件Notification函数
  IN  VOID                         *NotifyContext,//传给事件Notification函数的参数
  OUT EFI_EVENT                    *Event//生成的事件
  );

实例

创建事件

在这里我们只需要创建一个事件就可以了,不需要整组事件联动的,所以直接使用CreateEvent就可以了,如果是整组的话,就需要用CreateEventEx.

在入口函数中创建事件

Status = pBS->CreateEvent(
                 EVT_NOTIFY_WAIT,
                 TPL_NOTIFY,
                 (EFI_EVENT_NOTIFY)HomeWorkDxeHobnotify,
                 (VOID*)NULL,
                 &homeworkevent
                );

完成notification函数

注意在notification函数中我们用SignalEvent(Event)触发事件,也就是说我们目前的事件是直接被触发的,后面我们会通过其他手段来触发事件

VOID HomeWorkDxeHobnotify(
        IN EFI_EVENT                    Event,
        IN VOID                         *Context   
)
{
    EFI_GUID                GuidHob = HOB_LIST_GUID;
     HOMEWORK_HOB            *Homeworkhob=NULL;
     EFI_GUID                 HomeworkHobGuid=HOMEWORK_HOB_GUID;
     VOID                    *pHobList = NULL;
     EFI_STATUS              Status;
     pHobList = GetEfiConfigurationTable(pST, &GuidHob);
     if (!pHobList) return;
         
     Homeworkhob = (HOMEWORK_HOB*)pHobList;
     while (!EFI_ERROR(Status = FindNextHobByType(EFI_HOB_TYPE_GUID_EXTENSION, &Homeworkhob)))
     {
         if (guidcmp(&(*Homeworkhob).EfiHobGuidType.Name, &HomeworkHobGuid) == 0)
                     break;
     }
     if (EFI_ERROR(Status)) 
     {
          return;
     }else{
              OEM_TRACE("data=%d\n",Homeworkhob->homeworkdata);
     }
     
     pBS->SignalEvent(Event);
}

等待事件发生

Status =  pBS->WaitForEvent(1,&homeworkevent,&index);

WaitForEvent属于阻塞操作,指导Event数组中的事件被触发或者出错才会返回,其实我并不太建议这样做,毕竟这是一种浪费资源的行为,不过呢,我们在这边仅仅是为了实验,所以我就不说什么了。

posted @ 2023-08-15 14:25  King_Alex  阅读(178)  评论(0编辑  收藏  举报