]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.c
ArmPkg/ArmMmuLib: AARCH64: enable stack alignment checking
[mirror_edk2.git] / ArmPkg / Library / ArmArchTimerLib / ArmArchTimerLib.c
index a0e4f5804b57e04e9bad55d9a5e81d728c7664a5..b81293c5cfde0234a56abed42ece062d9dd6fab7 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Generic ARM implementation of TimerLib.h\r
 \r
-  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
+  Copyright (c) 2011-2016, ARM Limited. All rights reserved.\r
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
 #define TICKS_PER_MICRO_SEC     (PcdGet32 (PcdArmArchTimerFreqInHz)/1000000U)\r
 \r
+// Select appropriate multiply function for platform architecture.\r
+#ifdef MDE_CPU_ARM\r
+#define MultU64xN MultU64x32\r
+#else\r
+#define MultU64xN MultU64x64\r
+#endif\r
+\r
+\r
 RETURN_STATUS\r
 EFIAPI\r
 TimerConstructor (\r
@@ -34,7 +42,6 @@ TimerConstructor (
   // Check if the ARM Generic Timer Extension is implemented.\r
   //\r
   if (ArmIsArchTimerImplemented ()) {\r
-    UINTN TimerFreq;\r
 \r
     //\r
     // Check if Architectural Timer frequency is pre-determined by the platform\r
@@ -43,7 +50,7 @@ TimerConstructor (
     if (PcdGet32 (PcdArmArchTimerFreqInHz) != 0) {\r
       //\r
       // Check if ticks/uS is not 0. The Architectural timer runs at constant\r
-      // frequency, irrespective of CPU frequency. According to General Timer\r
+      // frequency, irrespective of CPU frequency. According to Generic Timer\r
       // Ref manual, lower bound of the frequency is in the range of 1-10MHz.\r
       //\r
       ASSERT (TICKS_PER_MICRO_SEC);\r
@@ -62,27 +69,49 @@ TimerConstructor (
     }\r
 \r
     //\r
-    // Architectural Timer Frequency must be set in the Secure privileged\r
+    // Architectural Timer Frequency must be set in Secure privileged\r
     // mode (if secure extension is supported).\r
     // If the reset value (0) is returned, just ASSERT.\r
     //\r
-    TimerFreq = ArmGenericTimerGetTimerFreq ();\r
-    ASSERT (TimerFreq != 0);\r
+    ASSERT (ArmGenericTimerGetTimerFreq () != 0);\r
+\r
   } else {\r
-    DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library can not be used.\n"));\r
+    DEBUG ((EFI_D_ERROR, "ARM Architectural Timer is not available in the CPU, hence this library cannot be used.\n"));\r
     ASSERT (0);\r
   }\r
 \r
   return RETURN_SUCCESS;\r
 }\r
 \r
+/**\r
+  A local utility function that returns the PCD value, if specified.\r
+  Otherwise it defaults to ArmGenericTimerGetTimerFreq.\r
+\r
+  @return The timer frequency.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+EFIAPI\r
+GetPlatformTimerFreq (\r
+  )\r
+{\r
+  UINTN TimerFreq;\r
+\r
+  TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);\r
+  if (TimerFreq == 0) {\r
+    TimerFreq = ArmGenericTimerGetTimerFreq ();\r
+  }\r
+  return TimerFreq;\r
+}\r
+\r
 \r
 /**\r
   Stalls the CPU for the number of microseconds specified by MicroSeconds.\r
 \r
   @param  MicroSeconds  The minimum number of microseconds to delay.\r
 \r
-  @return The value of MicroSeconds inputted.\r
+  @return The value of MicroSeconds input.\r
 \r
 **/\r
 UINTN\r
@@ -93,31 +122,14 @@ MicroSecondDelay (
 {\r
   UINT64 TimerTicks64;\r
   UINT64 SystemCounterVal;\r
-  UINT64 (EFIAPI\r
-          *MultU64xN) (\r
-            IN UINT64 Multiplicand,\r
-            IN UINTN  Multiplier\r
-            );\r
-  UINTN TimerFreq;\r
-\r
-#ifdef MDE_CPU_ARM\r
-  MultU64xN = MultU64x32;\r
-#else\r
-  MultU64xN = MultU64x64;\r
-#endif\r
 \r
-  TimerFreq = PcdGet32 (PcdArmArchTimerFreqInHz);\r
-  if (TimerFreq == 0) {\r
-    TimerFreq = ArmGenericTimerGetTimerFreq ();\r
-  }\r
-\r
-  // Calculate counter ticks that can represent requested delay:\r
+  // Calculate counter ticks that represent requested delay:\r
   //  = MicroSeconds x TICKS_PER_MICRO_SEC\r
   //  = MicroSeconds x Frequency.10^-6\r
   TimerTicks64 = DivU64x32 (\r
                    MultU64xN (\r
                      MicroSeconds,\r
-                     TimerFreq\r
+                     GetPlatformTimerFreq ()\r
                      ),\r
                    1000000U\r
                    );\r
@@ -127,7 +139,7 @@ MicroSecondDelay (
 \r
   TimerTicks64 += SystemCounterVal;\r
 \r
-  // Wait until delay count is expired.\r
+  // Wait until delay count expires.\r
   while (SystemCounterVal < TimerTicks64) {\r
     SystemCounterVal = ArmGenericTimerGetSystemCount ();\r
   }\r
@@ -218,14 +230,63 @@ GetPerformanceCounterProperties (
   )\r
 {\r
   if (StartValue != NULL) {\r
-    // Timer starts with the reload value\r
+    // Timer starts at 0\r
     *StartValue = (UINT64)0ULL ;\r
   }\r
 \r
   if (EndValue != NULL) {\r
-    // Timer counts down to 0x0\r
+    // Timer counts up.\r
     *EndValue = 0xFFFFFFFFFFFFFFFFUL;\r
   }\r
 \r
   return (UINT64)ArmGenericTimerGetTimerFreq ();\r
 }\r
+\r
+/**\r
+  Converts elapsed ticks of performance counter to time in nanoseconds.\r
+\r
+  This function converts the elapsed ticks of running performance counter to\r
+  time value in unit of nanoseconds.\r
+\r
+  @param  Ticks     The number of elapsed ticks of running performance counter.\r
+\r
+  @return The elapsed time in nanoseconds.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+GetTimeInNanoSecond (\r
+  IN      UINT64                     Ticks\r
+  )\r
+{\r
+  UINT64  NanoSeconds;\r
+  UINT32  Remainder;\r
+  UINT32  TimerFreq;\r
+\r
+  TimerFreq = GetPlatformTimerFreq ();\r
+  //\r
+  //          Ticks\r
+  // Time = --------- x 1,000,000,000\r
+  //        Frequency\r
+  //\r
+  NanoSeconds = MultU64xN (\r
+                  DivU64x32Remainder (\r
+                    Ticks,\r
+                    TimerFreq,\r
+                    &Remainder),\r
+                  1000000000U\r
+                  );\r
+\r
+  //\r
+  // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)\r
+  // will not overflow 64-bit.\r
+  //\r
+  NanoSeconds += DivU64x32 (\r
+                   MultU64xN (\r
+                     (UINT64) Remainder,\r
+                     1000000000U),\r
+                   TimerFreq\r
+                   );\r
+\r
+  return NanoSeconds;\r
+}\r