UEFI开发与调试---事件的处理

UEFI SPEC目前不支持多线程,是单线程环境,但是它必须提供一种异步机制来支持有限多任务。UEFI不再为开发者提供中断支持,也就是说我们无法利用UEFI提供的接口设置中断服务程序,那么如果来实现异步操作呢?那就用到了本章所介绍的事件(Event)功能,UEFI提供了对事件Event的支持,Event的内部实现当然也是依赖与中断的。事件的支持是由BootServices启动服务表提供的。

事件接口

主要包含如下接口:

EFI_CREATE_EVENT                  CreateEvent;
EFI_CREATE_EVENT_EX               CreateEventEx;
EFI_SET_TIMER                     SetTimer;
EFI_WAIT_FOR_EVENT                WaitForEvent;
EFI_SIGNAL_EVENT                  SignalEvent;
EFI_CLOSE_EVENT                   CloseEvent;
EFI_CHECK_EVENT                   CheckEvent;

既然是异步处理,那么就会有一个优先级的问题,BootServices同样提供了任务优先级处理函数:

EFI_RAISE_TPL                   RaiseTPL;
EFI_RESTORE_TPL                 RestoreTPL;

一个事件生产者会使用到的接口是CreateEvent/CreateEventEx/SignalEvent/CloseEvent,事件使用者会使用的接口为WaitForEvent/CheckEvent。

 typedef
 EFI_STATUS
 (EFIAPI *EFI_CREATE_EVENT)(
   IN  UINT32                       Type,
   IN  EFI_TPL                      NotifyTpl,
   IN  EFI_EVENT_NOTIFY             NotifyFunction,
   IN  VOID                         *NotifyContext,
   OUT EFI_EVENT                    *Event
   );
  • Type
    事件类型:

    EVT_TIMER     //定时器事件,没有notify函数
    EVT_NOTIFY_WAIT //普通事件,有notify函数,当WaitForEvent()和CheckEvent()时,此notify函数被放到待执行队列
    EVT_NOTIFY_SIGNAL//普通事件,有notify函数,当SignalEvent()触发时,此notify函数被放到待执行队列,通常配合定时器事件使用
    EVT_SIGNAL_EXIT_BOOT_SERVICES //特殊事件
    EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE //特殊事件
    EVT_RUNTIME_CONTEXT //特殊事件
    EVT_RUNTIME   //特殊事件
    EVT_TIMER | EVT_NOTIFY_WAIT  //带有notify函数的定时器事件,触发类型和EVT_NOTIFY_WAIT
    EVT_TIMER | EVT_NOTIFY_SIGNAL //带有notify函数的定时器事件,触发类型和EVT_NOTIFY_SIGNAL一样

    由此函数原型,可知我们在创建事件时需要传入一个NotifyFunction,这个就是event回调函数,当事件发生时要执行的操作。

  • NotifyTpl
    事件优先级别:

    //
    // Task priority level
    //
    
    #define TPL_APPLICATION       4
    
    
    #define TPL_CALLBACK          8
    
    
    #define TPL_NOTIFY            16
    
    
    #define TPL_HIGH_LEVEL        31
    
    

    其数值越大,优先级别越高。上面定义的运行级别是针对UEFI中的所有任务而言,而并非仅仅针对事件,对于大部分事件,其NotifyTpl一般都可以设置为TPL_NOTIFY级别。

  • NotifyFunction
    Event回调函数,根据Type类型的不同,可以选择传入此函数,定时器类型是不需要此参数的,所以要设置为NULL。

  • NotifyContext
    回调函数的参数。

  • Event
    返回创建成功的Event句柄。

定时器事件

对于定时器事件的创建,我们需要执行如下步骤:

1.创建EVT_TIMER类型的事件
2.通过SetTimer设置定时器属性

实例:

EFI_STATUS MyTimer()
{
    EFI_STATUS Status;
    EFI_STATUS myEvent;
    UINTN index = 0;
    //step 1
    Status = gBS->CreateEvent(EVT_TIMER, TPL_CALLBACK, (EFI_EVENT_NOTIFY)NULL, (void *)NULL, &myEvent);
    //step 2
    Status = gBS->SetTimer(myEvent, TimerPeriodic, 10 * 1000 * 1000);
    while(1) {
        Status = gBS->WaitForEvent(1, &myEvent, &index);
        //timeout
    }
    gBS->CloseEvent(myEvent);
    return EFI_SUCCESS;
}

SetTimer的第二个参数,可以选择定时器的类型:

TimerCancel  //用于取消定时器触发,设置后定时器不再触发
TimerPeriodic //周期定时器 (单位100ns)
TimerRelative //一次性定时器(单位100ns)

时钟中断

UEFI内核实现采用的是一个单线程机制,不支持多线程操作,同时不对外提供中断支持,然而实际上异步操作的基础还是离不开中断。事件的实现就是利用了时钟中断,在时钟中断处理函数中,UEFI内核会检查系统中的定时器事件并处理到期的定时器时间,并在合适的时机调度事件的Notify函数,因此事件的实现基础就是时钟中断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值