| moel@90 |      1 | /*
 | 
| moel@90 |      2 |   
 | 
| moel@90 |      3 |   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 | 
| moel@90 |      4 | 
 | 
| moel@90 |      5 |   The contents of this file are subject to the Mozilla Public License Version
 | 
| moel@90 |      6 |   1.1 (the "License"); you may not use this file except in compliance with
 | 
| moel@90 |      7 |   the License. You may obtain a copy of the License at
 | 
| moel@90 |      8 |  
 | 
| moel@90 |      9 |   http://www.mozilla.org/MPL/
 | 
| moel@90 |     10 | 
 | 
| moel@90 |     11 |   Software distributed under the License is distributed on an "AS IS" basis,
 | 
| moel@90 |     12 |   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 | 
| moel@90 |     13 |   for the specific language governing rights and limitations under the License.
 | 
| moel@90 |     14 | 
 | 
| moel@90 |     15 |   The Original Code is the Open Hardware Monitor code.
 | 
| moel@90 |     16 | 
 | 
| moel@90 |     17 |   The Initial Developer of the Original Code is 
 | 
| moel@90 |     18 |   Michael Möller <m.moeller@gmx.ch>.
 | 
| moel@90 |     19 |   Portions created by the Initial Developer are Copyright (C) 2009-2010
 | 
| moel@90 |     20 |   the Initial Developer. All Rights Reserved.
 | 
| moel@90 |     21 | 
 | 
| moel@90 |     22 |   Contributor(s):
 | 
| moel@90 |     23 | 
 | 
| moel@90 |     24 |   Alternatively, the contents of this file may be used under the terms of
 | 
| moel@90 |     25 |   either the GNU General Public License Version 2 or later (the "GPL"), or
 | 
| moel@90 |     26 |   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 | 
| moel@90 |     27 |   in which case the provisions of the GPL or the LGPL are applicable instead
 | 
| moel@90 |     28 |   of those above. If you wish to allow use of your version of this file only
 | 
| moel@90 |     29 |   under the terms of either the GPL or the LGPL, and not to allow others to
 | 
| moel@90 |     30 |   use your version of this file under the terms of the MPL, indicate your
 | 
| moel@90 |     31 |   decision by deleting the provisions above and replace them with the notice
 | 
| moel@90 |     32 |   and other provisions required by the GPL or the LGPL. If you do not delete
 | 
| moel@90 |     33 |   the provisions above, a recipient may use your version of this file under
 | 
| moel@90 |     34 |   the terms of any one of the MPL, the GPL or the LGPL.
 | 
| moel@90 |     35 |  
 | 
| moel@90 |     36 | */
 | 
| moel@90 |     37 | 
 | 
| moel@90 |     38 | using System;
 | 
| moel@90 |     39 | using System.Collections.Generic;
 | 
| moel@90 |     40 | using System.Text;
 | 
| moel@90 |     41 | 
 | 
