261 lines
5.6 KiB
C++
261 lines
5.6 KiB
C++
#include "precomp.h"
|
|
#include <oprahcom.h>
|
|
#include <regentry.h>
|
|
#include "mperror.h"
|
|
#include <sehcall.h>
|
|
#define LEGACY_DIVISOR 8
|
|
|
|
extern "C" WORD _cdecl is_cyrix(void);
|
|
extern "C" DWORD _cdecl get_nxcpu_type(void);
|
|
|
|
|
|
#ifndef _M_IX86
|
|
DWORD WINAPI CallWithSEH(EXCEPTPROC pfn, void *pv, INEXCEPTION InException)
|
|
{
|
|
// we don't have a native version of SEH for the alpha,
|
|
// use __try and __except
|
|
pfn(pv);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _M_IX86
|
|
|
|
DWORD NMINTERNAL FindTSC (LPVOID pvRefData)
|
|
{
|
|
_asm
|
|
{
|
|
mov eax,1
|
|
_emit 00Fh ;; CPUID
|
|
_emit 0A2h
|
|
|
|
// The ref data is 2 DWORDS, the first is the flags,
|
|
// the second the family
|
|
mov ecx,pvRefData
|
|
mov [ecx],edx
|
|
mov [ecx][4],eax
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
DWORD NMINTERNAL NoCPUID (LPEXCEPTION_RECORD per,PCONTEXT pctx)
|
|
{
|
|
return 0;
|
|
}
|
|
//
|
|
// GetProcessorSpeed(dwFamily)
|
|
//
|
|
// get the processor speed in MHz, only works on Pentium or better
|
|
// machines.
|
|
//
|
|
// Will put 3, or 4 in dwFamily for 386/486, but no speed.
|
|
// returns speed and family for 586+
|
|
//
|
|
// - thanks to toddla, modified by mikeg
|
|
//
|
|
|
|
int NMINTERNAL GetProcessorSpeed(int *pdwFamily)
|
|
{
|
|
SYSTEM_INFO si;
|
|
__int64 start, end, freq;
|
|
int flags,family;
|
|
int time;
|
|
int clocks;
|
|
DWORD oldclass;
|
|
HANDLE hprocess;
|
|
int pRef[2];
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
GetSystemInfo(&si);
|
|
|
|
//Set the family. If wProcessorLevel is not specified, dig it out of dwProcessorType
|
|
//Because wProcessor level is not implemented on Win95
|
|
if (si.wProcessorLevel) {
|
|
*pdwFamily=si.wProcessorLevel;
|
|
}else {
|
|
//Ok, we're on Win95
|
|
switch (si.dwProcessorType) {
|
|
case PROCESSOR_INTEL_386:
|
|
*pdwFamily=3;
|
|
break;
|
|
|
|
case PROCESSOR_INTEL_486:
|
|
*pdwFamily=4;
|
|
break;
|
|
default:
|
|
*pdwFamily=0;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// make sure this is a INTEL Pentium (or clone) or higher.
|
|
//
|
|
if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
|
|
return 0;
|
|
|
|
if (si.dwProcessorType < PROCESSOR_INTEL_PENTIUM)
|
|
return 0;
|
|
|
|
//
|
|
// see if this chip supports rdtsc before using it.
|
|
//
|
|
if (!CallWithSEH (FindTSC,&pRef,NoCPUID)) {
|
|
flags=0;
|
|
} else {
|
|
// The ref data is 2 DWORDS, the first is the flags,
|
|
// the second the family. Pull them out and use them
|
|
flags=pRef[0];
|
|
family=pRef[1];
|
|
}
|
|
|
|
if (!(flags & 0x10))
|
|
return 0;
|
|
|
|
|
|
//If we don't have a family, set it now
|
|
//Family is bits 11:8 of eax from CPU, with eax=1
|
|
if (!(*pdwFamily)) {
|
|
*pdwFamily=(family& 0x0F00) >> 8;
|
|
}
|
|
|
|
|
|
hprocess = GetCurrentProcess();
|
|
oldclass = GetPriorityClass(hprocess);
|
|
SetPriorityClass(hprocess, REALTIME_PRIORITY_CLASS);
|
|
Sleep(10);
|
|
|
|
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&start);
|
|
_asm
|
|
{
|
|
_emit 0Fh ;; RDTSC
|
|
_emit 31h
|
|
mov ecx,100000
|
|
x: dec ecx
|
|
jnz x
|
|
mov ebx,eax
|
|
_emit 0Fh ;; RDTSC
|
|
_emit 31h
|
|
sub eax,ebx
|
|
mov dword ptr clocks[0],eax
|
|
}
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&end);
|
|
SetPriorityClass(hprocess, oldclass);
|
|
|
|
time = MulDiv((int)(end-start),1000000,(int)freq);
|
|
|
|
return (clocks + time/2) / time;
|
|
}
|
|
|
|
|
|
|
|
HRESULT NMINTERNAL GetNormalizedCPUSpeed (int *pdwNormalizedSpeed, int *dwFamily)
|
|
{
|
|
int dwProcessorSpeed;
|
|
|
|
dwProcessorSpeed=GetProcessorSpeed (dwFamily);
|
|
|
|
*pdwNormalizedSpeed=dwProcessorSpeed;
|
|
|
|
if (*dwFamily > 5) {
|
|
//Ok, TWO things.
|
|
// ONE DO NOT DO FP!
|
|
// Two for the same Mhz assume a 686 is 1.3 times as fast as a 586 and a 786 is 1.6 times, etc.
|
|
*pdwNormalizedSpeed=(ULONG) (((10+3*(*dwFamily-5))*dwProcessorSpeed)/10);
|
|
}
|
|
|
|
if (*dwFamily < 5) {
|
|
//bugbug until we have 386/486 timing code, assume
|
|
//486=50,386=37
|
|
if (*dwFamily > 3) {
|
|
//Cyrix, (5x86)? check before making default assignment
|
|
if (is_cyrix()) {
|
|
if (*pdwNormalizedSpeed==0) {
|
|
*dwFamily=5;
|
|
*pdwNormalizedSpeed=100;
|
|
return hrSuccess;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pdwNormalizedSpeed= (*dwFamily*100)/LEGACY_DIVISOR;
|
|
|
|
if (get_nxcpu_type ()) {
|
|
//Double the perceived value on a NexGen
|
|
*pdwNormalizedSpeed *=2;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return hrSuccess;
|
|
}
|
|
#endif //_M_IX86
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI IsFloatingPointEmulated(void)
|
|
{
|
|
long lRegValue;
|
|
SYSTEM_INFO si;
|
|
OSVERSIONINFO osi;
|
|
BOOL fEmulation, bNT;
|
|
|
|
|
|
// are we a Pentium
|
|
ZeroMemory(&si, sizeof(si));
|
|
GetSystemInfo(&si);
|
|
if (si.dwProcessorType != PROCESSOR_INTEL_PENTIUM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Which OS: NT or 95 ?
|
|
ZeroMemory(&osi, sizeof(osi));
|
|
osi.dwOSVersionInfoSize = sizeof(osi);
|
|
GetVersionEx(&osi);
|
|
bNT = (osi.dwPlatformId == VER_PLATFORM_WIN32_NT);
|
|
|
|
// Windows NT
|
|
if (bNT)
|
|
{
|
|
RegEntry re(TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
|
|
HKEY_LOCAL_MACHINE, FALSE);
|
|
|
|
// try to get a definitive answer from the registry
|
|
lRegValue = re.GetNumber(TEXT("ForceNpxEmulation"), -1);
|
|
|
|
// registry: 0: no
|
|
// 1: conditional (not definitive!)
|
|
// 2: yes
|
|
|
|
if (lRegValue == 2)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// we could load "IsProcessorFeaturePresent from kernel32.dll,
|
|
// but the version that shipped with NT 4 has a bug in it that
|
|
// returns the exact opposite of what it should be. It was
|
|
// fixed in NT 5. Since this API isn't the same across platforms,
|
|
// we won't use it.
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Windows 95 - to be added later
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|