Add HPET and TSC stall execution backends
All checks were successful
Builds / ExectOS (amd64, debug) (push) Successful in -59m29s
Builds / ExectOS (amd64, release) (push) Successful in -59m30s
Builds / ExectOS (i686, debug) (push) Successful in -59m24s
Builds / ExectOS (i686, release) (push) Successful in -59m25s

This commit is contained in:
2026-05-07 20:24:19 +02:00
parent 689951cfde
commit 976eee9ce3
2 changed files with 99 additions and 9 deletions

View File

@@ -37,7 +37,7 @@ HL::Timer::CalibrateApicTimer()
HL::Pic::WriteApicRegister(APIC_TICR, InitialCount); HL::Pic::WriteApicRegister(APIC_TICR, InitialCount);
/* Stall CPU execution for exactly 10 milliseconds */ /* Stall CPU execution for exactly 10 milliseconds */
StallExecutionPit(10000); StallExecution(10000);
/* Read current tick count from APIC timer and clear APIC timer */ /* Read current tick count from APIC timer and clear APIC timer */
CurrentCount = HL::Pic::ReadApicRegister(APIC_TCCR); CurrentCount = HL::Pic::ReadApicRegister(APIC_TCCR);
@@ -87,7 +87,7 @@ HL::Timer::CalibrateTscCounter(VOID)
InitialTickCount = AR::CpuFunc::ReadTimeStampCounterProcessor(&TscAux); InitialTickCount = AR::CpuFunc::ReadTimeStampCounterProcessor(&TscAux);
/* Stall CPU execution for exactly 10 milliseconds */ /* Stall CPU execution for exactly 10 milliseconds */
StallExecutionPit(10000); StallExecution(10000);
/* Read current tick count from TSC */ /* Read current tick count from TSC */
FinalTickCount = AR::CpuFunc::ReadTimeStampCounterProcessor(&TscAux); FinalTickCount = AR::CpuFunc::ReadTimeStampCounterProcessor(&TscAux);
@@ -683,12 +683,12 @@ HL::Timer::ProbeTimerType(VOID)
/* Determine if the ACPI PM Timer port is physically provisioned */ /* Determine if the ACPI PM Timer port is physically provisioned */
if(AcpiTimerInfo->TimerPort != 0) if(AcpiTimerInfo->TimerPort != 0)
{ {
/* Route execution stalls through the active ACPI PM hardware */ /* Temporarily route execution stalls through the active ACPI PM hardware */
TimerRoutines.StallExecution = StallExecutionAcpiPm; TimerRoutines.StallExecution = StallExecutionAcpiPm;
} }
else else
{ {
/* Route execution stalls through the legacy PIT hardware */ /* Temporarily route execution stalls through the legacy PIT hardware */
TimerRoutines.StallExecution = StallExecutionPit; TimerRoutines.StallExecution = StallExecutionPit;
} }
@@ -720,27 +720,31 @@ HL::Timer::ProbeTimerType(VOID)
{ {
case TimerTsc: case TimerTsc:
/* Register the TSC */ /* Register the TSC */
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterTsc;
PerformanceFrequency = CalibrateTscCounter(); PerformanceFrequency = CalibrateTscCounter();
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterTsc;
TimerRoutines.StallExecution = StallExecutionTsc;
DebugPrint(L"Performance Counter: Invariant TSC @ %lluHz\n", PerformanceFrequency); DebugPrint(L"Performance Counter: Invariant TSC @ %lluHz\n", PerformanceFrequency);
break; break;
case TimerHpet: case TimerHpet:
/* Register the HPET */ /* Register the HPET */
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterHpet;
PerformanceFrequency = HpetFrequency; PerformanceFrequency = HpetFrequency;
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterHpet;
TimerRoutines.StallExecution = StallExecutionHpet;
DebugPrint(L"Performance Counter: HPET @ %lluHz\n", PerformanceFrequency); DebugPrint(L"Performance Counter: HPET @ %lluHz\n", PerformanceFrequency);
break; break;
case TimerAcpiPm: case TimerAcpiPm:
/* Register the ACPI PM */ /* Register the ACPI PM */
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterAcpiPm;
PerformanceFrequency = 3579545; PerformanceFrequency = 3579545;
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterAcpiPm;
TimerRoutines.StallExecution = StallExecutionAcpiPm;
KeInitializeSpinLock(&PerformanceCounterLock); KeInitializeSpinLock(&PerformanceCounterLock);
DebugPrint(L"Performance Counter: ACPI PM Timer\n"); DebugPrint(L"Performance Counter: ACPI PM Timer\n");
break; break;
default: default:
/* Register the legacy PIT */ /* Register the legacy PIT */
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterPit;
PerformanceFrequency = 1193182; PerformanceFrequency = 1193182;
TimerRoutines.QueryPerformanceCounter = QueryPerformanceCounterPit;
TimerRoutines.StallExecution = StallExecutionPit;
KeInitializeSpinLock(&PerformanceCounterLock); KeInitializeSpinLock(&PerformanceCounterLock);
DebugPrint(L"Performance Counter: Legacy PIT\n"); DebugPrint(L"Performance Counter: Legacy PIT\n");
break; break;
@@ -1264,6 +1268,50 @@ HL::Timer::StallExecutionAcpiPm(IN ULONG MicroSeconds)
} }
} }
/**
* Stalls the CPU execution for a specified duration (maximum 3 seconds) using the High Precision Event Timer (HPET).
*
* @param MicroSeconds
* Supplies the number of microseconds to stall execution.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
HL::Timer::StallExecutionHpet(IN ULONG MicroSeconds)
{
PHPET_REGISTERS Hpet;
ULONGLONG StartTick, TargetTicks;
/* Validate input parameter */
if(MicroSeconds == 0)
{
/* Nothing to do */
return;
}
else if(MicroSeconds > 3000000)
{
/* Cap execution stall to 3 seconds */
MicroSeconds = 3000000;
}
/* Cast the mapped virtual address to the HPET hardware register */
Hpet = (PHPET_REGISTERS)HpetAddress;
/* Calculate target ticks based on HPET frequency */
TargetTicks = ((ULONGLONG)MicroSeconds * PerformanceFrequency) / 1000000ULL;
StartTick = Hpet->MainCounterValue;
/* Spin until the elapsed ticks reach the target */
while((Hpet->MainCounterValue - StartTick) < TargetTicks)
{
/* Issue a PAUSE instruction to relieve memory bus contention */
AR::CpuFunc::YieldProcessor();
}
}
/** /**
* Stalls the CPU execution for a specified duration (maximum 3 seconds) using the legacy PIT timer. * Stalls the CPU execution for a specified duration (maximum 3 seconds) using the legacy PIT timer.
* *
@@ -1335,6 +1383,46 @@ HL::Timer::StallExecutionPit(IN ULONG MicroSeconds)
HL::IoPort::WritePort8(0x61, Port61State); HL::IoPort::WritePort8(0x61, Port61State);
} }
/**
* Stalls the CPU execution for a specified duration (maximum 3 seconds) using the Time Stamp Counter (TSC).
*
* @param MicroSeconds
* Supplies the number of microseconds to stall execution.
*
* @return This routine does not return any value.
*
* @since XT 1.0
*/
XTAPI
VOID
HL::Timer::StallExecutionTsc(IN ULONG MicroSeconds)
{
ULONGLONG StartTick, TargetTicks;
/* Validate input parameter */
if(MicroSeconds == 0)
{
/* Nothing to do */
return;
}
else if(MicroSeconds > 3000000)
{
/* Cap execution stall to 3 seconds */
MicroSeconds = 3000000;
}
/* Calculate target ticks based on calibrated TSC frequency */
TargetTicks = ((ULONGLONG)MicroSeconds * PerformanceFrequency) / 1000000ULL;
StartTick = AR::CpuFunc::ReadTimeStampCounter();
/* Spin until the elapsed ticks reach the target */
while((AR::CpuFunc::ReadTimeStampCounter() - StartTick) < TargetTicks)
{
/* Issue a PAUSE instruction to relieve memory bus contention */
AR::CpuFunc::YieldProcessor();
}
}
/** /**
* Enables the profile interrupt for the specified profile source. * Enables the profile interrupt for the specified profile source.
* *

View File

@@ -65,7 +65,9 @@ namespace HL
STATIC XTAPI VOID QueryTimerCapabilities(VOID); STATIC XTAPI VOID QueryTimerCapabilities(VOID);
STATIC XTAPI ULONG SetClockRateApic(ULONG TargetIncrement); STATIC XTAPI ULONG SetClockRateApic(ULONG TargetIncrement);
STATIC XTAPI VOID StallExecutionAcpiPm(IN ULONG MicroSeconds); STATIC XTAPI VOID StallExecutionAcpiPm(IN ULONG MicroSeconds);
STATIC XTAPI VOID StallExecutionHpet(IN ULONG MicroSeconds);
STATIC XTAPI VOID StallExecutionPit(IN ULONG MicroSeconds); STATIC XTAPI VOID StallExecutionPit(IN ULONG MicroSeconds);
STATIC XTAPI VOID StallExecutionTsc(IN ULONG MicroSeconds);
STATIC XTAPI BOOLEAN ValidateTimerSupport(IN TIMER_TYPE TimerType, STATIC XTAPI BOOLEAN ValidateTimerSupport(IN TIMER_TYPE TimerType,
IN BOOLEAN IsClock); IN BOOLEAN IsClock);
}; };