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