Home | History | Annotate | Download | only in Misc
      1 /** @file
      2   UEFI Miscellaneous boot Services Stall service implementation
      3 
      4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 //
     16 // Include statements
     17 //
     18 
     19 #include "DxeMain.h"
     20 
     21 /**
     22   Internal worker function to call the Metronome Architectural Protocol for
     23   the number of ticks specified by the UINT64 Counter value.  WaitForTick()
     24   service of the Metronome Architectural Protocol uses a UINT32 for the number
     25   of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
     26 
     27   @param  Counter           Number of ticks to wait.
     28 
     29 **/
     30 VOID
     31 CoreInternalWaitForTick (
     32   IN UINT64  Counter
     33   )
     34 {
     35   while (RShiftU64 (Counter, 32) > 0) {
     36     gMetronome->WaitForTick (gMetronome, 0xffffffff);
     37     Counter -= 0xffffffff;
     38   }
     39   gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
     40 }
     41 
     42 /**
     43   Introduces a fine-grained stall.
     44 
     45   @param  Microseconds           The number of microseconds to stall execution.
     46 
     47   @retval EFI_SUCCESS            Execution was stalled for at least the requested
     48                                  amount of microseconds.
     49   @retval EFI_NOT_AVAILABLE_YET  gMetronome is not available yet
     50 
     51 **/
     52 EFI_STATUS
     53 EFIAPI
     54 CoreStall (
     55   IN UINTN            Microseconds
     56   )
     57 {
     58   UINT64  Counter;
     59   UINT32  Remainder;
     60   UINTN   Index;
     61 
     62   if (gMetronome == NULL) {
     63     return EFI_NOT_AVAILABLE_YET;
     64   }
     65 
     66   //
     67   // Counter = Microseconds * 10 / gMetronome->TickPeriod
     68   // 0x1999999999999999 = (2^64 - 1) / 10
     69   //
     70   if (Microseconds > 0x1999999999999999ULL) {
     71     //
     72     // Microseconds is too large to multiple by 10 first.  Perform the divide
     73     // operation first and loop 10 times to avoid 64-bit math overflow.
     74     //
     75     Counter = DivU64x32Remainder (
     76                 Microseconds,
     77                 gMetronome->TickPeriod,
     78                 &Remainder
     79                 );
     80     for (Index = 0; Index < 10; Index++) {
     81       CoreInternalWaitForTick (Counter);
     82     }
     83 
     84     if (Remainder != 0) {
     85       //
     86       // If Remainder was not zero, then normally, Counter would be rounded
     87       // up by 1 tick.  In this case, since a loop for 10 counts was used
     88       // to emulate the multiply by 10 operation, Counter needs to be rounded
     89       // up by 10 counts.
     90       //
     91       CoreInternalWaitForTick (10);
     92     }
     93   } else {
     94     //
     95     // Calculate the number of ticks by dividing the number of microseconds by
     96     // the TickPeriod.  Calculation is based on 100ns unit.
     97     //
     98     Counter = DivU64x32Remainder (
     99                 MultU64x32 (Microseconds, 10),
    100                 gMetronome->TickPeriod,
    101                 &Remainder
    102                 );
    103     if (Remainder != 0) {
    104       //
    105       // If Remainder is not zero, then round Counter up by one tick.
    106       //
    107       Counter++;
    108     }
    109     CoreInternalWaitForTick (Counter);
    110   }
    111 
    112   return EFI_SUCCESS;
    113 }
    114