home *** CD-ROM | disk | FTP | other *** search
/ PC User 1997 April / PCU_APR_97.ISO / utils / cpu / cpuinfo / source / cpuinf32 / cpuid.c next >
Encoding:
C/C++ Source or Header  |  1995-10-26  |  15.1 KB  |  620 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.  Intel has various 
  7. *        intellectual property rights which it may assert under
  8. *       certain circumstances, such as if another manufacturer's
  9. *       processor mis-identifies itself as being "GenuineIntel"
  10. *        when the CPUID instruction is executed.
  11. *
  12. *       Intel specifically disclaims all warranties, express or
  13. *       implied, and all liability, including consequential and
  14. *        other indirect damages, for the use of this code, 
  15. *        including liability for infringement of any proprietary
  16. *        rights, and including the warranties of merchantability
  17. *        and fitness for a particular purpose.  Intel does not 
  18. *        assume any responsibility for any errors which may 
  19. *        appear in this code nor any responsibility to update it.
  20. *
  21. *  * Other brands and names are the property of their respective
  22. *    owners.
  23. *
  24. *  Copyright (c) 1995, Intel Corporation.  All rights reserved.
  25. ***************************************************************/
  26.  
  27.  
  28.  
  29. /***************************************************************
  30. * This is a 32-bit MS-Windows* DLL.  It uses the standard Intel
  31. * 32-bit cpuid assembly code to determine what type of processor
  32. * is in the computer.
  33. *
  34. * Warning: avoid making frequent calls to wincpuid() or using 
  35. * the CPUID instruction frequently.  This instruction & function
  36. * require several clocks to execute, and they cause 
  37. * serialization of the instruction stream.
  38. ***************************************************************/
  39.  
  40. #include <windows.h> 
  41. #include "cpuid.h"
  42. #include "speed.h"
  43.  
  44.  
  45. // Global Variable /////////////////////////////////////////////
  46. int clone_flag;                // Flag to show whether processor
  47.                             //   is an Intel clone
  48.  
  49.  
  50.  
  51. // Public DLL Functions ////////////////////////////////////////
  52.  
  53. /***************************************************************
  54. * wincpuidsupport()
  55. *
  56. * Inputs: none
  57. *
  58. * Returns:
  59. *  1 = CPUID opcode is supported
  60. *  0 = CPUID opcode is not supported
  61. ***************************************************************/
  62.  
  63. WORD wincpuidsupport() {
  64.     int cpuid_support = 1;
  65.  
  66.     _asm {
  67.         pushfd                    // Get original EFLAGS
  68.         pop        eax
  69.         mov     ecx, eax
  70.         xor     eax, 200000h    // Flip ID bit in EFLAGS
  71.         push    eax                // Save new EFLAGS value on
  72.                                 //   stack
  73.         popfd                    // Replace current EFLAGS value
  74.         pushfd                    // Get new EFLAGS
  75.         pop     eax                // Store new EFLAGS in EAX
  76.         xor     eax, ecx        // Can not toggle ID bit,
  77.         jnz     support            // Processor=80486
  78.         
  79.         mov cpuid_support,0        // Clear support flag
  80. support:
  81.       }
  82.     
  83.     return cpuid_support;
  84.  
  85. } // wincpuidsupport()
  86.  
  87.  
  88.  
  89. /***************************************************************
  90. * wincpuid()
  91. *
  92. * Inputs: none
  93. *
  94. * Returns:
  95. *  0 = 8086/88
  96. *  2 = 80286
  97. *  3 = 80386
  98. *  4 = 80486
  99. *  5 = Pentium(R) Processor
  100. *  6 = PentiumPro(R) Processor
  101. *  7 or higher = Processor beyond the PentiumPro6(R) Processor
  102. *
  103. *  Note: This function also sets the global variable clone_flag
  104. ***************************************************************/
  105.  
  106. WORD wincpuid() {
  107.  
  108.     WORD cpuid;
  109.     
  110.     if ( wincpuidsupport() )     // Determine whether CPUID 
  111.                                 //   opcode is supported
  112.         cpuid=check_IDProc();
  113.  
  114.     else {
  115.         
  116.         clone_flag=check_clone();
  117.     
  118.         cpuid=check_8086();            // Will return FFFFh or 0
  119.         if (cpuid == 0) goto end;
  120.     
  121.         cpuid=check_80286();           // Will return FFFFh or 2
  122.         if (cpuid == 2) goto end;
  123.  
  124.         cpuid=check_80386();           // Will return FFFFh or 3
  125.         if (cpuid == 3) goto end;    // temporarily commented out.
  126.         
  127.         cpuid=4;        // If the processor does not support CPUID,
  128.                         //  is not an 8086, 80286, or 80386, assign
  129.                         //  processor to be an 80486
  130.     }
  131.  
  132. end:
  133.     if (clone_flag)
  134.         cpuid = cpuid | CLONE_MASK;    // Signify that a clone has been
  135.                                     //   detected by setting MSB high 
  136.  
  137.        return cpuid;
  138.  
  139. } // wincpuid ()
  140.  
  141.  
  142.  
  143. /***************************************************************
  144. * wincpuidext()
  145. *
  146. * Inputs: none
  147. *
  148. * Returns:
  149. * AX(15:14) = Reserved (mask these off in the calling code 
  150. *                before using)
  151. * AX(13:12) = Processor type (00=Standard OEM CPU, 01=OverDrive,
  152. *                10=Dual CPU, 11=Reserved)
  153. * AX(11:8)  = CPU Family (the same 4-bit quantity as wincpuid())
  154. * AX(7:4)   = CPU Model, if the processor supports the CPUID 
  155. *                opcode; zero otherwise
  156. * AX(3:0)   = Stepping #, if the processor supports the CPUID 
  157. *                opcode; zero otherwise
  158. *
  159. *  Note: This function also sets the global variable clone_flag
  160. ***************************************************************/
  161.  
  162. WORD wincpuidext() {
  163.  
  164.         int i=0;
  165.         WORD cpu_type=0x0000;
  166.         WORD cpuidext=0x0000;
  167.         BYTE vendor_id[12]="------------";
  168.         BYTE intel_id[12]="GenuineIntel";
  169.  
  170.     if ( wincpuidsupport() ) {
  171.  
  172. _asm {      
  173.  
  174.         xor     eax, eax        // Set up for CPUID instruction
  175.         
  176.         CPU_ID                  // Get and save vendor ID
  177.  
  178.         mov     dword ptr vendor_id, ebx
  179.         mov     dword ptr vendor_id[+4], edx
  180.         mov     dword ptr vendor_id[+8], ecx
  181. }
  182.  
  183. for (i=0;i<12;i++)
  184. {
  185.     if (!(vendor_id[i]==intel_id[i]))
  186.         clone_flag = 1;    
  187. }
  188.  
  189. _asm {
  190.         
  191.         cmp     eax, 1            // Make sure 1 is valid input 
  192.                                 //   for CPUID
  193.         
  194.         jl      end_cpuidext    // If not, jump to end
  195.         xor     eax, eax
  196.         inc        eax
  197.         CPU_ID                    // Get family/model/stepping/
  198.                                 //   features
  199.  
  200.         mov        cpuidext, ax
  201.  
  202. end_cpuidext:
  203.         mov        ax, cpuidext
  204.         }
  205.     }
  206.     else {
  207.  
  208.     cpu_type = wincpuid();        // If CPUID opcode is not
  209.     cpuidext = cpu_type << 8;    //   supported, put family
  210.                                 //   value in extensions and
  211.     }                            //   return
  212.     
  213.     return cpuidext;
  214.  
  215. } // wincpuidext()
  216.  
  217.  
  218.  
  219. /***************************************************************
  220. * wincpufeatures()
  221. *
  222. * Inputs: none
  223. *
  224. * Returns:
  225. *   0 = Processor which does not execute the CPUID instruction.
  226. *          This includes 8086, 8088, 80286, 80386, and some 
  227. *           older 80486 processors.                       
  228. *
  229. * Else
  230. *   Feature Flags (refer to App Note AP-485 for description).
  231. *      This DWORD was put into EDX by the CPUID instruction.
  232. *
  233. *    Current flag assignment is as follows:
  234. *
  235. *        bit31..10   reserved (=0)
  236. *        bit9=1      CPU contains a local APIC (iPentium-3V)
  237. *        bit8=1      CMPXCHG8B instruction supported
  238. *        bit7=1      machine check exception supported
  239. *        bit6=0      reserved (36bit-addressing & 2MB-paging)
  240. *        bit5=1      iPentium-style MSRs supported
  241. *        bit4=1      time stamp counter TSC supported
  242. *        bit3=1      page size extensions supported
  243. *        bit2=1      I/O breakpoints supported
  244. *        bit1=1      enhanced virtual 8086 mode supported
  245. *        bit0=1      CPU contains a floating-point unit (FPU)
  246. *
  247. *    Note: New bits will be assigned on future processors... see
  248. *         processor data books for updated information
  249. *
  250. *    Note: This function also sets the global variable clone_flag
  251. ***************************************************************/
  252.  
  253. DWORD wincpufeatures() {
  254.  
  255.     int i=0;
  256.     DWORD cpuff=0x00000000;
  257.     BYTE vendor_id[12]="------------";
  258.     BYTE intel_id[12]="GenuineIntel";
  259.  
  260.     if ( wincpuidsupport() ) {
  261.  
  262. _asm {      
  263.  
  264.         xor     eax, eax        // Set up for CPUID instruction
  265.         
  266.         CPU_ID                  // Get and save vendor ID
  267.  
  268.         mov     dword ptr vendor_id, ebx
  269.         mov     dword ptr vendor_id[+4], edx
  270.         mov     dword ptr vendor_id[+8], ecx
  271. }
  272.  
  273. for (i=0;i<12;i++)
  274. {
  275.     if (!(vendor_id[i]==intel_id[i]))
  276.         clone_flag = 1;    
  277. }
  278.  
  279. _asm {
  280.          
  281.         cmp     eax, 1            // Make sure 1 is valid input 
  282.                                 //   for CPUID
  283.         
  284.         jl      end_cpuff        // If not, jump to end
  285.         xor     eax, eax
  286.         inc        eax
  287.         CPU_ID                    // Get family/model/stepping/
  288.                                 //   features
  289.  
  290.         mov        cpuff, edx
  291.  
  292. end_cpuff:
  293.         mov        eax, cpuff
  294.       }
  295.     }
  296.  
  297.     return cpuff;
  298.  
  299. } // wincpufeatures()
  300.  
  301.  
  302.  
  303. /***************************************************************
  304. * winrdtsc()
  305. *
  306. * Inputs: none
  307. *
  308. * Returns:
  309. *   0 = CPU does not support the time stamp register
  310. *
  311. * Else
  312. *   Returns a variable of type TIME_STAMP which is composed of 
  313. *      two DWORD variables. The 'High' DWORD contains the upper
  314. *      32-bits of the Time Stamp Register. The 'Low' DWORD 
  315. *      contains the lower 32-bits of the Time Stamp Register.
  316. *
  317. *  Note: This function also sets the global variable clone_flag
  318. ***************************************************************/
  319.  
  320. struct TIME_STAMP winrdtsc() {
  321.  
  322.     struct TIME_STAMP timestamp;    // Return variable for time
  323.                                     //   stamp read
  324.     DWORD features = wincpufeatures();    // Processor Features
  325.     
  326.     timestamp.Low  = 0;
  327.     timestamp.High = 0;
  328.         
  329.     if ( features & 0x00000010 ) {
  330.  
  331.         RDTSC                        // Read Time Stamp
  332.  
  333.         _asm
  334.             {
  335.             MOV timestamp.Low, EAX
  336.             MOV timestamp.High, EDX
  337.  
  338.             }
  339.     }
  340.     
  341.     return timestamp;
  342.  
  343. } // winrdtsc
  344.  
  345.  
  346.  
  347. /***************************************************************
  348. * getdllversion()
  349. *
  350. * Inputs: none
  351. *
  352. * Returns:  Major and Minor version of this DLL.
  353. *         
  354. *        i.e.    getdllversion() = 0x01 00
  355. *                      Major Version<--|-->Minor Version
  356. *            
  357. ***************************************************************/
  358.  
  359. unsigned short getdllversion(void) {
  360.     unsigned short Version = VERSION;
  361.     
  362.     return Version;
  363.  
  364. } // getdllversion()
  365.  
  366.  
  367.  
  368. // Internal Private Functions //////////////////////////////////
  369.  
  370. /***************************************************************
  371. * check_clone()
  372. *
  373. * Inputs: none
  374. *
  375. * Returns:
  376. *   1      if processor is clone (limited detection ability)
  377. *   0      otherwise
  378. ***************************************************************/
  379.  
  380. static WORD check_clone()
  381. {
  382.     short cpu_type=0;
  383.  
  384.     _asm 
  385.         {
  386.                       MOV AX,5555h    // Check to make sure this
  387.                     XOR DX,DX        //   is a 32-bit processor
  388.                     MOV CX,2h
  389.                     DIV CX            // Perform Division
  390.                     CLC
  391.                     JNZ no_clone
  392.                     JMP clone
  393.         no_clone:    STC
  394.         clone:        PUSHF
  395.                     POP AX          // Get the flags
  396.                     AND AL,1
  397.                     XOR AL,1        // AL=0 is probably Intel,
  398.                                     //   AL=1 is a Clone
  399.                     
  400.                     MOV cpu_type, ax
  401.         }
  402.     
  403.     cpu_type = cpu_type & 0x0001;
  404.     
  405.     return cpu_type;
  406.         
  407. } // check_clone()
  408.  
  409.  
  410.  
  411. /***************************************************************
  412. * check_8086()
  413. *
  414. * Inputs: none
  415. *
  416. * Returns: 
  417. *   0      if processor 8086
  418. *   0xffff otherwise
  419. ***************************************************************/
  420.  
  421. static WORD check_8086()
  422. {
  423.  
  424.         WORD cpu_type=0xffff;
  425.  
  426. _asm {
  427.         pushf                   // Push original FLAGS
  428.         pop     ax              // Get original FLAGS
  429.         mov     cx, ax          // Save original FLAGS
  430.         and     ax, 0fffh       // Clear bits 12-15 in FLAGS
  431.         push    ax              // Save new FLAGS value on stack
  432.         popf                    // Replace current FLAGS value
  433.         pushf                   // Get new FLAGS
  434.         pop     ax              // Store new FLAGS in AX
  435.         and     ax, 0f000h      // If bits 12-15 are set, then
  436.         cmp     ax, 0f000h      //   processor is an 8086/8088
  437.         mov     cpu_type, 0        // Turn on 8086/8088 flag
  438.         je      end_8086        // Jump if processor is 8086/
  439.                                 //   8088
  440.         mov        cpu_type, 0ffffh
  441. end_8086:
  442.         push     cx
  443.         popf
  444.         mov        ax, cpu_type
  445.  
  446.       }
  447.     
  448.     return cpu_type;
  449.  
  450. } // check_8086()
  451.  
  452.  
  453.  
  454. /***************************************************************
  455. * check_80286()
  456. *
  457. * Inputs: none
  458. *
  459. * Returns:
  460. *   2      if processor 80286
  461. *   0xffff otherwise
  462. ***************************************************************/
  463.  
  464. static WORD check_80286()
  465. {
  466.  
  467.         WORD cpu_type=0xffff;
  468.  
  469. _asm {
  470.         pushf
  471.         pop        cx
  472.         mov        bx, cx
  473.         or      cx, 0f000h      // Try to set bits 12-15
  474.         push    cx              // Save new FLAGS value on stack
  475.         popf                    // Replace current FLAGS value
  476.         pushf                   // Get new FLAGS
  477.         pop     ax              // Store new FLAGS in AX
  478.         and     ax, 0f000h      // If bits 12-15 are clear
  479.         
  480.         mov     cpu_type, 2     // Processor=80286, turn on 
  481.                                 //   80286 flag
  482.         
  483.         jz      end_80286       // If no bits set, processor is 
  484.                                 //   80286
  485.         
  486.         mov        cpu_type, 0ffffh
  487. end_80286:
  488.         push    bx
  489.         popf
  490.         mov        ax, cpu_type
  491.  
  492.       }
  493.     
  494.     return cpu_type;
  495.  
  496. } // check_80286()
  497.  
  498.  
  499.  
  500. /***************************************************************
  501. * check_80386()
  502. *
  503. * Inputs: none
  504. *
  505. * Returns:
  506. *   3      if processor 80386
  507. *   0xffff otherwise
  508. ***************************************************************/
  509.  
  510. static WORD check_80386()
  511. {
  512.  
  513.         WORD cpu_type=0xffff;
  514.  
  515. _asm {   
  516.         mov     bx, sp
  517.         and        sp, not 3
  518.         pushfd                    // Push original EFLAGS 
  519.         pop     eax                // Get original EFLAGS
  520.         mov     ecx, eax        // Save original EFLAGS
  521.         xor     eax, 40000h        // Flip AC bit in EFLAGS
  522.         
  523.         push    eax             // Save new EFLAGS value on
  524.                                 //   stack
  525.         
  526.         popfd                   // Replace current EFLAGS value
  527.         pushfd                    // Get new EFLAGS
  528.         pop     eax             // Store new EFLAGS in EAX
  529.         
  530.         xor     eax, ecx        // Can't toggle AC bit, 
  531.                                 //   processor=80386
  532.         
  533.         mov     cpu_type, 3        // Turn on 80386 processor flag
  534.         jz      end_80386        // Jump if 80386 processor
  535.         mov        cpu_type, 0ffffh
  536. end_80386:
  537.         push    ecx
  538.         popfd
  539.         mov        sp, bx
  540.         mov        ax, cpu_type
  541.         and        eax, 0000ffffh
  542.       }
  543.  
  544.     return cpu_type;
  545.  
  546. } // check_80386()
  547.  
  548.  
  549.  
  550. /***************************************************************
  551. * check_IDProc()
  552. *
  553. * Inputs: none
  554. *
  555. * Returns:
  556. *  CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
  557. *
  558. *  Note: This function also sets the global variable clone_flag
  559. ***************************************************************/
  560.  
  561. static WORD check_IDProc() {
  562.  
  563.         int i=0;
  564.         WORD cpu_type=0xffff;
  565.         BYTE stepping=0;
  566.         BYTE model=0;
  567.         BYTE vendor_id[12]="------------";
  568.         BYTE intel_id[12]="GenuineIntel";
  569.  
  570. _asm {      
  571.  
  572.         xor     eax, eax        // Set up for CPUID instruction
  573.         
  574.         CPU_ID                  // Get and save vendor ID
  575.  
  576.         mov     dword ptr vendor_id, ebx
  577.         mov     dword ptr vendor_id[+4], edx
  578.         mov     dword ptr vendor_id[+8], ecx
  579. }
  580.  
  581. for (i=0;i<12;i++)
  582. {
  583.     if (!(vendor_id[i]==intel_id[i]))
  584.         clone_flag = 1;    
  585. }
  586.  
  587. _asm {
  588.  
  589.         cmp     eax, 1            // Make sure 1 is valid input 
  590.                                 //   for CPUID
  591.         
  592.         jl      end_IDProc        // If not, jump to end
  593.         xor     eax, eax
  594.         inc        eax
  595.         CPU_ID                    // Get family/model/stepping/
  596.                                 //   features
  597.  
  598.         mov     stepping, al
  599.         and        stepping, 0x0f //0fh
  600.         
  601.         and     al, 0f0h
  602.         shr        al, 4
  603.         mov     model, al
  604.         
  605.         and        eax, 0f00h
  606.         shr     eax, 8            // Isolate family
  607.         and        eax, 0fh
  608.         mov     cpu_type, ax    // Set _cpu_type with family
  609.  
  610. end_IDProc:
  611.         mov        ax, cpu_type
  612.       }
  613.     
  614.     return cpu_type;
  615.  
  616. } // Check_IDProc()
  617.  
  618.  
  619.  
  620.