ueif的stall的实现

本文详细解析了UEFI环境中如何实现精确的延时操作,包括通过gBS->Stall函数进行10微秒延时的具体流程,以及背后的数学运算和时间转换机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在uefi 中一般通过下面的code来delay 10us
  // SRST should assert for at least 5 us, we use 10 us for
  // better compatibility
  //
  gBS->Stall (10);


其中gBs的stall是在mdemodulepkg/dxe/dxemain 中来赋值的
EFI_BOOT_SERVICES mBootServices = {
  {
    EFI_BOOT_SERVICES_SIGNATURE,                                                          // Signature
    EFI_BOOT_SERVICES_REVISION,                                                           // Revision
    sizeof (EFI_BOOT_SERVICES),                                                           // HeaderSize
    0,                                                                                    // CRC32
    0                                                                                     // Reserved
  },
  (EFI_STALL)                                   CoreStall,                                // Stall

而CoreStall 的实现如下:
EFI_STATUS
EFIAPI
CoreStall (
  IN UINTN            Microseconds
  )
{
  UINT64  Counter;
  UINT32  Remainder;
  UINTN   Index;

  if (gMetronome == NULL) {
    return EFI_NOT_AVAILABLE_YET;
  }

  //
  // Counter = Microseconds * 10 / gMetronome->TickPeriod
  // 0x1999999999999999 = (2^64 - 1) / 10
  //
由于我们delay的时间小于0x1999999999999999ULL,一次我们走else的case
  if (Microseconds > 0x1999999999999999ULL) {
    //
    // Microseconds is too large to multiple by 10 first.  Perform the divide
    // operation first and loop 10 times to avoid 64-bit math overflow.
    //
    Counter = DivU64x32Remainder (
                Microseconds,
                gMetronome->TickPeriod,
                &Remainder
                );
    for (Index = 0; Index < 10; Index++) {
      CoreInternalWaitForTick (Counter);
    }      

    if (Remainder != 0) {
      //
      // If Remainder was not zero, then normally, Counter would be rounded
      // up by 1 tick.  In this case, since a loop for 10 counts was used
      // to emulate the multiply by 10 operation, Counter needs to be rounded
      // up by 10 counts.
      //
      CoreInternalWaitForTick (10);
    }
  } else {
    //
    // Calculate the number of ticks by dividing the number of microseconds by
    // the TickPeriod.  Calculation is based on 100ns unit.
    //
计算需要delay的counter
    Counter = DivU64x32Remainder (
                MultU64x32 (Microseconds, 10),
                gMetronome->TickPeriod,
                &Remainder
                );
如果remainder 不为0,就说明counter 不是整数,因此我们直接加一,也就是说调用stall的时间最多比需要的时间多一个counter
    if (Remainder != 0) {
      //
      // If Remainder is not zero, then round Counter up by one tick.
      //
      Counter++;
    }
继续调用CoreInternalWaitForTick
    CoreInternalWaitForTick (Counter);
  }

  return EFI_SUCCESS;
}

在CoreInternalWaitForTick 中直接调用gMetronome的WaitForTick
CoreInternalWaitForTick (
  IN UINT64  Counter
  )
{
  while (RShiftU64 (Counter, 32) > 0) {
    gMetronome->WaitForTick (gMetronome, 0xffffffff);
    Counter -= 0xffffffff;
  }
  gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
}
gMetronome的定义如下:

EFI_CORE_PROTOCOL_NOTIFY_ENTRY  mArchProtocols[] = {
  { &gEfiSecurityArchProtocolGuid,         (VOID **)&gSecurity,      NULL, NULL, FALSE },
  { &gEfiCpuArchProtocolGuid,              (VOID **)&gCpu,           NULL, NULL, FALSE },
  { &gEfiMetronomeArchProtocolGuid,        (VOID **)&gMetronome,     NULL, NULL, FALSE },
}
gEfiCpuArchProtocolGuid定义如下:
EFI_STATUS
EFIAPI
WaitForTick (
  IN EFI_METRONOME_ARCH_PROTOCOL  *This,
  IN UINT32                       TickNumber
  )
{
  //
  // Check the value of TickNumber, so a 32-bit overflow can be avoided
  // when TickNumber of converted to nanosecond units
  //
  if (TickNumber < 10000000) {
    //
    // If TickNumber is small, then use NanoSecondDelay()
    //
    NanoSecondDelay (TickNumber * 100);
  } else {
    //
    // If TickNumber is large, then use MicroSecondDelay()
    //
    MicroSecondDelay (TickNumber / 10);
  }
  return EFI_SUCCESS;
}


EFI_STATUS
EFIAPI
InstallMetronome (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS  Status;

  //
  // Make sure the Metronome Architectural Protocol is not already installed in the system
  //
  ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiMetronomeArchProtocolGuid);

  //
  // Install on a new handle
  //
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &mMetronomeHandle,
                  &gEfiMetronomeArchProtocolGuid, &mMetronome,
                  NULL
                  );
  ASSERT_EFI_ERROR (Status);

  return Status;
}
可见在gEfiCpuArchProtocolGuid 中最终是通过NanoSecondDelay或者MicroSecondDelay 来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值