Hardware/CPU/CPUID.cs
author moel.mich
Sun, 31 Oct 2010 22:08:47 +0000
changeset 236 763675f19ff4
parent 195 0ee888c485d5
child 238 bddc6e01840a
permissions -rw-r--r--
Replaced the non-kernel code of WinRing0 with a managed implementation. The new implementation should fix Issue 32 and simplify further work on Issue 46.
     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.Text;
    40 
    41 namespace OpenHardwareMonitor.Hardware.CPU {
    42 
    43   internal enum Vendor {
    44     Unknown,
    45     Intel,
    46     AMD,
    47   }
    48 
    49   internal class CPUID {
    50 
    51     private readonly int thread;
    52 
    53     private readonly Vendor vendor = Vendor.Unknown;
    54 
    55     private readonly string cpuBrandString = "";
    56     private readonly string name = "";
    57 
    58     private readonly uint[,] cpuidData = new uint[0, 0];
    59     private readonly uint[,] cpuidExtData = new uint[0, 0];
    60 
    61     private readonly uint family;
    62     private readonly uint model;
    63     private readonly uint stepping;
    64 
    65     private readonly uint apicId;
    66 
    67     private readonly uint threadMaskWith;
    68     private readonly uint coreMaskWith;
    69 
    70     private readonly uint processorId;
    71     private readonly uint coreId;
    72     private readonly uint threadId;
    73 
    74     public const uint CPUID_0 = 0;
    75     public const uint CPUID_EXT = 0x80000000;
    76 
    77     private static void AppendRegister(StringBuilder b, uint value) {
    78       b.Append((char)((value) & 0xff));
    79       b.Append((char)((value >> 8) & 0xff));
    80       b.Append((char)((value >> 16) & 0xff));
    81       b.Append((char)((value >> 24) & 0xff));
    82     }
    83 
    84     private static uint NextLog2(long x) {
    85       if (x <= 0)
    86         return 0;
    87 
    88       x--;
    89       uint count = 0;
    90       while (x > 0) {
    91         x >>= 1;
    92         count++;
    93       }
    94 
    95       return count;
    96     }
    97 
    98     public CPUID(int thread) {
    99       this.thread = thread;
   100 
   101       uint maxCpuid = 0;
   102       uint maxCpuidExt = 0;
   103 
   104       uint eax, ebx, ecx, edx;
   105 
   106       if (thread >= 32)
   107         throw new ArgumentOutOfRangeException("thread");
   108       UIntPtr mask = (UIntPtr)(1L << thread);
   109 
   110       if (Opcode.CpuidTx(CPUID_0, 0,
   111           out eax, out ebx, out ecx, out edx, mask)) {
   112         if (eax > 0)
   113           maxCpuid = eax;
   114         else
   115           return;
   116 
   117         StringBuilder vendorBuilder = new StringBuilder();
   118         AppendRegister(vendorBuilder, ebx);
   119         AppendRegister(vendorBuilder, edx);
   120         AppendRegister(vendorBuilder, ecx);
   121         string cpuVendor = vendorBuilder.ToString();
   122         switch (cpuVendor) {
   123           case "GenuineIntel":
   124             vendor = Vendor.Intel;
   125             break;
   126           case "AuthenticAMD":
   127             vendor = Vendor.AMD;
   128             break;
   129           default:
   130             vendor = Vendor.Unknown;
   131             break;
   132         }
   133         eax = ebx = ecx = edx = 0;
   134         if (Opcode.CpuidTx(CPUID_EXT, 0,
   135           out eax, out ebx, out ecx, out edx, mask)) {
   136           if (eax > CPUID_EXT)
   137             maxCpuidExt = eax - CPUID_EXT;
   138           else
   139             return;
   140         } else {
   141           throw new ArgumentOutOfRangeException("thread");
   142         }
   143       } else {
   144         throw new ArgumentOutOfRangeException("thread");
   145       }
   146 
   147       maxCpuid = Math.Min(maxCpuid, 1024);
   148       maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
   149 
   150       cpuidData = new uint[maxCpuid + 1, 4];
   151       for (uint i = 0; i < (maxCpuid + 1); i++)
   152         Opcode.CpuidTx(CPUID_0 + i, 0, 
   153           out cpuidData[i, 0], out cpuidData[i, 1],
   154           out cpuidData[i, 2], out cpuidData[i, 3], mask);
   155 
   156       cpuidExtData = new uint[maxCpuidExt + 1, 4];
   157       for (uint i = 0; i < (maxCpuidExt + 1); i++)
   158         Opcode.CpuidTx(CPUID_EXT + i, 0, 
   159           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
   160           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
   161 
   162       StringBuilder nameBuilder = new StringBuilder();
   163       for (uint i = 2; i <= 4; i++) {
   164         if (Opcode.CpuidTx(CPUID_EXT + i, 0, 
   165           out eax, out ebx, out ecx, out edx, mask)) 
   166         {
   167           AppendRegister(nameBuilder, eax);
   168           AppendRegister(nameBuilder, ebx);
   169           AppendRegister(nameBuilder, ecx);
   170           AppendRegister(nameBuilder, edx);
   171         }
   172       }
   173       nameBuilder.Replace('\0', ' ');
   174       cpuBrandString = nameBuilder.ToString().Trim();
   175       nameBuilder.Replace("(R)", " ");
   176       nameBuilder.Replace("(TM)", " ");
   177       nameBuilder.Replace("(tm)", " ");
   178       nameBuilder.Replace("CPU", "");
   179       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
   180       name = nameBuilder.ToString();
   181       if (name.Contains("@"))
   182         name = name.Remove(name.LastIndexOf('@'));
   183       name = name.Trim();      
   184 
   185       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
   186         ((cpuidData[1, 0] & 0x0F00) >> 8);
   187       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
   188         ((cpuidData[1, 0] & 0xF0) >> 4);
   189       this.stepping = (cpuidData[1, 0] & 0x0F);
   190 
   191       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
   192 
   193       switch (vendor) {
   194         case Vendor.Intel:
   195           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   196           uint maxCoreIdPerPackage;
   197           if (maxCpuid >= 4)
   198             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   199           else
   200             maxCoreIdPerPackage = 1;
   201           threadMaskWith = 
   202             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
   203           coreMaskWith = NextLog2(maxCoreIdPerPackage);
   204           break;
   205         case Vendor.AMD:
   206           uint corePerPackage;
   207           if (maxCpuidExt >= 8)
   208             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
   209           else
   210             corePerPackage = 1;
   211           threadMaskWith = 0;
   212           coreMaskWith = NextLog2(corePerPackage);
   213           break;
   214         default:
   215           threadMaskWith = 0;
   216           coreMaskWith = 0;
   217           break;
   218       }
   219 
   220       processorId = (apicId >> (int)(coreMaskWith + threadMaskWith));
   221       coreId = ((apicId >> (int)(threadMaskWith)) 
   222         - (processorId << (int)(coreMaskWith)));
   223       threadId = apicId
   224         - (processorId << (int)(coreMaskWith + threadMaskWith))
   225         - (coreId << (int)(threadMaskWith)); 
   226     }
   227 
   228     public string Name {
   229       get { return name; }
   230     }
   231 
   232     public string BrandString {
   233       get { return cpuBrandString; }
   234     }
   235 
   236     public int Thread {
   237       get { return thread; }
   238     }
   239 
   240     public Vendor Vendor {
   241       get { return vendor; }
   242     }
   243 
   244     public uint Family {
   245       get { return family; }
   246     }
   247 
   248     public uint Model {
   249       get { return model; }
   250     }
   251 
   252     public uint Stepping {
   253       get { return stepping; }
   254     }
   255 
   256     public uint ApicId {
   257       get { return apicId; }
   258     }
   259 
   260     public uint ProcessorId {
   261       get { return processorId; }
   262     }
   263 
   264     public uint CoreId {
   265       get { return coreId; }
   266     }
   267 
   268     public uint ThreadId {
   269       get { return threadId; }
   270     }
   271 
   272     public uint[,] Data {
   273       get { return cpuidData; }
   274     }
   275 
   276     public uint[,] ExtData {
   277       get { return cpuidExtData; }
   278     }
   279   }
   280 }