/*++ 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; }