ReactOS 0.4.16-dev-2633-g8dc9e50
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;
28
29/* FUNCTIONS *****************************************************************/
30
31static
32CODE_SEG("INIT")
33VOID
35{
37 PKPRCB Prcb = KeGetCurrentPrcb();
38
39 /* xor eax, eax; cpuid */
40 ASSERT((Instruction[1] == 0xC0) && // The byte [0] has different encodings
41 (Instruction[2] == 0x0F) &&
42 (Instruction[3] == 0xA2));
43
44 /*
45 * Starting with the Pentium Pro processor it is necessary to force
46 * the in-order execution of the RDTSC instruction using a serializing instruction.
47 * For more details, please refer to Section 3.1 of
48 * Intel "Using the RDTSC Instruction for Performance Monitoring".
49 *
50 * Patch the KeStallExecutionProcessor function to remove the serializing instruction
51 * for the Pentium and Pentium MMX processors.
52 */
53 if ((Prcb->CpuType < 6) && !strcmp(Prcb->VendorString, "GenuineIntel"))
54 {
55 /* Replace "xor eax, eax; cpuid" with "lea esi, [esi+0]" */
56 Instruction[0] = 0x8D;
57 Instruction[1] = 0x74;
58 Instruction[2] = 0x26;
59 Instruction[3] = 0x00;
60
62 }
63}
64
65static
66CODE_SEG("INIT")
69 _In_ ULONG XMax,
70 _In_reads_(XMax + 1) const ULONG64* ArrayY)
71{
72 ULONG X, SumXX;
73 ULONG64 SumXY;
74
75 /* Calculate the sum of the squares of X */
76 SumXX = (XMax * (XMax + 1) * (2 * XMax + 1)) / 6;
77
78 /* Calculate the sum of the differences to the first value weighted by X */
79 for (SumXY = 0, X = 1; X <= XMax; X++)
80 {
81 SumXY += X * (ArrayY[X] - ArrayY[0]);
82 }
83
84 /* Account for sample frequency */
85 SumXY *= SAMPLE_FREQUENCY;
86
87 /* Return the quotient of the sums */
88 return (SumXY + (SumXX / 2)) / SumXX;
89}
90
91CODE_SEG("INIT")
92VOID
95{
97 PVOID PreviousHandler;
98 TIMER_CONTROL_PORT_REGISTER TimerControl;
99 ULONG TimerFrequency;
101 ULONG64 CpuClockFrequency;
102
103 /* Check if the CPU supports RDTSC */
104 if (!(KeGetCurrentPrcb()->FeatureBits & KF_RDTSC))
105 {
106 KeBugCheck(HAL_INITIALIZATION_FAILED);
107 }
108
110 _disable();
111
112 PreviousHandler = KeQueryInterruptHandler(PIC_TIMER_IRQ);
114
115 /* Program the PIT for binary mode */
116 TimerControl.BcdMode = FALSE;
117 TimerControl.OperatingMode = PitOperatingMode2;
118 TimerControl.Channel = PitChannel0;
119 TimerControl.AccessMode = PitAccessModeLowHigh;
120
121 if (__inbyte(0x42) & 0x20)
122 TimerFrequency = TIMER_FREQUENCY_1;
123 else
124 TimerFrequency = TIMER_FREQUENCY_2;
125 Period = (TimerFrequency + (SAMPLE_FREQUENCY / 2)) / SAMPLE_FREQUENCY;
126
127 __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
130
132
133 /* Collect the sample data */
134 _enable();
135 while (TscCalibrationPhase != (NUM_SAMPLES + 1))
136 NOTHING;
137 _disable();
138
141
142 /* Calculate an average, using simplified linear regression */
144 KeGetPcr()->StallScaleFactor = (ULONG)(CpuClockFrequency / 1000000);
145
147
149}
#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
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:68
#define SAMPLE_FREQUENCY
Definition: delay.c:20
static VOID HalpPrepareStallExecution(VOID)
Definition: delay.c:34
VOID NTAPI HalpCalibrateStallExecution(VOID)
Definition: delay.c:94
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
#define KeStallExecutionProcessor(MicroSeconds)
Definition: precomp.h:27
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
#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