]> xenbits.xensource.com Git - ovmf.git/commitdiff
UefiCpuPkg: CpuTimerDxeRiscV64: fix tick duration accounting
authorAndrei Warkentin <andrei.warkentin@intel.com>
Sat, 18 Feb 2023 00:44:51 +0000 (18:44 -0600)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 8 Mar 2023 18:10:34 +0000 (18:10 +0000)
The TimerDxe implementation doesn't account for the physical
time passed due to timer handler execution or (perhaps even
more importantly) time spent with interrupts masked.

Other implementations (e.g. like the Arm one) do. If the
timer tick is always incremented at a fixed rate, then
you can slow down UEFI's perception of time by running
long sections of code in a critical section.

Cc: Daniel Schaefer <git@danielschaefer.me>
Reviewed-by: Sunil V L <sunilvl@ventanamicro.com>
Signed-off-by: Andrei Warkentin <andrei.warkentin@intel.com>
UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c

index db153f715e60090d32a794974f4eecfa47c13170..287e7e133048c25714bb537b7d82d869bdf5c235 100644 (file)
@@ -40,7 +40,8 @@ STATIC EFI_TIMER_NOTIFY  mTimerNotifyFunction;
 //\r
 // The current period of the timer interrupt\r
 //\r
-STATIC UINT64  mTimerPeriod = 0;\r
+STATIC UINT64  mTimerPeriod     = 0;\r
+STATIC UINT64  mLastPeriodStart = 0;\r
 \r
 /**\r
   Timer Interrupt Handler.\r
@@ -56,25 +57,33 @@ TimerInterruptHandler (
   )\r
 {\r
   EFI_TPL  OriginalTPL;\r
-  UINT64   RiscvTimer;\r
+  UINT64   PeriodStart;\r
+\r
+  PeriodStart = RiscVReadTimer ();\r
 \r
   OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
   if (mTimerNotifyFunction != NULL) {\r
-    mTimerNotifyFunction (mTimerPeriod);\r
+    //\r
+    // For any number of reasons, the ticks could be coming\r
+    // in slower than mTimerPeriod. For example, some code\r
+    // is doing a *lot* of stuff inside an EFI_TPL_HIGH\r
+    // critical section, and this should not cause the EFI\r
+    // time to increment slower. So when we take an interrupt,\r
+    // account for the actual time passed.\r
+    //\r
+    mTimerNotifyFunction (PeriodStart - mLastPeriodStart);\r
   }\r
 \r
-  RiscVDisableTimerInterrupt (); // Disable SMode timer int\r
-  RiscVClearPendingTimerInterrupt ();\r
   if (mTimerPeriod == 0) {\r
+    RiscVDisableTimerInterrupt ();\r
     gBS->RestoreTPL (OriginalTPL);\r
-    RiscVDisableTimerInterrupt (); // Disable SMode timer int\r
     return;\r
   }\r
 \r
-  RiscvTimer               = RiscVReadTimer ();\r
-  SbiSetTimer (RiscvTimer += mTimerPeriod);\r
-  gBS->RestoreTPL (OriginalTPL);\r
+  mLastPeriodStart          = PeriodStart;\r
+  SbiSetTimer (PeriodStart += mTimerPeriod);\r
   RiscVEnableTimerInterrupt (); // enable SMode timer int\r
+  gBS->RestoreTPL (OriginalTPL);\r
 }\r
 \r
 /**\r
@@ -154,8 +163,6 @@ TimerDriverSetTimerPeriod (
   IN UINT64                   TimerPeriod\r
   )\r
 {\r
-  UINT64  RiscvTimer;\r
-\r
   DEBUG ((DEBUG_INFO, "TimerDriverSetTimerPeriod(0x%lx)\n", TimerPeriod));\r
 \r
   if (TimerPeriod == 0) {\r
@@ -164,9 +171,9 @@ TimerDriverSetTimerPeriod (
     return EFI_SUCCESS;\r
   }\r
 \r
-  mTimerPeriod = TimerPeriod / 10; // convert unit from 100ns to 1us\r
-  RiscvTimer   = RiscVReadTimer ();\r
-  SbiSetTimer (RiscvTimer + mTimerPeriod);\r
+  mTimerPeriod     = TimerPeriod / 10; // convert unit from 100ns to 1us\r
+  mLastPeriodStart = RiscVReadTimer ();\r
+  SbiSetTimer (mLastPeriodStart + mTimerPeriod);\r
 \r
   mCpu->EnableInterrupt (mCpu);\r
   RiscVEnableTimerInterrupt (); // enable SMode timer int\r