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