Hardware/CPU/CPUID.cs
author moel.mich
Sat, 15 May 2010 11:09:02 +0000
changeset 114 69dfa910e628
parent 105 f46d163ffba2
child 124 b68a6f3b82a3
permissions -rw-r--r--
Fixed Issue 55.
     1 /*
     2   
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
     4 
     5   The contents of this file are subject to the Mozilla Public License Version
     6   1.1 (the "License"); you may not use this file except in compliance with
     7   the License. You may obtain a copy of the License at
     8  
     9   http://www.mozilla.org/MPL/
    10 
    11   Software distributed under the License is distributed on an "AS IS" basis,
    12   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    13   for the specific language governing rights and limitations under the License.
    14 
    15   The Original Code is the Open Hardware Monitor code.
    16 
    17   The Initial Developer of the Original Code is 
    18   Michael Möller <m.moeller@gmx.ch>.
    19   Portions created by the Initial Developer are Copyright (C) 2009-2010
    20   the Initial Developer. All Rights Reserved.
    21 
    22   Contributor(s):
    23 
    24   Alternatively, the contents of this file may be used under the terms of
    25   either the GNU General Public License Version 2 or later (the "GPL"), or
    26   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    27   in which case the provisions of the GPL or the LGPL are applicable instead
    28   of those above. If you wish to allow use of your version of this file only
    29   under the terms of either the GPL or the LGPL, and not to allow others to
    30   use your version of this file under the terms of the MPL, indicate your
    31   decision by deleting the provisions above and replace them with the notice
    32   and other provisions required by the GPL or the LGPL. If you do not delete
    33   the provisions above, a recipient may use your version of this file under
    34   the terms of any one of the MPL, the GPL or the LGPL.
    35  
    36 */
    37 
    38 using System;
    39 using System.Collections.Generic;
    40 using System.Text;
    41 
    42 namespace OpenHardwareMonitor.Hardware.CPU {
    43   
    44   public enum Vendor {
    45     Unknown,
    46     Intel,
    47     AMD,
    48   }
    49   
    50   public class CPUID {
    51 
    52     private int thread;
    53 
    54     private uint maxCpuid = 0;
    55     private uint maxCpuidExt = 0;
    56 
    57     private Vendor vendor;
    58 
    59     private string cpuBrandString;
    60     private string name;
    61 
    62     private uint[,] cpuidData;
    63     private uint[,] cpuidExtData;
    64 
    65     private uint family;
    66     private uint model;
    67     private uint stepping;
    68 
    69     private uint apicId;
    70 
    71     private uint threadMaskWith;
    72     private uint coreMaskWith;
    73 
    74     private uint processorId;
    75     private uint coreId;
    76     private uint threadId;
    77 
    78     public static uint CPUID_0 = 0;
    79     public static uint CPUID_EXT = 0x80000000;
    80 
    81     private void AppendRegister(StringBuilder b, uint value) {
    82       b.Append((char)((value) & 0xff));
    83       b.Append((char)((value >> 8) & 0xff));
    84       b.Append((char)((value >> 16) & 0xff));
    85       b.Append((char)((value >> 24) & 0xff));
    86     }
    87 
    88     private uint NextLog2(long x) {
    89       if (x <= 0)
    90         return 0;
    91 
    92       x--;
    93       uint count = 0;
    94       while (x > 0) {
    95         x >>= 1;
    96         count++;
    97       }
    98 
    99       return count;
   100     }
   101 
   102     public CPUID(int thread) {
   103       this.thread = thread;
   104 
   105       uint eax, ebx, ecx, edx;
   106 
   107       if (thread >= 32)
   108         throw new ArgumentException();
   109       UIntPtr mask = (UIntPtr)(1L << thread);
   110 
   111       if (WinRing0.CpuidTx(CPUID_0, 0,
   112           out eax, out ebx, out ecx, out edx, mask)) {
   113         if (eax > 0)
   114           maxCpuid = eax;
   115         else
   116           return;
   117 
   118         StringBuilder vendorBuilder = new StringBuilder();
   119         AppendRegister(vendorBuilder, ebx);
   120         AppendRegister(vendorBuilder, edx);
   121         AppendRegister(vendorBuilder, ecx);
   122         string cpuVendor = vendorBuilder.ToString();
   123         switch (cpuVendor) {
   124           case "GenuineIntel":
   125             vendor = Vendor.Intel;
   126             break;
   127           case "AuthenticAMD":
   128             vendor = Vendor.AMD;
   129             break;
   130           default:
   131             vendor = Vendor.Unknown;
   132             break;
   133         }
   134         eax = ebx = ecx = edx = 0;
   135         if (WinRing0.CpuidTx(CPUID_EXT, 0,
   136           out eax, out ebx, out ecx, out edx, mask)) {
   137           if (eax > CPUID_EXT)
   138             maxCpuidExt = eax - CPUID_EXT;
   139           else
   140             return;
   141         }
   142       } else {
   143         throw new ArgumentException();
   144       }
   145 
   146       maxCpuid = Math.Min(maxCpuid, 1024);
   147       maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
   148 
   149       cpuidData = new uint[maxCpuid + 1, 4];
   150       for (uint i = 0; i < (maxCpuid + 1); i++)
   151         WinRing0.CpuidTx(CPUID_0 + i, 0, 
   152           out cpuidData[i, 0], out cpuidData[i, 1],
   153           out cpuidData[i, 2], out cpuidData[i, 3], mask);
   154 
   155       cpuidExtData = new uint[maxCpuidExt + 1, 4];
   156       for (uint i = 0; i < (maxCpuidExt + 1); i++)
   157         WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   158           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
   159           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
   160 
   161       StringBuilder nameBuilder = new StringBuilder();
   162       for (uint i = 2; i <= 4; i++) {
   163         if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   164           out eax, out ebx, out ecx, out edx, mask)) 
   165         {
   166           AppendRegister(nameBuilder, eax);
   167           AppendRegister(nameBuilder, ebx);
   168           AppendRegister(nameBuilder, ecx);
   169           AppendRegister(nameBuilder, edx);
   170         }
   171       }
   172       nameBuilder.Replace('\0', ' ');
   173       cpuBrandString = nameBuilder.ToString().Trim();
   174       nameBuilder.Replace("(R)", " ");
   175       nameBuilder.Replace("(TM)", " ");
   176       nameBuilder.Replace("(tm)", " ");
   177       nameBuilder.Replace("CPU", "");
   178       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
   179       name = nameBuilder.ToString();
   180       if (name.Contains("@"))
   181         name = name.Remove(name.LastIndexOf('@'));
   182       name = name.Trim();      
   183 
   184       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
   185         ((cpuidData[1, 0] & 0x0F00) >> 8);
   186       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
   187         ((cpuidData[1, 0] & 0xF0) >> 4);
   188       this.stepping = (cpuidData[1, 0] & 0x0F);
   189 
   190       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
   191 
   192       switch (vendor) {
   193         case Vendor.Intel:
   194           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   195           uint maxCoreIdPerPackage;
   196           if (maxCpuid >= 4)
   197             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   198           else
   199             maxCoreIdPerPackage = 1;
   200           threadMaskWith = 
   201             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
   202           coreMaskWith = NextLog2(maxCoreIdPerPackage);
   203           break;
   204         case Vendor.AMD:
   205           uint corePerPackage;
   206           if (maxCpuidExt >= 8)
   207             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
   208           else
   209             corePerPackage = 1;
   210           threadMaskWith = 0;
   211           coreMaskWith = NextLog2(corePerPackage);
   212           break;
   213         default:
   214           threadMaskWith = 0;
   215           coreMaskWith = 0;
   216           break;
   217       }
   218 
   219       processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
   220       coreId = (uint)((apicId >> (int)(threadMaskWith)) 
   221         - (processorId << (int)(coreMaskWith)));
   222       threadId = apicId
   223         - (processorId << (int)(coreMaskWith + threadMaskWith))
   224         - (coreId << (int)(threadMaskWith)); 
   225     }
   226 
   227     public string Name {
   228       get { return name; }
   229     }
   230 
   231     public string BrandString {
   232       get { return cpuBrandString; }
   233     }
   234 
   235     public int Thread {
   236       get { return thread; }
   237     }
   238 
   239     public uint MaxCPUID {
   240       get { return maxCpuid; }
   241     }
   242 
   243     public uint MaxCpuidExt {
   244       get { return maxCpuidExt; }
   245     }
   246 
   247     public Vendor Vendor {
   248       get { return vendor; }
   249     }
   250 
   251     public uint Family {
   252       get { return family; }
   253     }
   254 
   255     public uint Model {
   256       get { return model; }
   257     }
   258 
   259     public uint Stepping {
   260       get { return stepping; }
   261     }
   262 
   263     public uint ApicId {
   264       get { return apicId; }
   265     }
   266 
   267     public uint ProcessorId {
   268       get { return processorId; }
   269     }
   270 
   271     public uint CoreId {
   272       get { return coreId; }
   273     }
   274 
   275     public uint ThreadId {
   276       get { return threadId; }
   277     }
   278 
   279     public uint[,] Data {
   280       get { return cpuidData; }
   281     }
   282 
   283     public uint[,] ExtData {
   284       get { return cpuidExtData; }
   285     }
   286   }
   287 }