Hardware/CPU/CPUID.cs
author moel.mich
Mon, 28 May 2012 10:39:30 +0000
changeset 350 6de77245e32b
parent 329 756af5ee409e
child 427 39ed1a16c32a
permissions -rw-r--r--
Added support for Intel Ivy Bridge based CPUs. Added code to prevent displaying wrong information on unknown (future) Intel CPUs.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2010 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Text;
    13 
    14 namespace OpenHardwareMonitor.Hardware.CPU {
    15 
    16   internal enum Vendor {
    17     Unknown,
    18     Intel,
    19     AMD,
    20   }
    21 
    22   internal class CPUID {
    23 
    24     private readonly int thread;
    25 
    26     private readonly Vendor vendor = Vendor.Unknown;
    27 
    28     private readonly string cpuBrandString = "";
    29     private readonly string name = "";
    30 
    31     private readonly uint[,] cpuidData = new uint[0, 0];
    32     private readonly uint[,] cpuidExtData = new uint[0, 0];
    33 
    34     private readonly uint family;
    35     private readonly uint model;
    36     private readonly uint stepping;
    37 
    38     private readonly uint apicId;
    39 
    40     private readonly uint threadMaskWith;
    41     private readonly uint coreMaskWith;
    42 
    43     private readonly uint processorId;
    44     private readonly uint coreId;
    45     private readonly uint threadId;
    46 
    47     public const uint CPUID_0 = 0;
    48     public const uint CPUID_EXT = 0x80000000;
    49 
    50     private static void AppendRegister(StringBuilder b, uint value) {
    51       b.Append((char)((value) & 0xff));
    52       b.Append((char)((value >> 8) & 0xff));
    53       b.Append((char)((value >> 16) & 0xff));
    54       b.Append((char)((value >> 24) & 0xff));
    55     }
    56 
    57     private static uint NextLog2(long x) {
    58       if (x <= 0)
    59         return 0;
    60 
    61       x--;
    62       uint count = 0;
    63       while (x > 0) {
    64         x >>= 1;
    65         count++;
    66       }
    67 
    68       return count;
    69     }
    70 
    71     public CPUID(int thread) {
    72       this.thread = thread;
    73 
    74       uint maxCpuid = 0;
    75       uint maxCpuidExt = 0;
    76 
    77       uint eax, ebx, ecx, edx;
    78 
    79       if (thread >= 32)
    80         throw new ArgumentOutOfRangeException("thread");
    81       ulong mask = 1UL << thread;
    82 
    83       if (Opcode.CpuidTx(CPUID_0, 0,
    84           out eax, out ebx, out ecx, out edx, mask)) {
    85         if (eax > 0)
    86           maxCpuid = eax;
    87         else
    88           return;
    89 
    90         StringBuilder vendorBuilder = new StringBuilder();
    91         AppendRegister(vendorBuilder, ebx);
    92         AppendRegister(vendorBuilder, edx);
    93         AppendRegister(vendorBuilder, ecx);
    94         string cpuVendor = vendorBuilder.ToString();
    95         switch (cpuVendor) {
    96           case "GenuineIntel":
    97             vendor = Vendor.Intel;
    98             break;
    99           case "AuthenticAMD":
   100             vendor = Vendor.AMD;
   101             break;
   102           default:
   103             vendor = Vendor.Unknown;
   104             break;
   105         }
   106         eax = ebx = ecx = edx = 0;
   107         if (Opcode.CpuidTx(CPUID_EXT, 0,
   108           out eax, out ebx, out ecx, out edx, mask)) {
   109           if (eax > CPUID_EXT)
   110             maxCpuidExt = eax - CPUID_EXT;
   111           else
   112             return;
   113         } else {
   114           throw new ArgumentOutOfRangeException("thread");
   115         }
   116       } else {
   117         throw new ArgumentOutOfRangeException("thread");
   118       }
   119 
   120       maxCpuid = Math.Min(maxCpuid, 1024);
   121       maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
   122 
   123       cpuidData = new uint[maxCpuid + 1, 4];
   124       for (uint i = 0; i < (maxCpuid + 1); i++)
   125         Opcode.CpuidTx(CPUID_0 + i, 0, 
   126           out cpuidData[i, 0], out cpuidData[i, 1],
   127           out cpuidData[i, 2], out cpuidData[i, 3], mask);
   128 
   129       cpuidExtData = new uint[maxCpuidExt + 1, 4];
   130       for (uint i = 0; i < (maxCpuidExt + 1); i++)
   131         Opcode.CpuidTx(CPUID_EXT + i, 0, 
   132           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
   133           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
   134 
   135       StringBuilder nameBuilder = new StringBuilder();
   136       for (uint i = 2; i <= 4; i++) {
   137         if (Opcode.CpuidTx(CPUID_EXT + i, 0, 
   138           out eax, out ebx, out ecx, out edx, mask)) 
   139         {
   140           AppendRegister(nameBuilder, eax);
   141           AppendRegister(nameBuilder, ebx);
   142           AppendRegister(nameBuilder, ecx);
   143           AppendRegister(nameBuilder, edx);
   144         }
   145       }
   146       nameBuilder.Replace('\0', ' ');
   147       cpuBrandString = nameBuilder.ToString().Trim();
   148       nameBuilder.Replace("(R)", " ");
   149       nameBuilder.Replace("(TM)", " ");
   150       nameBuilder.Replace("(tm)", "");
   151       nameBuilder.Replace("CPU", "");
   152       nameBuilder.Replace("Quad-Core Processor", "");
   153       nameBuilder.Replace("Six-Core Processor", "");
   154       nameBuilder.Replace("Eight-Core Processor", "");
   155       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
   156       name = nameBuilder.ToString();
   157       if (name.Contains("@"))
   158         name = name.Remove(name.LastIndexOf('@'));
   159       name = name.Trim();      
   160 
   161       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
   162         ((cpuidData[1, 0] & 0x0F00) >> 8);
   163       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
   164         ((cpuidData[1, 0] & 0xF0) >> 4);
   165       this.stepping = (cpuidData[1, 0] & 0x0F);
   166 
   167       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
   168 
   169       switch (vendor) {
   170         case Vendor.Intel:
   171           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
   172           uint maxCoreIdPerPackage;
   173           if (maxCpuid >= 4)
   174             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
   175           else
   176             maxCoreIdPerPackage = 1;
   177           threadMaskWith = 
   178             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
   179           coreMaskWith = NextLog2(maxCoreIdPerPackage);
   180           break;
   181         case Vendor.AMD:
   182           uint corePerPackage;
   183           if (maxCpuidExt >= 8)
   184             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
   185           else
   186             corePerPackage = 1;
   187           threadMaskWith = 0;
   188           coreMaskWith = NextLog2(corePerPackage);
   189           break;
   190         default:
   191           threadMaskWith = 0;
   192           coreMaskWith = 0;
   193           break;
   194       }
   195 
   196       processorId = (apicId >> (int)(coreMaskWith + threadMaskWith));
   197       coreId = ((apicId >> (int)(threadMaskWith)) 
   198         - (processorId << (int)(coreMaskWith)));
   199       threadId = apicId
   200         - (processorId << (int)(coreMaskWith + threadMaskWith))
   201         - (coreId << (int)(threadMaskWith)); 
   202     }
   203 
   204     public string Name {
   205       get { return name; }
   206     }
   207 
   208     public string BrandString {
   209       get { return cpuBrandString; }
   210     }
   211 
   212     public int Thread {
   213       get { return thread; }
   214     }
   215 
   216     public Vendor Vendor {
   217       get { return vendor; }
   218     }
   219 
   220     public uint Family {
   221       get { return family; }
   222     }
   223 
   224     public uint Model {
   225       get { return model; }
   226     }
   227 
   228     public uint Stepping {
   229       get { return stepping; }
   230     }
   231 
   232     public uint ApicId {
   233       get { return apicId; }
   234     }
   235 
   236     public uint ProcessorId {
   237       get { return processorId; }
   238     }
   239 
   240     public uint CoreId {
   241       get { return coreId; }
   242     }
   243 
   244     public uint ThreadId {
   245       get { return threadId; }
   246     }
   247 
   248     public uint[,] Data {
   249       get { return cpuidData; }
   250     }
   251 
   252     public uint[,] ExtData {
   253       get { return cpuidExtData; }
   254     }
   255   }
   256 }