Hardware/CPU/CPUID.cs
author moel.mich
Sun, 08 Aug 2010 13:57:26 +0000
changeset 165 813d8bc3192f
parent 124 b68a6f3b82a3
child 167 b7cc9d09aefe
permissions -rw-r--r--
Refactored the hardware monitoring code into a library (Issue 101).
     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   internal enum Vendor {
    45     Unknown,
    46     Intel,
    47     AMD,
    48   }
    49 
    50   internal class CPUID {
    51 
    52     private int thread;
    53 
    54     private Vendor vendor = Vendor.Unknown;
    55 
    56     private string cpuBrandString = "";
    57     private string name = "";
    58 
    59     private uint[,] cpuidData = new uint[0, 0];
    60     private uint[,] cpuidExtData = new uint[0, 0];
    61 
    62     private uint family;
    63     private uint model;
    64     private uint stepping;
    65 
    66     private uint apicId;
    67 
    68     private uint threadMaskWith;
    69     private uint coreMaskWith;
    70 
    71     private uint processorId;
    72     private uint coreId;
    73     private uint threadId;
    74 
    75     public static uint CPUID_0 = 0;
    76     public static uint CPUID_EXT = 0x80000000;
    77 
    78     private void AppendRegister(StringBuilder b, uint value) {
    79       b.Append((char)((value) & 0xff));
    80       b.Append((char)((value >> 8) & 0xff));
    81       b.Append((char)((value >> 16) & 0xff));
    82       b.Append((char)((value >> 24) & 0xff));
    83     }
    84 
    85     private uint NextLog2(long x) {
    86       if (x <= 0)
    87         return 0;
    88 
    89       x--;
    90       uint count = 0;
    91       while (x > 0) {
    92         x >>= 1;
    93         count++;
    94       }
    95 
    96       return count;
    97     }
    98 
    99     public CPUID(int thread) {
   100       this.thread = thread;
   101 
   102       uint maxCpuid = 0;
   103       uint maxCpuidExt = 0;
   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         } else {
   142           throw new ArgumentException();
   143         }
   144       } else {
   145         throw new ArgumentException();
   146       }
   147 
   148       maxCpuid = Math.Min(maxCpuid, 1024);
   149       maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
   150 
   151       cpuidData = new uint[maxCpuid + 1, 4];
   152       for (uint i = 0; i < (maxCpuid + 1); i++)
   153         WinRing0.CpuidTx(CPUID_0 + i, 0, 
   154           out cpuidData[i, 0], out cpuidData[i, 1],
   155           out cpuidData[i, 2], out cpuidData[i, 3], mask);
   156 
   157       cpuidExtData = new uint[maxCpuidExt + 1, 4];
   158       for (uint i = 0; i < (maxCpuidExt + 1); i++)
   159         WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   160           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
   161           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
   162 
   163       StringBuilder nameBuilder = new StringBuilder();
   164       for (uint i = 2; i <= 4; i++) {
   165         if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
   166           out eax, out ebx, out ecx, out edx, mask)) 
   167         {
   168           AppendRegister(nameBuilder, eax);
   169           AppendRegister(nameBuilder, ebx);
   170           AppendRegister(nameBuilder, ecx);
   171           AppendRegister(nameBuilder, edx);
   172         }
   173       }
   174       nameBuilder.Replace('\0', ' ');
   175       cpuBrandString = nameBuilder.ToString().Trim();
   176       nameBuilder.Replace("(R)", " ");
   177       nameBuilder.Replace("(TM)", " ");
   178       nameBuilder.Replace("(tm)", " ");
   179       nameBuilder.Replace("CPU", "");
   180       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
   181       name = nameBuilder.ToString();
   182       if (name.Contains("@"))
   183         name = name.Remove(name.LastIndexOf('@'));
   184       name = name.Trim();      
   185 
   186       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
   187         ((cpuidData[1, 0] & 0x0F00) >> 8);
   188       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
   189         ((cpuidData[1, 0] & 0xF0) >> 4);
   190       this.stepping = (cpuidData[1, 0] & 0x0F);
   191 
   192       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
   193 
   194       switch (vendor) {
   195         case Vendor.Intel:
   196           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   197           uint maxCoreIdPerPackage;
   198           if (maxCpuid >= 4)
   199             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   200           else
   201             maxCoreIdPerPackage = 1;
   202           threadMaskWith = 
   203             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
   204           coreMaskWith = NextLog2(maxCoreIdPerPackage);
   205           break;
   206         case Vendor.AMD:
   207           uint corePerPackage;
   208           if (maxCpuidExt >= 8)
   209             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
   210           else
   211             corePerPackage = 1;
   212           threadMaskWith = 0;
   213           coreMaskWith = NextLog2(corePerPackage);
   214           break;
   215         default:
   216           threadMaskWith = 0;
   217           coreMaskWith = 0;
   218           break;
   219       }
   220 
   221       processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
   222       coreId = (uint)((apicId >> (int)(threadMaskWith)) 
   223         - (processorId << (int)(coreMaskWith)));
   224       threadId = apicId
   225         - (processorId << (int)(coreMaskWith + threadMaskWith))
   226         - (coreId << (int)(threadMaskWith)); 
   227     }
   228 
   229     public string Name {
   230       get { return name; }
   231     }
   232 
   233     public string BrandString {
   234       get { return cpuBrandString; }
   235     }
   236 
   237     public int Thread {
   238       get { return thread; }
   239     }
   240 
   241     public Vendor Vendor {
   242       get { return vendor; }
   243     }
   244 
   245     public uint Family {
   246       get { return family; }
   247     }
   248 
   249     public uint Model {
   250       get { return model; }
   251     }
   252 
   253     public uint Stepping {
   254       get { return stepping; }
   255     }
   256 
   257     public uint ApicId {
   258       get { return apicId; }
   259     }
   260 
   261     public uint ProcessorId {
   262       get { return processorId; }
   263     }
   264 
   265     public uint CoreId {
   266       get { return coreId; }
   267     }
   268 
   269     public uint ThreadId {
   270       get { return threadId; }
   271     }
   272 
   273     public uint[,] Data {
   274       get { return cpuidData; }
   275     }
   276 
   277     public uint[,] ExtData {
   278       get { return cpuidExtData; }
   279     }
   280   }
   281 }