Hardware/CPU/CPUID.cs
author moel.mich
Tue, 04 May 2010 17:32:41 +0000
changeset 108 4f569432e14b
parent 102 9620449d2620
child 112 69d29f1a2307
permissions -rw-r--r--
Fixed Issue 52.
     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       UIntPtr mask = (UIntPtr)(1L << thread);
   108 
   109       if (WinRing0.CpuidTx(CPUID_0, 0,
   110           out eax, out ebx, out ecx, out edx, mask)) {
   111         maxCpuid = eax;
   112         StringBuilder vendorBuilder = new StringBuilder();
   113         AppendRegister(vendorBuilder, ebx);
   114         AppendRegister(vendorBuilder, edx);
   115         AppendRegister(vendorBuilder, ecx);
   116         string cpuVendor = vendorBuilder.ToString();
   117         switch (cpuVendor) {
   118           case "GenuineIntel":
   119             vendor = Vendor.Intel;
   120             break;
   121           case "AuthenticAMD":
   122             vendor = Vendor.AMD;
   123             break;
   124           default:
   125             vendor = Vendor.Unknown;
   126             break;
   127         }
   128         eax = ebx = ecx = edx = 0;
   129         if (WinRing0.CpuidTx(CPUID_EXT, 0,
   130           out eax, out ebx, out ecx, out edx, mask))
   131           maxCpuidExt = eax - CPUID_EXT;
   132       } else {
   133         throw new ArgumentException();
   134       }
   135 
   136       if (maxCpuid == 0 || maxCpuidExt == 0)
   137         return;
   138 
   139       cpuidData = new uint[maxCpuid + 1, 4];
   140       for (uint i = 0; i < (maxCpuid + 1); i++)
   141         WinRing0.CpuidTx(CPUID_0 + i, 0, 
   142           out cpuidData[i, 0], out cpuidData[i, 1],
   143           out cpuidData[i, 2], out cpuidData[i, 3], mask);
   144 
   145       cpuidExtData = new uint[maxCpuidExt + 1, 4];
   146       for (uint i = 0; i < (maxCpuidExt + 1); i++)
   147         WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   148           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
   149           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
   150 
   151       StringBuilder nameBuilder = new StringBuilder();
   152       for (uint i = 2; i <= 4; i++) {
   153         if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   154           out eax, out ebx, out ecx, out edx, mask)) 
   155         {
   156           AppendRegister(nameBuilder, eax);
   157           AppendRegister(nameBuilder, ebx);
   158           AppendRegister(nameBuilder, ecx);
   159           AppendRegister(nameBuilder, edx);
   160         }
   161       }
   162       nameBuilder.Replace('\0', ' ');
   163       cpuBrandString = nameBuilder.ToString().Trim();
   164       nameBuilder.Replace("(R)", " ");
   165       nameBuilder.Replace("(TM)", " ");
   166       nameBuilder.Replace("(tm)", " ");
   167       nameBuilder.Replace("CPU", "");
   168       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
   169       name = nameBuilder.ToString();
   170       if (name.Contains("@"))
   171         name = name.Remove(name.LastIndexOf('@'));
   172       name = name.Trim();      
   173 
   174       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
   175         ((cpuidData[1, 0] & 0x0F00) >> 8);
   176       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
   177         ((cpuidData[1, 0] & 0xF0) >> 4);
   178       this.stepping = (cpuidData[1, 0] & 0x0F);
   179 
   180       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
   181 
   182       switch (vendor) {
   183         case Vendor.Intel:
   184           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   185           uint maxCoreIdPerPackage;
   186           if (maxCpuid >= 4)
   187             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   188           else
   189             maxCoreIdPerPackage = 1;
   190           threadMaskWith = 
   191             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
   192           coreMaskWith = NextLog2(maxCoreIdPerPackage);
   193           break;
   194         case Vendor.AMD:
   195           uint corePerPackage;
   196           if (maxCpuidExt >= 8)
   197             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
   198           else
   199             corePerPackage = 1;
   200           threadMaskWith = 0;
   201           coreMaskWith = NextLog2(corePerPackage);
   202           break;
   203         default:
   204           threadMaskWith = 0;
   205           coreMaskWith = 0;
   206           break;
   207       }
   208 
   209       processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
   210       coreId = (uint)((apicId >> (int)(threadMaskWith)) 
   211         - (processorId << (int)(coreMaskWith)));
   212       threadId = apicId
   213         - (processorId << (int)(coreMaskWith + threadMaskWith))
   214         - (coreId << (int)(threadMaskWith)); 
   215     }
   216 
   217     public string Name {
   218       get { return name; }
   219     }
   220 
   221     public string BrandString {
   222       get { return cpuBrandString; }
   223     }
   224 
   225     public int Thread {
   226       get { return thread; }
   227     }
   228 
   229     public uint MaxCPUID {
   230       get { return maxCpuid; }
   231     }
   232 
   233     public uint MaxCpuidExt {
   234       get { return maxCpuidExt; }
   235     }
   236 
   237     public Vendor Vendor {
   238       get { return vendor; }
   239     }
   240 
   241     public uint Family {
   242       get { return family; }
   243     }
   244 
   245     public uint Model {
   246       get { return model; }
   247     }
   248 
   249     public uint Stepping {
   250       get { return stepping; }
   251     }
   252 
   253     public uint ApicId {
   254       get { return apicId; }
   255     }
   256 
   257     public uint ProcessorId {
   258       get { return processorId; }
   259     }
   260 
   261     public uint CoreId {
   262       get { return coreId; }
   263     }
   264 
   265     public uint ThreadId {
   266       get { return threadId; }
   267     }
   268 
   269     public uint[,] Data {
   270       get { return cpuidData; }
   271     }
   272 
   273     public uint[,] ExtData {
   274       get { return cpuidExtData; }
   275     }
   276   }
   277 }