mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
UefiCpuPkg/BaseRiscV64CpuTimerLib: Add constructor to initialize mTimeBase
Add a constructor function that calls GetPerformanceCounterProperties(NULL, NULL) to ensure mTimeBase is initialized during DXE phase, before virtual memory is enabled. This fixes crashes on RISC-V platforms without fw_cfg device support (e.g., QEMU rvsp-ref) where Runtime Services may call GetPerformanceCounterProperties() before mTimeBase has been initialized. When virtual memory is then enabled, the uninitialized mTimeBase value causes HOB access to fail with a page fault. Fixes: https://github.com/tianocore/edk2/issues/11747 Signed-off-by: Chao Liu <chao.liu.riscv@isrc.iscas.ac.cn> Reported-by: Xiaofan Tan <xiaofan@iscas.ac.cn> Suggested-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
parent
b1707d99ae
commit
f2c63dca1b
2 changed files with 64 additions and 50 deletions
|
|
@ -16,6 +16,7 @@
|
|||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = TimerLib
|
||||
MODULE_UNI_FILE = BaseRisV64CpuTimerLib.uni
|
||||
CONSTRUCTOR = BaseRiscV64CpuTimerLibConstructor
|
||||
|
||||
[Sources]
|
||||
CpuTimerLib.c
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@
|
|||
|
||||
STATIC UINT64 mTimeBase;
|
||||
|
||||
#define GET_TIME_BASE() (mTimeBase ?: GetPerformanceCounterProperties(NULL, NULL))
|
||||
|
||||
/**
|
||||
Stalls the CPU for at least the given number of ticks.
|
||||
|
||||
|
|
@ -67,7 +65,7 @@ MicroSecondDelay (
|
|||
DivU64x32 (
|
||||
MultU64x32 (
|
||||
MicroSeconds,
|
||||
GET_TIME_BASE ()
|
||||
mTimeBase
|
||||
),
|
||||
1000000u
|
||||
)
|
||||
|
|
@ -95,7 +93,7 @@ NanoSecondDelay (
|
|||
DivU64x32 (
|
||||
MultU64x32 (
|
||||
NanoSeconds,
|
||||
GET_TIME_BASE ()
|
||||
mTimeBase
|
||||
),
|
||||
1000000000u
|
||||
)
|
||||
|
|
@ -154,12 +152,6 @@ GetPerformanceCounterProperties (
|
|||
OUT UINT64 *EndValue OPTIONAL
|
||||
)
|
||||
{
|
||||
VOID *Hob;
|
||||
RISCV_SEC_HANDOFF_DATA *SecData;
|
||||
CONST EFI_GUID SecHobDataGuid = RISCV_SEC_HANDOFF_HOB_GUID;
|
||||
UINT64 TimeBase;
|
||||
CONST VOID *FdtBase;
|
||||
|
||||
if (StartValue != NULL) {
|
||||
*StartValue = 0;
|
||||
}
|
||||
|
|
@ -168,9 +160,66 @@ GetPerformanceCounterProperties (
|
|||
*EndValue = 32 - 1;
|
||||
}
|
||||
|
||||
if (mTimeBase != 0) {
|
||||
return mTimeBase;
|
||||
}
|
||||
return mTimeBase;
|
||||
}
|
||||
|
||||
/**
|
||||
Converts elapsed ticks of performance counter to time in nanoseconds.
|
||||
|
||||
This function converts the elapsed ticks of running performance counter to
|
||||
time value in unit of nanoseconds.
|
||||
|
||||
@param Ticks The number of elapsed ticks of running performance counter.
|
||||
|
||||
@return The elapsed time in nanoseconds.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetTimeInNanoSecond (
|
||||
IN UINT64 Ticks
|
||||
)
|
||||
{
|
||||
UINT64 NanoSeconds;
|
||||
UINT32 Remainder;
|
||||
|
||||
//
|
||||
// Ticks
|
||||
// Time = --------- x 1,000,000,000
|
||||
// Frequency
|
||||
//
|
||||
NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, mTimeBase, &Remainder), 1000000000u);
|
||||
|
||||
//
|
||||
// Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
|
||||
// will not overflow 64-bit.
|
||||
//
|
||||
NanoSeconds += DivU64x32 (MultU64x32 ((UINT64)Remainder, 1000000000u), mTimeBase);
|
||||
|
||||
return NanoSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
Constructor function for the Timer Library.
|
||||
|
||||
This constructor function is called early during DXE phase to ensure that
|
||||
GetPerformanceCounterProperties() is invoked and mTimeBase is initialized
|
||||
before any code that depends on it.
|
||||
|
||||
@retval EFI_SUCCESS The constructor always returns success.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
BaseRiscV64CpuTimerLibConstructor (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
VOID *Hob;
|
||||
RISCV_SEC_HANDOFF_DATA *SecData;
|
||||
CONST EFI_GUID SecHobDataGuid = RISCV_SEC_HANDOFF_HOB_GUID;
|
||||
UINT64 TimeBase;
|
||||
CONST VOID *FdtBase;
|
||||
|
||||
//
|
||||
// Locate the FDT HOB and validate header
|
||||
|
|
@ -224,41 +273,5 @@ GetPerformanceCounterProperties (
|
|||
//
|
||||
mTimeBase = TimeBase;
|
||||
|
||||
return TimeBase;
|
||||
}
|
||||
|
||||
/**
|
||||
Converts elapsed ticks of performance counter to time in nanoseconds.
|
||||
|
||||
This function converts the elapsed ticks of running performance counter to
|
||||
time value in unit of nanoseconds.
|
||||
|
||||
@param Ticks The number of elapsed ticks of running performance counter.
|
||||
|
||||
@return The elapsed time in nanoseconds.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetTimeInNanoSecond (
|
||||
IN UINT64 Ticks
|
||||
)
|
||||
{
|
||||
UINT64 NanoSeconds;
|
||||
UINT32 Remainder;
|
||||
|
||||
//
|
||||
// Ticks
|
||||
// Time = --------- x 1,000,000,000
|
||||
// Frequency
|
||||
//
|
||||
NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, GET_TIME_BASE (), &Remainder), 1000000000u);
|
||||
|
||||
//
|
||||
// Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
|
||||
// will not overflow 64-bit.
|
||||
//
|
||||
NanoSeconds += DivU64x32 (MultU64x32 ((UINT64)Remainder, 1000000000u), GET_TIME_BASE ());
|
||||
|
||||
return NanoSeconds;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue