summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
diff options
context:
space:
mode:
authorAndrei Warkentin <andrei.warkentin@intel.com>2023-02-17 18:44:51 -0600
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2023-03-08 18:10:34 +0000
commit5ad2592ab370b6c9030d1239940046bdeec9c2c6 (patch)
tree295a62746bf284070455f9bf6d1a998b5cea0ef9 /UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
parentdb0a3087a535f54f3697e0d658a53bb78d57ce70 (diff)
downloadedk2-5ad2592ab370b6c9030d1239940046bdeec9c2c6.tar.gz
edk2-5ad2592ab370b6c9030d1239940046bdeec9c2c6.tar.bz2
edk2-5ad2592ab370b6c9030d1239940046bdeec9c2c6.zip
UefiCpuPkg: CpuTimerDxeRiscV64: fix tick duration accounting
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>
Diffstat (limited to 'UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c')
-rw-r--r--UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c b/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
index db153f715e..287e7e1330 100644
--- a/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
+++ b/UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
@@ -40,7 +40,8 @@ STATIC EFI_TIMER_NOTIFY mTimerNotifyFunction;
//
// The current period of the timer interrupt
//
-STATIC UINT64 mTimerPeriod = 0;
+STATIC UINT64 mTimerPeriod = 0;
+STATIC UINT64 mLastPeriodStart = 0;
/**
Timer Interrupt Handler.
@@ -56,25 +57,33 @@ TimerInterruptHandler (
)
{
EFI_TPL OriginalTPL;
- UINT64 RiscvTimer;
+ UINT64 PeriodStart;
+
+ PeriodStart = RiscVReadTimer ();
OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
if (mTimerNotifyFunction != NULL) {
- mTimerNotifyFunction (mTimerPeriod);
+ //
+ // For any number of reasons, the ticks could be coming
+ // in slower than mTimerPeriod. For example, some code
+ // is doing a *lot* of stuff inside an EFI_TPL_HIGH
+ // critical section, and this should not cause the EFI
+ // time to increment slower. So when we take an interrupt,
+ // account for the actual time passed.
+ //
+ mTimerNotifyFunction (PeriodStart - mLastPeriodStart);
}
- RiscVDisableTimerInterrupt (); // Disable SMode timer int
- RiscVClearPendingTimerInterrupt ();
if (mTimerPeriod == 0) {
+ RiscVDisableTimerInterrupt ();
gBS->RestoreTPL (OriginalTPL);
- RiscVDisableTimerInterrupt (); // Disable SMode timer int
return;
}
- RiscvTimer = RiscVReadTimer ();
- SbiSetTimer (RiscvTimer += mTimerPeriod);
- gBS->RestoreTPL (OriginalTPL);
+ mLastPeriodStart = PeriodStart;
+ SbiSetTimer (PeriodStart += mTimerPeriod);
RiscVEnableTimerInterrupt (); // enable SMode timer int
+ gBS->RestoreTPL (OriginalTPL);
}
/**
@@ -154,8 +163,6 @@ TimerDriverSetTimerPeriod (
IN UINT64 TimerPeriod
)
{
- UINT64 RiscvTimer;
-
DEBUG ((DEBUG_INFO, "TimerDriverSetTimerPeriod(0x%lx)\n", TimerPeriod));
if (TimerPeriod == 0) {
@@ -164,9 +171,9 @@ TimerDriverSetTimerPeriod (
return EFI_SUCCESS;
}
- mTimerPeriod = TimerPeriod / 10; // convert unit from 100ns to 1us
- RiscvTimer = RiscVReadTimer ();
- SbiSetTimer (RiscvTimer + mTimerPeriod);
+ mTimerPeriod = TimerPeriod / 10; // convert unit from 100ns to 1us
+ mLastPeriodStart = RiscVReadTimer ();
+ SbiSetTimer (mLastPeriodStart + mTimerPeriod);
mCpu->EnableInterrupt (mCpu);
RiscVEnableTimerInterrupt (); // enable SMode timer int