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