ueif的stall的实现

xiaoxiao2021-02-27  210

在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 来实现。
转载请注明原文地址: https://www.6miu.com/read-16685.html

最新回复(0)