| moel@90 |     42 | namespace OpenHardwareMonitor.Hardware.CPU {
 | 
| moel@90 |     43 |   
 | 
| moel@90 |     44 |   public enum Vendor {
 | 
| moel@90 |     45 |     Unknown,
 | 
| moel@90 |     46 |     Intel,
 | 
| moel@90 |     47 |     AMD,
 | 
| moel@90 |     48 |   }
 | 
| moel@90 |     49 |   
 | 
| moel@90 |     50 |   public class CPUID {
 | 
| moel@90 |     51 | 
 | 
| moel@90 |     52 |     private int thread;
 | 
| moel@90 |     53 | 
 | 
| moel@90 |     54 |     private uint maxCpuid = 0;
 | 
| moel@90 |     55 |     private uint maxCpuidExt = 0;
 | 
| moel@90 |     56 | 
 | 
| moel@90 |     57 |     private Vendor vendor;
 | 
| moel@90 |     58 | 
 | 
| moel@90 |     59 |     private string cpuBrandString;
 | 
| moel@90 |     60 |     private string name;
 | 
| moel@90 |     61 | 
 | 
| moel@90 |     62 |     private uint[,] cpuidData;
 | 
| moel@90 |     63 |     private uint[,] cpuidExtData;
 | 
| moel@90 |     64 | 
 | 
| moel@90 |     65 |     private uint family;
 | 
| moel@90 |     66 |     private uint model;
 | 
| moel@90 |     67 |     private uint stepping;
 | 
| moel@90 |     68 | 
 | 
| moel@90 |     69 |     private uint apicId;
 | 
| moel@90 |     70 | 
 | 
| moel@90 |     71 |     private uint threadMaskWith;
 | 
| moel@90 |     72 |     private uint coreMaskWith;
 | 
| moel@90 |     73 | 
 | 
| moel@90 |     74 |     private uint processorId;
 | 
| moel@90 |     75 |     private uint coreId;
 | 
| moel@90 |     76 |     private uint threadId;
 | 
| moel@90 |     77 | 
 | 
| moel@90 |     78 |     public static uint CPUID_0 = 0;
 | 
| moel@90 |     79 |     public static uint CPUID_EXT = 0x80000000;
 | 
| moel@90 |     80 | 
 | 
| moel@90 |     81 |     private void AppendRegister(StringBuilder b, uint value) {
 | 
| moel@90 |     82 |       b.Append((char)((value) & 0xff));
 | 
| moel@90 |     83 |       b.Append((char)((value >> 8) & 0xff));
 | 
| moel@90 |     84 |       b.Append((char)((value >> 16) & 0xff));
 | 
| moel@90 |     85 |       b.Append((char)((value >> 24) & 0xff));
 | 
| moel@90 |     86 |     }
 | 
| moel@90 |     87 | 
 | 
| moel@90 |     88 |     public CPUID(int thread) {
 | 
| moel@90 |     89 |       this.thread = thread;
 | 
| moel@90 |     90 | 
 | 
| moel@90 |     91 |       uint eax, ebx, ecx, edx;
 | 
| moel@90 |     92 | 
 | 
| moel@90 |     93 |       UIntPtr mask = (UIntPtr)(1L << thread);
 | 
| moel@90 |     94 | 
 | 
| moel@90 |     95 |       if (WinRing0.CpuidTx(CPUID_0, 0,
 | 
| moel@90 |     96 |           out eax, out ebx, out ecx, out edx, mask)) {
 | 
| moel@90 |     97 |         maxCpuid = eax;
 | 
| moel@90 |     98 |         StringBuilder vendorBuilder = new StringBuilder();
 | 
| moel@90 |     99 |         AppendRegister(vendorBuilder, ebx);
 | 
| moel@90 |    100 |         AppendRegister(vendorBuilder, edx);
 | 
| moel@90 |    101 |         AppendRegister(vendorBuilder, ecx);
 | 
| moel@90 |    102 |         string cpuVendor = vendorBuilder.ToString();
 | 
| moel@90 |    103 |         switch (cpuVendor) {
 | 
| moel@90 |    104 |           case "GenuineIntel":
 | 
| moel@90 |    105 |             vendor = Vendor.Intel;
 | 
| moel@90 |    106 |             break;
 | 
| moel@90 |    107 |           case "AuthenticAMD":
 | 
| moel@90 |    108 |             vendor = Vendor.AMD;
 | 
| moel@90 |    109 |             break;
 | 
| moel@90 |    110 |           default:
 | 
| moel@90 |    111 |             vendor = Vendor.Unknown;
 | 
| moel@90 |    112 |             break;
 | 
| moel@90 |    113 |         }
 | 
| moel@90 |    114 |         eax = ebx = ecx = edx = 0;
 | 
| moel@90 |    115 |         if (WinRing0.CpuidTx(CPUID_EXT, 0,
 | 
| moel@90 |    116 |           out eax, out ebx, out ecx, out edx, mask))
 | 
| moel@90 |    117 |           maxCpuidExt = eax - CPUID_EXT;
 | 
| moel@90 |    118 |       } else {
 | 
| moel@90 |    119 |         throw new ArgumentException();
 | 
| moel@90 |    120 |       }
 | 
| moel@90 |    121 | 
 | 
| moel@90 |    122 |       if (maxCpuid == 0 || maxCpuidExt == 0)
 | 
| moel@90 |    123 |         return;
 | 
| moel@90 |    124 | 
 | 
| moel@90 |    125 |       cpuidData = new uint[maxCpuid + 1, 4];
 | 
| moel@90 |    126 |       for (uint i = 0; i < (maxCpuid + 1); i++)
 | 
| moel@90 |    127 |         WinRing0.CpuidTx(CPUID_0 + i, 0, 
 | 
| moel@90 |    128 |           out cpuidData[i, 0], out cpuidData[i, 1],
 | 
| moel@90 |    129 |           out cpuidData[i, 2], out cpuidData[i, 3], mask);
 | 
| moel@90 |    130 | 
 | 
| moel@95 |    131 |       cpuidExtData = new uint[maxCpuidExt + 1, 4];
 | 
| moel@95 |    132 |       for (uint i = 0; i < (maxCpuidExt + 1); i++)
 | 
| moel@90 |    133 |         WinRing0.CpuidTx(CPUID_EXT + i, 0, 
 | 
| moel@90 |    134 |           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
 | 
| moel@90 |    135 |           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
 | 
| moel@90 |    136 | 
 | 
| moel@90 |    137 |       StringBuilder nameBuilder = new StringBuilder();
 | 
| moel@90 |    138 |       for (uint i = 2; i <= 4; i++) {
 | 
| moel@90 |    139 |         if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
 | 
| moel@90 |    140 |           out eax, out ebx, out ecx, out edx, mask)) 
 | 
| moel@90 |    141 |         {
 | 
| moel@90 |    142 |           AppendRegister(nameBuilder, eax);
 | 
| moel@90 |    143 |           AppendRegister(nameBuilder, ebx);
 | 
| moel@90 |    144 |           AppendRegister(nameBuilder, ecx);
 | 
| moel@90 |    145 |           AppendRegister(nameBuilder, edx);
 | 
| moel@90 |    146 |         }
 | 
| moel@90 |    147 |       }
 | 
| moel@90 |    148 |       nameBuilder.Replace('\0', ' ');
 | 
| moel@90 |    149 |       cpuBrandString = nameBuilder.ToString().Trim();
 | 
| moel@90 |    150 |       nameBuilder.Replace("(R)", " ");
 | 
| moel@90 |    151 |       nameBuilder.Replace("(TM)", " ");
 | 
| moel@90 |    152 |       nameBuilder.Replace("(tm)", " ");
 | 
| moel@90 |    153 |       nameBuilder.Replace("CPU", "");
 | 
| moel@90 |    154 |       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
 | 
| moel@90 |    155 |       name = nameBuilder.ToString();
 | 
| moel@90 |    156 |       if (name.Contains("@"))
 | 
| moel@90 |    157 |         name = name.Remove(name.LastIndexOf('@'));
 | 
| moel@95 |    158 |       name = name.Trim();      
 | 
| moel@90 |    159 | 
 | 
| moel@90 |    160 |       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
 | 
| moel@90 |    161 |         ((cpuidData[1, 0] & 0x0F00) >> 8);
 | 
| moel@90 |    162 |       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
 | 
| moel@90 |    163 |         ((cpuidData[1, 0] & 0xF0) >> 4);
 | 
| moel@90 |    164 |       this.stepping = (cpuidData[1, 0] & 0x0F);
 | 
| moel@90 |    165 | 
 | 
| moel@90 |    166 |       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
 | 
| moel@90 |    167 | 
 | 
| moel@90 |    168 |       switch (vendor) {
 | 
| moel@90 |    169 |         case Vendor.Intel:
 | 
| moel@90 |    170 |           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
 | 
| moel@95 |    171 |           uint maxCoreIdPerPackage;
 | 
| moel@95 |    172 |           if (maxCpuid >= 4)
 | 
| moel@95 |    173 |             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
 | 
| moel@95 |    174 |           else
 | 
| moel@95 |    175 |             maxCoreIdPerPackage = 1;
 | 
| moel@90 |    176 |           threadMaskWith = (uint)Math.Ceiling(Math.Log(
 | 
| moel@90 |    177 |             maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage, 2));
 | 
| moel@90 |    178 |           coreMaskWith = (uint)Math.Ceiling(Math.Log(maxCoreIdPerPackage, 2));
 | 
| moel@90 |    179 |           break;
 | 
| moel@90 |    180 |         case Vendor.AMD:
 | 
| moel@95 |    181 |           uint corePerPackage;
 | 
| moel@95 |    182 |           if (maxCpuidExt >= 8)
 | 
| moel@95 |    183 |             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
 | 
| moel@95 |    184 |           else
 | 
| moel@95 |    185 |             corePerPackage = 1;
 | 
| moel@90 |    186 |           threadMaskWith = 0;
 | 
| moel@90 |    187 |           coreMaskWith = (uint)Math.Ceiling(Math.Log(corePerPackage, 2));
 | 
| moel@90 |    188 |           break;
 | 
| moel@90 |    189 |         default:
 | 
| moel@90 |    190 |           threadMaskWith = 0;
 | 
| moel@90 |    191 |           coreMaskWith = 0;
 | 
| moel@90 |    192 |           break;
 | 
| moel@90 |    193 |       }
 | 
| moel@90 |    194 | 
 | 
| moel@90 |    195 |       processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
 | 
| moel@95 |    196 |       coreId = (uint)((apicId >> (int)(threadMaskWith)) 
 | 
| moel@102 |    197 |         - (processorId << (int)(coreMaskWith)));
 | 
| moel@95 |    198 |       threadId = apicId
 | 
| moel@95 |    199 |         - (processorId << (int)(coreMaskWith + threadMaskWith))
 | 
| moel@95 |    200 |         - (coreId << (int)(threadMaskWith)); 
 | 
| moel@90 |    201 |     }
 | 
| moel@90 |    202 | 
 | 
| moel@90 |    203 |     public string Name {
 | 
| moel@90 |    204 |       get { return name; }
 | 
| moel@90 |    205 |     }
 | 
| moel@90 |    206 | 
 | 
| moel@90 |    207 |     public string BrandString {
 | 
| moel@90 |    208 |       get { return cpuBrandString; }
 | 
| moel@90 |    209 |     }
 | 
| moel@90 |    210 | 
 | 
| moel@90 |    211 |     public int Thread {
 | 
| moel@90 |    212 |       get { return thread; }
 | 
| moel@90 |    213 |     }
 | 
| moel@90 |    214 | 
 | 
| moel@90 |    215 |     public uint MaxCPUID {
 | 
| moel@90 |    216 |       get { return maxCpuid; }
 | 
| moel@90 |    217 |     }
 | 
| moel@90 |    218 | 
 | 
| moel@90 |    219 |     public uint MaxCpuidExt {
 | 
| moel@90 |    220 |       get { return maxCpuidExt; }
 | 
| moel@90 |    221 |     }
 | 
| moel@90 |    222 | 
 | 
| moel@90 |    223 |     public Vendor Vendor {
 | 
| moel@90 |    224 |       get { return vendor; }
 | 
| moel@90 |    225 |     }
 | 
| moel@90 |    226 | 
 | 
| moel@90 |    227 |     public uint Family {
 | 
| moel@90 |    228 |       get { return family; }
 | 
| moel@90 |    229 |     }
 | 
| moel@90 |    230 | 
 | 
| moel@90 |    231 |     public uint Model {
 | 
| moel@90 |    232 |       get { return model; }
 | 
| moel@90 |    233 |     }
 | 
| moel@90 |    234 | 
 | 
| moel@90 |    235 |     public uint Stepping {
 | 
| moel@90 |    236 |       get { return stepping; }
 | 
| moel@90 |    237 |     }
 | 
| moel@90 |    238 | 
 | 
| moel@90 |    239 |     public uint ApicId {
 | 
| moel@90 |    240 |       get { return apicId; }
 | 
| moel@90 |    241 |     }
 | 
| moel@90 |    242 | 
 | 
| moel@90 |    243 |     public uint ProcessorId {
 | 
| moel@90 |    244 |       get { return processorId; }
 | 
| moel@90 |    245 |     }
 | 
| moel@90 |    246 | 
 | 
| moel@90 |    247 |     public uint CoreId {
 | 
| moel@90 |    248 |       get { return coreId; }
 | 
| moel@90 |    249 |     }
 | 
| moel@90 |    250 | 
 | 
| moel@90 |    251 |     public uint ThreadId {
 | 
| moel@90 |    252 |       get { return threadId; }
 | 
| moel@90 |    253 |     }
 | 
| moel@90 |    254 | 
 | 
| moel@90 |    255 |     public uint[,] Data {
 | 
| moel@90 |    256 |       get { return cpuidData; }
 | 
| moel@90 |    257 |     }
 | 
| moel@90 |    258 | 
 | 
| moel@90 |    259 |     public uint[,] ExtData {
 | 
| moel@90 |    260 |       get { return cpuidExtData; }
 | 
| moel@90 |    261 |     }
 | 
| moel@90 |    262 |   }
 | 
| moel@90 |    263 | }
 |