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