2025-04-27 07:49:33 -04:00

407 lines
6.3 KiB
C

/*++
Copyright(c) 1998 Microsoft Corporation
Module Name:
util.c
Abstract:
misc routines.
Author:
Todd Carpenter
Environment:
kernel mode
Revision History:
12-05-00 : created, toddcar
--*/
#include "processor.h"
#define MAX_ATTEMPTS 10
struct {
LARGE_INTEGER PerfStart;
LARGE_INTEGER PerfEnd;
LONGLONG PerfDelta;
LARGE_INTEGER PerfFreq;
LONGLONG TSCStart;
LONGLONG TSCEnd;
LONGLONG TSCDelta;
ULONG MHz;
} Samples[MAX_ATTEMPTS], *pSamp;
__inline
ULONGLONG
RDTSC()
{
__asm{ RDTSC }
}
__inline
CPUID(
IN ULONG CpuIdType,
OUT PULONG EaxReg,
OUT PULONG EbxReg,
OUT PULONG EcxReg,
OUT PULONG EdxReg
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG eaxTemp, ebxTemp, ecxTemp, edxTemp;
_asm {
mov eax, DWORD PTR CpuIdType
xor ebx, ebx
xor ecx, ecx
xor edx, edx
cpuid
mov eaxTemp, eax
mov ebxTemp, ebx
mov ecxTemp, ecx
mov edxTemp, edx
}
*EaxReg = eaxTemp;
*EbxReg = ebxTemp;
*EcxReg = ecxTemp;
*EdxReg = edxTemp;
}
__inline
ULONGLONG
ReadMSR(
IN ULONG MSR
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULARGE_INTEGER msrContents;
_asm {
xor edx, edx
mov ecx, MSR
rdmsr
mov msrContents.LowPart, eax
mov msrContents.HighPart, edx
}
return msrContents.QuadPart;
}
__inline
WriteMSR(
IN ULONG MSR,
IN ULONG64 MSRInfo
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULARGE_INTEGER data;
data.QuadPart = MSRInfo;
_asm {
mov eax, data.LowPart
mov edx, data.HighPart
mov ecx, MSR
wrmsr
}
}
NTSTATUS
CalculateCpuFrequency(
OUT PULONG Freq
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG Index;
ULONG Average;
ULONG Junk;
Index = 0;
pSamp = Samples;
for (; ;) {
//
// Collect a new sample
// Delay the thread a "long" amount and time it with
// a time source and RDTSC.
//
CPUID(0, &Junk, &Junk, &Junk, &Junk);
pSamp->PerfStart = KeQueryPerformanceCounter(NULL);
pSamp->TSCStart = RDTSC();
pSamp->PerfFreq.QuadPart = -50000;
KeDelayExecutionThread (KernelMode, FALSE, &pSamp->PerfFreq);
CPUID(0, &Junk, &Junk, &Junk, &Junk);
pSamp->PerfEnd = KeQueryPerformanceCounter(&pSamp->PerfFreq);
pSamp->TSCEnd = RDTSC();
//
// Calculate processors MHz
//
pSamp->PerfDelta = pSamp->PerfEnd.QuadPart - pSamp->PerfStart.QuadPart;
pSamp->TSCDelta = pSamp->TSCEnd - pSamp->TSCStart;
pSamp->MHz = (ULONG) ((pSamp->TSCDelta * pSamp->PerfFreq.QuadPart + 500000L) /
(pSamp->PerfDelta * 1000000L));
//
// If last 2 samples matched within a MHz, done
//
if (Index) {
if (pSamp->MHz == pSamp[-1].MHz ||
pSamp->MHz == pSamp[-1].MHz + 1 ||
pSamp->MHz == pSamp[-1].MHz - 1) {
break;
}
}
//
// Advance to next sample
//
pSamp += 1;
Index += 1;
//
// If too many samples, then something is wrong
//
if (Index >= MAX_ATTEMPTS) {
//
// Temp breakpoint to see where this is failing
// and why
//
TRAP();
Average = 0;
for (Index = 0; Index < MAX_ATTEMPTS; Index++) {
Average += Samples[Index].MHz;
}
pSamp[-1].MHz = Average / MAX_ATTEMPTS;
break;
}
}
if (ARGUMENT_PRESENT(Freq)) {
*Freq = pSamp[-1].MHz;
}
return STATUS_SUCCESS;
}
NTSTATUS
GetCPUIDProcessorBrandString (
PUCHAR ProcessorString,
PULONG Size
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
#define CPUID_EXTENDED_FUNCTION 0x80000000
#define CPUID_80000002 0x80000002 // first 16 bytes
#define CPUID_80000003 0x80000003 // second 16 bytes
#define CPUID_80000004 0x80000004 // third 16 bytes
#define CPUID_BRAND_STRING_LENGTH 49
ULONG x, extdFunctions, junk;
PULONG string = (PULONG) ProcessorString;
DebugEnter();
DebugAssert(Size);
//
// if empty buffer or buffer too small, return the size needed
//
if (!ProcessorString ||
(ProcessorString && (*Size < CPUID_BRAND_STRING_LENGTH))) {
*Size = CPUID_BRAND_STRING_LENGTH;
return STATUS_BUFFER_TOO_SMALL;
}
//
// Check if extended CPUID functions are supported
//
CPUID(CPUID_EXTENDED_FUNCTION, &extdFunctions, &junk, &junk, &junk);
//
// check to see if Processor Name Brand String functions are supported,
// then loop through supported functions.
//
if (extdFunctions >= CPUID_80000002) {
ULONG max = (extdFunctions > CPUID_80000004) ? CPUID_80000004 : extdFunctions;
for (x=CPUID_80000002; x <= max; x++) {
CPUID(x, string, string+1, string+2, string+3);
string += 4;
}
} else {
DebugPrint((WARN, "GetCPUIDProcessorBrandString: CPUID Extended Functions not supported!\n"));
return STATUS_NOT_SUPPORTED;
}
//
// some processors forget to NULL terminate
//
ProcessorString[CPUID_BRAND_STRING_LENGTH-1] = 0;
//
// record size used.
//
*Size = CPUID_BRAND_STRING_LENGTH;
return STATUS_SUCCESS;
}
ULONG
GetCheckSum (
IN PUCHAR Address,
IN ULONG Length
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULONG i;
UCHAR sum = 0;
if (!Length) {
return 0;
}
for (i = 0; i < Length; i++) {
sum += Address[i];
}
return sum;
}
ULONG
Bcd8ToUlong(
IN ULONG BcdValue
)
{
#define NIBBLE_SIZE 4
ULONG intValue = 0;
ULONG powerOfTen = 1;
while (BcdValue) {
intValue += (BcdValue & 0xF) * powerOfTen;
BcdValue >>= NIBBLE_SIZE;
powerOfTen *= 10;
}
return intValue;
}