home *** CD-ROM | disk | FTP | other *** search
/ PC User 1997 April / PCU_APR_97.ISO / utils / cpu / cpuinfo / source / cpuinf16 / cpuid.c next >
Encoding:
C/C++ Source or Header  |  1995-10-26  |  16.8 KB  |  694 lines

  1. /***************************************************************
  2. * C file: cpuid.c... for cpuinf16 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 16-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 FAR PASCAL _export wincpuidsupport() {
  64.  
  65.     int cpuid_support=1;
  66.     
  67.     _asm {
  68.  
  69.         OPND32
  70.         pushf                    // Get original EFLAGS
  71.         OPND32
  72.         pop        ax
  73.         OPND32
  74.         mov     cx, ax            
  75.         
  76.         //xor     ax, 200000h    // flip ID bit in EFLAGS
  77.         // the following 7 lines replace the xor above
  78.         mov        dx, ax
  79.         OPND32
  80.         shr        ax, 16
  81.         xor        ax, 0020h
  82.         OPND32
  83.         shl        ax, 16
  84.         mov        ax, dx
  85.         /***********************************************/
  86.  
  87.         OPND32
  88.         push    ax              // Save new EFLAGS value on 
  89.                                 //   stack
  90.         OPND32
  91.         popf                    // Replace current EFLAGS value
  92.         OPND32
  93.         pushf                    // Get new EFLAGS
  94.         OPND32
  95.         pop     ax                // Store new EFLAGS in EAX
  96.         OPND32
  97.         xor     ax, cx            // Can't toggle AC bit, 
  98.         
  99.         jnz support      
  100.         mov cpuid_support,0
  101.     
  102.     support:        
  103.     
  104.     }                    
  105.     
  106.     return cpuid_support;
  107. } // wincpuidsupport()
  108.  
  109.  
  110.  
  111. /***************************************************************
  112. * wincpuid()
  113. *
  114. * Inputs: none
  115. *
  116. * Returns:
  117. *  0 = 8086/88
  118. *  2 = 80286
  119. *  3 = 80386
  120. *  4 = 80486
  121. *  5 = Pentium(R) Processor
  122. *  6 = PentiumPro(R) Processor
  123. *  7 or higher = Processor beyond the PentiumPro6(R) Processor
  124. *
  125. *  Note: This function also sets the global variable clone_flag
  126. ***************************************************************/
  127.  
  128. WORD FAR PASCAL _export wincpuid() {
  129.  
  130.     WORD cpuid;
  131.     
  132.     if ( wincpuidsupport() )     // Determine whether CPUID 
  133.                                 //   opcode is supported
  134.         cpuid=check_IDProc();
  135.  
  136.     else {
  137.         
  138.         clone_flag=check_clone();
  139.     
  140.         cpuid=check_8086();            // Will return FFFFh or 0
  141.         if (cpuid == 0) goto end;
  142.     
  143.         cpuid=check_80286();           // Will return FFFFh or 2
  144.         if (cpuid == 2) goto end;
  145.  
  146.         cpuid=check_80386();           // Will return FFFFh or 3
  147.         if (cpuid == 3) goto end;    // temporarily commented out.
  148.         
  149.         cpuid=4;        // If the processor does not support CPUID,
  150.                         //  is not an 8086, 80286, or 80386, assign
  151.                         //  processor to be an 80486
  152.     }
  153.  
  154. end:
  155.     if (clone_flag)
  156.         cpuid = cpuid | CLONE_MASK;    // Signify that a clone has been
  157.                                     //   detected by setting MSB high 
  158.  
  159.        return cpuid;
  160. } // wincpuid()
  161.  
  162.  
  163.  
  164. /***************************************************************
  165. * wincpuidext()
  166. *
  167. * Inputs: none
  168. *
  169. * Returns:
  170. * AX(15:14) = Reserved (mask these off in the calling code 
  171. *                before using)
  172. * AX(13:12) = Processor type (00=Standard OEM CPU, 01=OverDrive,
  173. *                10=Dual CPU, 11=Reserved)
  174. * AX(11:8)  = CPU Family (the same 4-bit quantity as wincpuid())
  175. * AX(7:4)   = CPU Model, if the processor supports the CPUID 
  176. *                opcode; zero otherwise
  177. * AX(3:0)   = Stepping #, if the processor supports the CPUID 
  178. *                opcode; zero otherwise
  179. *
  180. *  Note: This function also sets the global variable clone_flag
  181. ***************************************************************/
  182.  
  183. WORD FAR PASCAL _export wincpuidext()
  184. {
  185.         int i=0;
  186.         WORD cpu_type=0x0000;
  187.         WORD cpuidext=0x0000;
  188.         BYTE vendor_id[12]="------------";
  189.         BYTE intel_id[12]="GenuineIntel";
  190.  
  191.     if ( wincpuidsupport() ) {
  192.  
  193. _asm {
  194.  
  195.         OPND32
  196.         xor     ax, ax          // Set up for CPUID instruction
  197.         CPU_ID                  // Get and save vendor ID
  198.  
  199.         OPND32
  200.         mov     word ptr vendor_id, bx
  201.         OPND32
  202.         mov     word ptr vendor_id[+4], dx
  203.         OPND32
  204.         mov     word ptr vendor_id[+8], cx
  205. }
  206.  
  207. for (i=0;i<12;i++)
  208. {
  209.     if (!(vendor_id[i]==intel_id[i]))
  210.         clone_flag = 1;
  211. }
  212.  
  213. _asm {
  214.         OPND32
  215.         cmp     ax, 1            // Make sure 1 is valid input 
  216.                                 //   for CPUID
  217.         
  218.         jl      end_cpuidext    // If not, jump to end
  219.         OPND32
  220.         xor     ax, ax
  221.         OPND32
  222.         inc        ax
  223.         CPU_ID                    // Get family/model/stepping/
  224.                                 //   features
  225.         mov     cpuidext, ax
  226.  
  227. end_cpuidext:
  228.         mov        ax, cpuidext
  229.       }
  230.     }
  231.     
  232.     else {
  233.  
  234.     cpu_type = wincpuid();        // If CPUID opcode is not
  235.     cpuidext = cpu_type << 8;    //   supported, put family
  236.                                 //   value in extensions and
  237.     }                            //   return
  238.     
  239.     return cpuidext;
  240.  
  241. } // wincpuidext()
  242.  
  243.  
  244.  
  245. /***************************************************************
  246. * wincpufeatures()
  247. *
  248. * Inputs: none
  249. *
  250. * Returns:
  251. *   0 = Processor which does not execute the CPUID instruction.
  252. *          This includes 8086, 8088, 80286, 80386, and some 
  253. *           older 80486 processors.                       
  254. *
  255. * Else
  256. *   Feature Flags (refer to App Note AP-485 for description).
  257. *      This DWORD was put into EDX by the CPUID instruction.
  258. *
  259. *    Current flag assignment is as follows:
  260. *
  261. *        bit31..10   reserved (=0)
  262. *        bit9=1      CPU contains a local APIC (iPentium-3V)
  263. *        bit8=1      CMPXCHG8B instruction supported
  264. *        bit7=1      machine check exception supported
  265. *        bit6=0      reserved (36bit-addressing & 2MB-paging)
  266. *        bit5=1      iPentium-style MSRs supported
  267. *        bit4=1      time stamp counter TSC supported
  268. *        bit3=1      page size extensions supported
  269. *        bit2=1      I/O breakpoints supported
  270. *        bit1=1      enhanced virtual 8086 mode supported
  271. *        bit0=1      CPU contains a floating-point unit (FPU)
  272. *
  273. *    Note: New bits will be assigned on future processors... see
  274. *         processor data books for updated information
  275. *
  276. *    Note: This function also sets the global variable clone_flag
  277. ***************************************************************/
  278.  
  279. DWORD FAR PASCAL _export wincpufeatures()
  280. {
  281.     int i=0;
  282.     DWORD cpuff=0x00000000;
  283.     BYTE vendor_id[12]="------------";
  284.     BYTE intel_id[12]="GenuineIntel";
  285.  
  286.     if ( wincpuidsupport() ) {
  287.             
  288. _asm {
  289.  
  290.         OPND32
  291.         xor     ax, ax          // Set up for CPUID instruction
  292.         CPU_ID                  // Get and save vendor ID
  293.  
  294.         OPND32
  295.         mov     word ptr vendor_id, bx
  296.         OPND32
  297.         mov     word ptr vendor_id[+4], dx
  298.         OPND32
  299.         mov     word ptr vendor_id[+8], cx
  300. }
  301.  
  302. for (i=0;i<12;i++)
  303. {
  304.     if (!(vendor_id[i]==intel_id[i]))
  305.         clone_flag = 1;
  306. }
  307.  
  308. _asm {
  309.  
  310.         OPND32
  311.         cmp     ax, 1            // Make sure 1 is valid input 
  312.                                 //   for CPUID
  313.         
  314.         jl      end_NotIntel    // If not, jump to end
  315.         OPND32
  316.         xor     ax, ax
  317.         OPND32
  318.         inc        ax
  319.         CPU_ID                    // Get family/model/stepping/
  320.                                 //   features
  321.  
  322.         jmp        end_cpuff
  323.  
  324.  
  325. end_NotIntel:
  326.         OPND32
  327.         xor        dx, dx            // Put 00000000h into edx
  328.         
  329. end_cpuff:
  330.         OPND32
  331.         mov        ax, dx            // Return feature flags
  332.            
  333.            OPND32
  334.            mov        word ptr cpuff, dx
  335.       }                     
  336.     }
  337.     return cpuff;
  338.  
  339. } //wincpufeatures()
  340.  
  341.  
  342.  
  343. /***************************************************************
  344. * winrdtsc()
  345. *
  346. * Inputs: none
  347. *
  348. * Returns:
  349. *   0 = CPU does not support the time stamp register
  350. *
  351. * Else
  352. *   Returns a variable of type TIME_STAMP which is composed of 
  353. *      two DWORD variables. The 'High' DWORD contains the upper
  354. *      32-bits of the Time Stamp Register. The 'Low' DWORD 
  355. *      contains the lower 32-bits of the Time Stamp Register.
  356. *
  357. *  Note: This function also sets the global variable clone_flag
  358. ***************************************************************/
  359.  
  360. struct TIME_STAMP FAR PASCAL _export winrdtsc()
  361. {
  362.     struct TIME_STAMP timestamp;    // Return variable for time
  363.                                     //   stamp read
  364.     
  365.     unsigned short u0=0;            // Temporary variables 
  366.     unsigned short u1=0;
  367.     unsigned short u2=0;
  368.     unsigned short u3=0;
  369.  
  370.     DWORD features = wincpufeatures();    // Processor Features
  371.     
  372.     if ( features & 0x00000010 ) {
  373.  
  374.         RDTSC                        // Read Time Stamp
  375.     
  376.         __asm
  377.             {
  378.             MOV CL, 16
  379.                             
  380.             MOV u0, AX
  381.             OPND32
  382.             SHR    AX,CL
  383.             MOV u1, AX
  384.              
  385.             MOV u2,DX
  386.             OPND32
  387.             SHR DX,CL
  388.             MOV u3,DX
  389.             }
  390.     }
  391.     
  392.     timestamp.High = (DWORD) ( u3*65536 + u2 );
  393.     timestamp.Low  = (DWORD) ( u1*65536 + u0 ); 
  394.                                // Move two 16-bit values into one 
  395.                                //   32-bit value for the time stamp
  396.                                //   read at both the beginning and 
  397.                                //   end of the test.
  398.     return timestamp;
  399.  
  400. } // winrdtsc 
  401.  
  402.  
  403.  
  404. /***************************************************************
  405. * getdllversion()
  406. *
  407. * Inputs: none
  408. *
  409. * Returns:  Major and Minor version of this DLL.
  410. *         
  411. *        i.e.    getdllversion() = 0x01 00
  412. *                      Major Version<--|-->Minor Version
  413. *            
  414. ***************************************************************/
  415.  
  416. unsigned short FAR PASCAL _export getdllversion(void) {
  417.     unsigned short Version = VERSION;
  418.     
  419.     return Version;
  420.  
  421. } // getdllversion()
  422.  
  423.  
  424.  
  425. // Internal Private Functions //////////////////////////////////
  426.  
  427. /***************************************************************
  428. * check_clone()
  429. *
  430. * Inputs: none
  431. *
  432. * Returns:
  433. *   1      if processor is clone (limited detection ability)
  434. *   0      otherwise
  435. ***************************************************************/
  436.  
  437. static WORD check_clone()
  438. {
  439.     short cpu_type=0;
  440.  
  441.     _asm 
  442.         {
  443.                       MOV AX,5555h    // Check to make sure this
  444.                     XOR DX,DX        //   is a 32-bit processor
  445.                     MOV CX,2h
  446.                     DIV CX            // Perform Division
  447.                     CLC
  448.                     JNZ no_clone
  449.                     JMP clone
  450.         no_clone:    STC
  451.         clone:        PUSHF
  452.                     POP AX          // Get the flags
  453.                     AND AL,1
  454.                     XOR AL,1        // AL=0 is probably Intel,
  455.                                     //   AL=1 is a Clone
  456.                     
  457.                     MOV cpu_type, ax
  458.         }
  459.     
  460.     cpu_type = cpu_type & 0x0001;
  461.     
  462.     return cpu_type;
  463.         
  464. } // check_clone()
  465.  
  466.  
  467.  
  468. /***************************************************************
  469. * check_8086()
  470. *
  471. * Inputs: none
  472. *
  473. * Returns: 
  474. *   0      if processor 8086
  475. *   0xffff otherwise
  476. ***************************************************************/
  477.  
  478. static WORD check_8086()
  479. {
  480.  
  481.         WORD cpu_type=0xffff;
  482.  
  483. _asm {
  484.         pushf                   // Push original FLAGS
  485.         pop     ax              // Get original FLAGS
  486.         mov     cx, ax          // Save original FLAGS
  487.         and     ax, 0fffh       // Clear bits 12-15 in FLAGS
  488.         push    ax              // Save new FLAGS value on stack
  489.         popf                    // Replace current FLAGS value
  490.         pushf                   // Get new FLAGS
  491.         pop     ax              // Store new FLAGS in AX
  492.         and     ax, 0f000h      // If bits 12-15 are set, then
  493.         cmp     ax, 0f000h      //   processor is an 8086/8088
  494.         mov     cpu_type, 0        // Turn on 8086/8088 flag
  495.         je      end_8086        // Jump if processor is 8086/
  496.                                 //   8088
  497.         mov        cpu_type, 0ffffh
  498. end_8086:
  499.         push     cx
  500.         popf
  501.         mov        ax, cpu_type
  502.  
  503.       }
  504.     return cpu_type;
  505. } // check_8086()
  506.  
  507.  
  508.  
  509. /***************************************************************
  510. * check_80286()
  511. *
  512. * Inputs: none
  513. *
  514. * Returns:
  515. *   2      if processor 80286
  516. *   0xffff otherwise
  517. ***************************************************************/
  518.  
  519. static WORD check_80286()
  520. {
  521.  
  522.         WORD cpu_type=0xffff;
  523.  
  524. _asm {
  525.         pushf
  526.         pop        cx
  527.         mov        bx, cx
  528.         or      cx, 0f000h      // Try to set bits 12-15
  529.         push    cx              // Save new FLAGS value on stack
  530.         popf                    // Replace current FLAGS value
  531.         pushf                   // Get new FLAGS
  532.         pop     ax              // Store new FLAGS in AX
  533.         and     ax, 0f000h      // If bits 12-15 are clear
  534.         
  535.         mov     cpu_type, 2     // Processor=80286, turn on 
  536.                                 //   80286 flag
  537.         
  538.         jz      end_80286       // If no bits set, processor is 
  539.                                 //   80286
  540.         
  541.         mov        cpu_type, 0ffffh
  542. end_80286:
  543.         push    bx
  544.         popf
  545.         mov        ax, cpu_type
  546.  
  547.       }
  548.     return cpu_type;
  549. } // check_80286()
  550.  
  551.  
  552.  
  553.  
  554. /***************************************************************
  555. * check_80386()
  556. *
  557. * Inputs: none
  558. *
  559. * Returns:
  560. *   3      if processor 80386
  561. *   0xffff otherwise
  562. ***************************************************************/
  563.  
  564. static WORD check_80386()
  565. {
  566.  
  567.         WORD cpu_type=0xffff;
  568.  
  569. _asm {
  570.         mov     bx, sp
  571.         and        sp, not 3
  572.         OPND32
  573.         pushf                    // Push original EFLAGS
  574.         OPND32
  575.         pop     ax                // Get original EFLAGS
  576.         OPND32
  577.         mov     cx, ax            // Save original EFLAGS
  578.         
  579.         //xor     ax, 40000h     ; flip AC bit in EFLAGS
  580.         // the following 7 lines replace the xor above
  581.         
  582.         mov        dx, ax
  583.         OPND32
  584.         shr        ax, 16
  585.         xor        ax, 0004h
  586.         OPND32
  587.         shl        ax, 16
  588.         mov        ax, dx
  589.         /***********************************************/
  590.  
  591.         OPND32
  592.         push    ax              // Save new EFLAGS value on 
  593.                                 //   stack
  594.         OPND32
  595.         popf                    // Replace current EFLAGS value
  596.         OPND32
  597.         pushf                    // Get new EFLAGS
  598.         OPND32
  599.         pop     ax                // Store new EFLAGS in EAX
  600.         OPND32
  601.         xor     ax, cx            // Can't toggle AC bit, 
  602.                                 //   processor=80386
  603.         
  604.         mov     cpu_type, 3        // Turn on 80386 processor flag
  605.         jz      end_80386        // Jump if 80386 processor
  606.         mov        cpu_type, 0ffffh
  607. end_80386:
  608.         OPND32
  609.         push    cx
  610.         OPND32    
  611.         popf
  612.         mov        sp, bx
  613.         mov        ax, cpu_type
  614.         OPND32
  615.         and        ax, 0000ffffh
  616.       }
  617.     return cpu_type;
  618. } // check_80386()
  619.  
  620.  
  621.   
  622. /***************************************************************
  623. * check_IDProc()
  624. *
  625. * Inputs: none
  626. *
  627. * Returns:
  628. *  CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
  629. *
  630. *  Note: This function also sets the global variable clone_flag
  631. ***************************************************************/
  632.  
  633. static WORD check_IDProc()        // Processor can execute CPUID 
  634.                                 //   op; may be 80486 or greater
  635. {
  636.  
  637.         int i=0;
  638.         WORD cpu_type=0xffff;
  639.         BYTE stepping=0;
  640.         BYTE model=0;
  641.         BYTE vendor_id[12]="------------";
  642.         BYTE intel_id[12]="GenuineIntel";
  643.  
  644. _asm {
  645.  
  646.         OPND32
  647.         xor     ax, ax          // Set up for CPUID instruction
  648.         CPU_ID                  // Get and save vendor ID
  649.  
  650.         OPND32
  651.         mov     word ptr vendor_id, bx
  652.         OPND32
  653.         mov     word ptr vendor_id[+4], dx
  654.         OPND32
  655.         mov     word ptr vendor_id[+8], cx
  656. }
  657.  
  658. for (i=0;i<12;i++)
  659. {
  660.     if (!(vendor_id[i]==intel_id[i]))
  661.         clone_flag = 1;
  662. }
  663.  
  664. _asm {
  665.         OPND32
  666.         cmp     ax, 1            // Make sure 1 is valid input 
  667.                                 //   for CPUID
  668.         
  669.         jl      end_IDProc        // If not, jump to end
  670.         OPND32
  671.         xor     ax, ax
  672.         OPND32
  673.         inc        ax
  674.         CPU_ID                    // Get family/model/stepping/
  675.                                 //   features
  676.  
  677.         mov     stepping, al
  678.         and        stepping, 0fh
  679.  
  680.         and     al, 0f0h
  681.         shr        al, 4
  682.         mov     model, al
  683.  
  684.         and        ax, 0f00h
  685.         shr     ax, 8            // Isolate family
  686.         and        ax, 0fh
  687.         mov     cpu_type, ax    // Set cpu_type with family
  688.  
  689. end_IDProc:
  690.         mov        ax, cpu_type
  691.       }
  692.     return cpu_type;
  693. } // check_IDPRoc()
  694.