ReactOS 0.4.17-dev-117-g313be0c
delay.c
Go to the documentation of this file.
1/*
2 * PROJECT: NEC PC-98 series HAL
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: TSC calibration for the busy-wait loop routine
5 * COPYRIGHT: Copyright 2011 Timo Kreuzer <timo.kreuzer@reactos.org>
6 * Copyright 2026 Dmitry Borisov <di.sean@protonmail.com>
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <hal.h>
12
13#define NDEBUG
14#include <debug.h>
15
16#include "delay.h"
17
18/* GLOBALS *******************************************************************/
19
20#define SAMPLE_FREQUENCY 1024 // 0.977 ms
21
22VOID
25
26extern volatile ULONG TscCalibrationPhase;
29
30/* FUNCTIONS *****************************************************************/
31
32static
33CODE_SEG("INIT")
34VOID
36{
38 PKPRCB Prcb = KeGetCurrentPrcb();
39
40 /* xor eax, eax; cpuid */
41 ASSERT((Instruction[1] == 0xC0) && // The byte [0] has different encodings
42 (Instruction[2] == 0x0F) &&
43 (Instruction[3] == 0xA2));
44
45 /*
46 * Starting with the Pentium Pro processor it is necessary to force
47 * the in-order execution of the RDTSC instruction using a serializing instruction.
48 * For more details, please refer to Section 3.1 of
49 * Intel "Using the RDTSC Instruction for Performance Monitoring".
50 *
51 * Patch the KeStallExecutionProcessor function to remove the serializing instruction
52 * for the Pentium and Pentium MMX processors because the CPUID instruction is slow.
53 */
54 if ((Prcb->CpuType < 6) && !strcmp(Prcb->VendorString, "GenuineIntel"))
55 {
56 /* Replace "xor eax, eax; cpuid" with "lea esi, [esi+0]" */
57 Instruction[0] = 0x8D;
58 Instruction[1] = 0x74;
59 Instruction[2] = 0x26;
60 Instruction[3] = 0x00;
61
63 }
64}
65
66static
67CODE_SEG("INIT")
70 _In_ ULONG XMax,
71 _In_reads_(XMax + 1) const ULONG64* ArrayY)
72{
73 ULONG X, SumXX;
74 ULONG64 SumXY;
75
76 /* Calculate the sum of the squares of X */
77 SumXX = (XMax * (XMax + 1) * (2 * XMax + 1)) / 6;
78
79 /* Calculate the sum of the differences to the first value weighted by X */
80 for (SumXY = 0, X = 1; X <= XMax; X++)
81 {
82 SumXY += X * (ArrayY[X] - ArrayY[0]);
83 }
84
85 /* Account for sample frequency */
86 SumXY *= SAMPLE_FREQUENCY;
87
88 /* Return the quotient of the sums */
89 return (SumXY + (SumXX / 2)) / SumXX;
90}
91
92CODE_SEG("INIT")
93VOID
96{
98 PVOID PreviousHandler;
99 TIMER_CONTROL_PORT_REGISTER TimerControl;
100 ULONG TimerFrequency;
102 ULONG64 CpuClockFrequency;
103
104 /* Check if the CPU supports RDTSC */
105 if (!(KeGetCurrentPrcb()->FeatureBits & KF_RDTSC))
106 {
107 KeBugCheck(HAL_INITIALIZATION_FAILED);
108 }
109
111 _disable();
112
113 PreviousHandler = KeQueryInterruptHandler(PIC_TIMER_IRQ);
115
116 /* Program the PIT for binary mode */
117 TimerControl.BcdMode = FALSE;
118 TimerControl.OperatingMode = PitOperatingMode2;
119 TimerControl.Channel = PitChannel0;
120 TimerControl.AccessMode = PitAccessModeLowHigh;
121
122 if (__inbyte(0x42) & 0x20)
123 TimerFrequency = TIMER_FREQUENCY_1;
124 else
125 TimerFrequency = TIMER_FREQUENCY_2;
126 Period = (TimerFrequency + (SAMPLE_FREQUENCY / 2)) / SAMPLE_FREQUENCY;
127
128 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
131
133
134 /* Collect the sample data */
135 _enable();
136 while (TscCalibrationPhase != (NUM_SAMPLES + 1))
137 NOTHING;
138 _disable();
139
142
143 /* Calculate an average, using simplified linear regression */
145 KeGetPcr()->StallScaleFactor = (ULONG)(CpuClockFrequency / 1000000);
146
148
150}
#define CODE_SEG(...)
@ Instruction
Definition: asmpp.cpp:82
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1434
#define FALSE
Definition: types.h:117
#define __cdecl
Definition: corecrt.h:121
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3319
#define CLOCK2_LEVEL
Definition: env_spec_w32.h:700
BOOLEAN NTAPI HalEnableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode)
Definition: pic.c:295
VOID NTAPI HalDisableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql)
Definition: pic.c:309
UCHAR HalpStallExecutionSerialize
ULONG64 TscCalibrationArray[NUM_SAMPLES]
Definition: tsc.c:20
VOID __cdecl HalpTscCalibrationISR(VOID)
static ULONG64 HalpDoLinearRegression(_In_ ULONG XMax, _In_reads_(XMax+1) const ULONG64 *ArrayY)
Definition: delay.c:69
#define SAMPLE_FREQUENCY
Definition: delay.c:20
static VOID HalpPrepareStallExecution(VOID)
Definition: delay.c:35
VOID NTAPI HalpCalibrateStallExecution(VOID)
Definition: delay.c:95
volatile ULONG TscCalibrationPhase
Definition: tsc.c:19
#define PRIMARY_VECTOR_BASE
Definition: halp.h:16
@ PitChannel0
Definition: halhw.h:102
#define TIMER_CONTROL_PORT
Definition: halhw.h:70
@ PitAccessModeLowHigh
Definition: halhw.h:97
#define PIC_TIMER_IRQ
Definition: halhw.h:155
@ PitOperatingMode2
Definition: halhw.h:84
#define TIMER_CHANNEL0_DATA_PORT
Definition: halhw.h:67
#define X(b, s)
#define NOTHING
Definition: input_list.c:10
PPC_QUAL unsigned char __inbyte(const unsigned long Port)
Definition: intrin_ppc.h:539
PPC_QUAL void __outbyte(unsigned long const Port, const unsigned char Data)
Definition: intrin_ppc.h:605
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1701
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1706
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1187
#define KF_RDTSC
Definition: ketypes.h:32
#define KeGetPcr()
Definition: ketypes.h:81
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _In_
Definition: no_sal2.h:158
FORCEINLINE PVOID KeQueryInterruptHandler(IN ULONG Vector)
Definition: ke.h:329
FORCEINLINE VOID KeSweepICache(IN PVOID BaseAddress, IN SIZE_T FlushSize)
Definition: ke.h:282
FORCEINLINE VOID KeRegisterInterruptHandler(IN ULONG Vector, IN PVOID Handler)
Definition: ke.h:303
unsigned short USHORT
Definition: pedump.c:61
@ Latched
Definition: miniport.h:81
#define TIMER_FREQUENCY_1
Definition: pit.h:16
#define TIMER_FREQUENCY_2
Definition: pit.h:17
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
CHAR CpuType
Definition: ketypes.h:678
UCHAR VendorString[13]
Definition: ketypes.h:895
#define NUM_SAMPLES
Definition: tsc.h:5
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1313
#define const
Definition: zconf.h:233