BIOS/UEFI基础——优先级

时间:2024-04-04 14:00:31

UEFI下的优先级

UEFI SPEC中定义了如下几种优先级:

BIOS/UEFI基础——优先级

对应到EDK代码中是一个整型,如下所示:

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

关于优先级有以下需要注意的点:

1. 优先级是与Boot Service同时存在的,因此在PEI阶段,以及ExitBootServices事件之后都没有意义了;

2. 目前提供给外部接口使用的只有三种优先级:TPL_APPLICATION、TPL_CALLBACK和TPL_NOTIFY,它们的优先级依次增加;至于TPL_HIGH_LEVEL以及其它没有具体名称的优先级是供内部使用的,一般代码不应该去使用;

3. 高优先级的任务可以打断低优先级的任务;

4. 高优先级的任务执行的时间要求越短,否则就可能导致异常;

5. TPL_APPLICATION是通常代码下的优先级,TPL_HIGH_LEVEL是最高优先级无法被中断;

6. 通常是事件来触发更好的优先级代码的执行;

关于目前各个模块(Protocol)的优先级可以在UEFI SPEC中找到,这里不再列举。

 

优先级的操作函数

Boot Services中提供了两个接口用来操作优先级:

typedef
EFI_BOOTSERVICE
EFI_TPL
(EFIAPI *EFI_RAISE_TPL) (
  IN EFI_TPL      NewTpl
  );

typedef
EFI_BOOTSERVICE
VOID
(EFIAPI *EFI_RESTORE_TPL) (
  IN EFI_TPL      OldTpl
  );

前者用来设置当前的优先级并返回原始的优先级;

后者恢复到原来的优先级。

两个函数配合使用,可以自行提供当前的优先级以防止代码被打断。

下面是一个例子,代码来自Ping.c:

/**
  Get the timer period of the system.

  This function tries to get the system timer period by creating
  an 1ms period timer.

  @return     System timer period in MS, or 0 if operation failed.

**/
UINT32
GetTimerPeriod(
  VOID
  )
{
  EFI_STATUS                 Status;
  UINT32                     RttTimerTick;
  EFI_EVENT                  TimerEvent;
  UINT32                     StallCounter;
  EFI_TPL                    OldTpl;

  RttTimerTick = 0;
  StallCounter   = 0;

  Status = gBS->CreateEvent (
                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
                  TPL_NOTIFY,
                  RttTimerTickRoutine,
                  &RttTimerTick,
                  &TimerEvent
                  );
  if (EFI_ERROR (Status)) {
    return 0;
  }

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
  Status = gBS->SetTimer (
                  TimerEvent,
                  TimerPeriodic,
                  TICKS_PER_MS
                  );
  if (EFI_ERROR (Status)) {
    gBS->CloseEvent (TimerEvent);
    return 0;
  }

  while (RttTimerTick < 10) {
    gBS->Stall (STALL_1_MILLI_SECOND);
    ++StallCounter;
  }

  gBS->RestoreTPL (OldTpl);

  gBS->SetTimer (TimerEvent, TimerCancel, 0);
  gBS->CloseEvent (TimerEvent);

  return StallCounter / RttTimerTick;
}

除了上述的两个基本函数,还有其它的函数也会用到,比如说创建事件的函数:

/**
  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,
  IN  EFI_EVENT_NOTIFY             NotifyFunction,
  IN  VOID                         *NotifyContext,
  OUT EFI_EVENT                    *Event
  );

这里的优先级表示了回调函数的优先级。