Skip to content

Commit

Permalink
UefiCpuPkg: CpuTimerDxeRiscV64: fix tick duration accounting
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Sunil V L <[email protected]>
Signed-off-by: Andrei Warkentin <[email protected]>
  • Loading branch information
Andrei Warkentin authored and mergify[bot] committed Mar 8, 2023
1 parent db0a308 commit 5ad2592
Showing 1 changed file with 21 additions and 14 deletions.
35 changes: 21 additions & 14 deletions UefiCpuPkg/CpuTimerDxeRiscV64/Timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -154,8 +163,6 @@ TimerDriverSetTimerPeriod (
IN UINT64 TimerPeriod
)
{
UINT64 RiscvTimer;

DEBUG ((DEBUG_INFO, "TimerDriverSetTimerPeriod(0x%lx)\n", TimerPeriod));

if (TimerPeriod == 0) {
Expand All @@ -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
Expand Down

0 comments on commit 5ad2592

Please sign in to comment.