home *** CD-ROM | disk | FTP | other *** search
/ Clickx 47 / Clickx 47.iso / assets / software / sswitchxp152.exe / source / SpeedswitchXP / Cpuid.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-14  |  12.9 KB  |  485 lines

  1. /***************************************************************
  2. * C file: cpuid.c... for cpuinf32 DLL
  3. *
  4. *   This program has been developed by Intel Corporation.  
  5. *        You have Intel's permission to incorporate this code 
  6. *   into your product, royalty free.
  7. *
  8. *  Copyright (c) 1995, Intel Corporation.  All rights reserved.
  9. *
  10. *  Runtime optimizations & modifications for SpeedswitchXP 
  11. *    by C. Diefer
  12. ***************************************************************/
  13.  
  14. #define _UNICODE
  15.  
  16. #include "stdafx.h"
  17. #include "cpuid.h"
  18. #include "speed.h"
  19.  
  20.  
  21. // Global Variable /////////////////////////////////////////////
  22. int clone_flag;             // Flag to show whether processor is an Intel clone
  23.  
  24. BYTE vendor_id[16] = "------------";
  25. DWORD family = 0;
  26. DWORD maxIDVal = 0;
  27. DWORD cpuffext = 0;
  28. DWORD brandid = 0;
  29.  
  30. // Public Functions
  31.  
  32. /***************************************************************
  33. * wincpuidsupport()
  34. *
  35. * Inputs: none
  36. *
  37. * Returns:
  38. *  1 = CPUID opcode is supported
  39. *  0 = CPUID opcode is not supported
  40. ***************************************************************/
  41. WORD wincpuidsupport() 
  42. {
  43.   WORD cpuid_support = 1;
  44.  
  45.   _asm {
  46.       pushfd                  // Get original EFLAGS
  47.       pop eax
  48.       mov ecx, eax
  49.       xor eax, 200000h        // Flip ID bit in EFLAGS
  50.       push eax                // Save new EFLAGS value on stack
  51.       popfd                   // Replace current EFLAGS value
  52.       pushfd                  // Get new EFLAGS
  53.       pop eax                 // Store new EFLAGS in EAX
  54.       xor eax, ecx            // Can not toggle ID bit,
  55.       jnz support             // Processor=80486
  56.       mov cpuid_support,0     // Clear support flag
  57.     support:
  58.   }
  59.  
  60.   return cpuid_support;
  61. } // wincpuidsupport()
  62.  
  63. /***************************************************************
  64. * wincpuid()
  65. *
  66. * Inputs: none
  67. *
  68. * Returns:
  69. *  0 = 8086/88
  70. *  2 = 80286
  71. *  3 = 80386
  72. *  4 = 80486
  73. *  5 = Pentium(R) Processor
  74. *  6 = PentiumPro(R) Processor
  75. *  7 or higher = Processor beyond the PentiumPro6(R) Processor
  76. *
  77. *  Note: This function also sets the global variable clone_flag
  78. ***************************************************************/
  79. DWORD haveCPUID = 0;
  80. WORD retCPUID;
  81.  
  82. WORD wincpuid() 
  83. {
  84.   if( haveCPUID )
  85.     return retCPUID;
  86.  
  87.   WORD cpuid;
  88.  
  89.   if( wincpuidsupport() )     // Determine whether CPUID opcode is supported
  90.     cpuid = check_IDProc();
  91.   else 
  92.   {
  93.     clone_flag = check_clone(); 
  94.  
  95.     cpuid = check_8086();               // Will return FFFFh or 0
  96.  
  97.     if( cpuid == 0 ) 
  98.       goto end;
  99.     
  100.     cpuid = check_80286();          // Will return FFFFh or 2
  101.     if( cpuid == 2 ) 
  102.       goto end;
  103.  
  104.     cpuid = check_80386();          // Will return FFFFh or 3
  105.     if( cpuid == 3 ) 
  106.       goto end;                   // temporarily commented out.
  107.         
  108.     cpuid = 4;  // If the processor does not support CPUID,
  109.                 //  is not an 8086, 80286, or 80386, assign
  110.                 //  processor to be an 80486
  111.   }
  112.  
  113. end:
  114.   if( clone_flag )
  115.     cpuid = cpuid | CLONE_MASK;   // Signify that a clone has been detected by setting MSB high 
  116.  
  117.   haveCPUID = 1;
  118.   retCPUID = cpuid;
  119.  
  120.   return cpuid;
  121. } // wincpuid ()
  122.  
  123.  
  124.  
  125. /***************************************************************
  126. * wincpufeatures()
  127. *
  128. * Inputs: none
  129. *
  130. * Returns:
  131. *   0 = Processor which does not execute the CPUID instruction.
  132. *          This includes 8086, 8088, 80286, 80386, and some 
  133. *          older 80486 processors.                       
  134. *
  135. * Else
  136. *   Feature Flags (refer to App Note AP-485 for description).
  137. *      This DWORD was put into EDX by the CPUID instruction.
  138. *
  139. *   Current flag assignment is as follows:
  140. *
  141. *       bit31..10   reserved (=0)
  142. *       bit9=1      CPU contains a local APIC (iPentium-3V)
  143. *       bit8=1      CMPXCHG8B instruction supported
  144. *       bit7=1      machine check exception supported
  145. *       bit6=0      reserved (36bit-addressing & 2MB-paging)
  146. *       bit5=1      iPentium-style MSRs supported
  147. *       bit4=1      time stamp counter TSC supported
  148. *       bit3=1      page size extensions supported
  149. *       bit2=1      I/O breakpoints supported
  150. *       bit1=1      enhanced virtual 8086 mode supported
  151. *       bit0=1      CPU contains a floating-point unit (FPU)
  152. *
  153. *   Note: New bits will be assigned on future processors... see
  154. *         processor data books for updated information
  155. *
  156. *   Note: This function also sets the global variable clone_flag
  157. ***************************************************************/
  158. DWORD haveFeat = 0;
  159. DWORD retFeat;
  160.  
  161. DWORD wincpufeatures() 
  162. {
  163.   if( haveFeat )
  164.     return retFeat;
  165.  
  166.   int i=0;
  167.   DWORD cpuff=0x00000000;
  168.   BYTE vendor_id[16] = "------------";
  169.   BYTE intel_id[16] = "GenuineIntel";
  170.  
  171.   if( wincpuidsupport() ) 
  172.   {
  173.     _asm {      
  174.         xor eax,eax                       // Set up for CPUID instruction
  175.         CPU_ID                            // Get and save vendor ID
  176.         mov dword ptr vendor_id,ebx
  177.         mov dword ptr vendor_id[+4],edx
  178.         mov dword ptr vendor_id[+8],ecx
  179.     }
  180.  
  181.     for( i=0; i<12; i++ )
  182.     {
  183.       if( !(vendor_id[i] == intel_id[i]) )
  184.         clone_flag = 1;    
  185.     }
  186.  
  187.     _asm {
  188.         cmp eax,1               // Make sure 1 is valid input for CPUID
  189.         jl end_cpuff            // If not, jump to end
  190.         xor eax, eax
  191.         inc eax
  192.         CPU_ID                  // Get family/model/stepping/features
  193.         mov cpuff, edx
  194.         mov cpuffext, ecx
  195.         mov brandid, ebx
  196.         mov family, eax
  197.  
  198.       end_cpuff:
  199.         mov eax, cpuff
  200.     }
  201.   }
  202.  
  203.   haveFeat = 1;
  204.   retFeat = cpuff;
  205.  
  206.   return cpuff;
  207. } // wincpufeatures()
  208.  
  209.  
  210.  
  211. /***************************************************************
  212. * winrdtsc()
  213. *
  214. * Inputs: none
  215. *
  216. * Returns:
  217. *   0 = CPU does not support the time stamp register
  218. *
  219. * Else
  220. *   Returns a variable of type TIME_STAMP which is composed of 
  221. *      two DWORD variables. The 'High' DWORD contains the upper
  222. *      32-bits of the Time Stamp Register. The 'Low' DWORD 
  223. *      contains the lower 32-bits of the Time Stamp Register.
  224. *
  225. *  Note: This function also sets the global variable clone_flag
  226. ***************************************************************/
  227.  
  228. struct TIME_STAMP winrdtsc() 
  229. {
  230.   struct TIME_STAMP timestamp;    // Return variable for time stamp read
  231.   DWORD features = wincpufeatures();  // Processor Features
  232.     
  233.   timestamp.Low  = 0;
  234.   timestamp.High = 0;
  235.         
  236.   if( features & 0x00000010 ) 
  237.   {
  238.     RDTSC                       // Read Time Stamp
  239.     _asm {
  240.         MOV timestamp.Low, EAX
  241.         MOV timestamp.High, EDX
  242.     }
  243.   }
  244.     
  245.   return timestamp;
  246. } // winrdtsc
  247.  
  248.  
  249.  
  250. // Internal Private Functions //////////////////////////////////
  251.  
  252. /***************************************************************
  253. * check_clone()
  254. *
  255. * Inputs: none
  256. *
  257. * Returns:
  258. *   1      if processor is clone (limited detection ability)
  259. *   0      otherwise
  260. ***************************************************************/
  261.  
  262. static WORD check_clone()
  263. {
  264.   short cpu_type=0;
  265.  
  266.   _asm {
  267.                     MOV AX,5555h    // Check to make sure this
  268.                     XOR DX,DX       //   is a 32-bit processor
  269.                     MOV CX,2h
  270.                     DIV CX          // Perform Division
  271.                     CLC
  272.                     JNZ no_clone
  273.                     JMP clone
  274.         no_clone:   STC
  275.         clone:      PUSHF
  276.                     POP AX          // Get the flags
  277.                     AND AL,1
  278.                     XOR AL,1        // AL=0 is probably Intel,
  279.                                     //   AL=1 is a Clone
  280.                     
  281.                     MOV cpu_type, ax
  282.   }
  283.     
  284.   cpu_type = cpu_type & 0x0001;
  285.     
  286.   return cpu_type;        
  287. } // check_clone()
  288.  
  289.  
  290.  
  291. /***************************************************************
  292. * check_8086()
  293. *
  294. * Inputs: none
  295. *
  296. * Returns: 
  297. *   0      if processor 8086
  298. *   0xffff otherwise
  299. ***************************************************************/
  300.  
  301. static WORD check_8086()
  302. {
  303.   WORD cpu_type=0xffff;
  304.  
  305.   _asm {
  306.         pushf                   // Push original FLAGS
  307.         pop     ax              // Get original FLAGS
  308.         mov     cx, ax          // Save original FLAGS
  309.         and     ax, 0fffh       // Clear bits 12-15 in FLAGS
  310.         push    ax              // Save new FLAGS value on stack
  311.         popf                    // Replace current FLAGS value
  312.         pushf                   // Get new FLAGS
  313.         pop     ax              // Store new FLAGS in AX
  314.         and     ax, 0f000h      // If bits 12-15 are set, then
  315.         cmp     ax, 0f000h      //   processor is an 8086/8088
  316.         mov     cpu_type, 0     // Turn on 8086/8088 flag
  317.         je      end_8086        // Jump if processor is 8086/
  318.                                 //   8088
  319.         mov     cpu_type, 0ffffh
  320. end_8086:
  321.         push    cx
  322.         popf
  323.         mov     ax, cpu_type
  324.   }
  325.     
  326.   return cpu_type;
  327. } // check_8086()
  328.  
  329.  
  330.  
  331. /***************************************************************
  332. * check_80286()
  333. *
  334. * Inputs: none
  335. *
  336. * Returns:
  337. *   2      if processor 80286
  338. *   0xffff otherwise
  339. ***************************************************************/
  340.  
  341. static WORD check_80286()
  342. {
  343.   WORD cpu_type=0xffff;
  344.  
  345.   _asm {
  346.         pushf
  347.         pop     cx
  348.         mov     bx, cx
  349.         or      cx, 0f000h      // Try to set bits 12-15
  350.         push    cx              // Save new FLAGS value on stack
  351.         popf                    // Replace current FLAGS value
  352.         pushf                   // Get new FLAGS
  353.         pop     ax              // Store new FLAGS in AX
  354.         and     ax, 0f000h      // If bits 12-15 are clear
  355.         
  356.         mov     cpu_type, 2     // Processor=80286, turn on 
  357.                                 //   80286 flag
  358.         
  359.         jz      end_80286       // If no bits set, processor is 
  360.                                 //   80286
  361.         
  362.         mov     cpu_type, 0ffffh
  363. end_80286:
  364.         push    bx
  365.         popf
  366.         mov     ax, cpu_type
  367.  
  368.   }
  369.     
  370.   return cpu_type;
  371. } // check_80286()
  372.  
  373.  
  374.  
  375. /***************************************************************
  376. * check_80386()
  377. *
  378. * Inputs: none
  379. *
  380. * Returns:
  381. *   3      if processor 80386
  382. *   0xffff otherwise
  383. ***************************************************************/
  384.  
  385. static WORD check_80386()
  386. {
  387.   WORD cpu_type=0xffff;
  388.  
  389.   _asm {   
  390.         mov     bx, sp
  391.         and     sp, not 3
  392.         pushfd                  // Push original EFLAGS 
  393.         pop     eax             // Get original EFLAGS
  394.         mov     ecx, eax        // Save original EFLAGS
  395.         xor     eax, 40000h     // Flip AC bit in EFLAGS
  396.         
  397.         push    eax             // Save new EFLAGS value on
  398.                                 //   stack
  399.         
  400.         popfd                   // Replace current EFLAGS value
  401.         pushfd                  // Get new EFLAGS
  402.         pop     eax             // Store new EFLAGS in EAX
  403.         
  404.         xor     eax, ecx        // Can't toggle AC bit, 
  405.                                 //   processor=80386
  406.         
  407.         mov     cpu_type, 3     // Turn on 80386 processor flag
  408.         jz      end_80386       // Jump if 80386 processor
  409.         mov     cpu_type, 0ffffh
  410. end_80386:
  411.         push    ecx
  412.         popfd
  413.         mov     sp, bx
  414.         mov     ax, cpu_type
  415.         and     eax, 0000ffffh
  416.   }
  417.  
  418.   return cpu_type;
  419. } // check_80386()
  420.  
  421.  
  422.  
  423. /***************************************************************
  424. * check_IDProc()
  425. *
  426. * Inputs: none
  427. *
  428. * Returns:
  429. *  CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
  430. *
  431. *  Note: This function also sets the global variable clone_flag
  432. ***************************************************************/
  433.  
  434. static WORD check_IDProc() 
  435. {
  436.   int i=0;
  437.   WORD cpu_type=0xffff;
  438.   BYTE stepping=0;
  439.   BYTE model=0;
  440.   BYTE intel_id[16] = "GenuineIntel";
  441.  
  442.   _asm {      
  443.         xor  eax, eax        // Set up for CPUID instruction
  444.         CPU_ID               // Get and save vendor ID
  445.         mov  maxIDVal, eax
  446.         mov  dword ptr vendor_id, ebx
  447.         mov  dword ptr vendor_id[+4], edx
  448.         mov  dword ptr vendor_id[+8], ecx
  449.   }
  450.  
  451.   for( i=0; i<12; i++ )
  452.   {
  453.     if( !(vendor_id[i] == intel_id[i]) )
  454.       clone_flag = 1;    
  455.   }
  456.  
  457.   _asm {
  458.         cmp     eax, 1          // Make sure 1 is valid input for CPUID
  459.         jl      end_IDProc      // If not, jump to end
  460.         xor     eax, eax
  461.         inc     eax
  462.         CPU_ID                  // Get family/model/stepping/features
  463.  
  464.         mov     stepping, al
  465.         and     stepping, 0x0f  //0fh
  466.         
  467.         and     al, 0f0h
  468.         shr     al, 4
  469.         mov     model, al
  470.         
  471.         and     eax, 0f00h
  472.         shr     eax, 8          // Isolate family
  473.         and     eax, 0fh
  474.         mov     cpu_type, ax    // Set _cpu_type with family
  475.  
  476.     end_IDProc:
  477.         mov     ax, cpu_type
  478.   }
  479.  
  480.   return cpu_type;
  481. } // Check_IDProc()
  482.  
  483.  
  484.  
  485.