Hardware/CPU/IntelCPU.cs
author moel.mich
Sun, 24 Jul 2011 22:16:28 +0000
changeset 315 158ec57434e8
parent 306 e9127c00ada1
child 317 1ccf99e620a9
permissions -rw-r--r--
Fixed the Intel CPU package temperature sensor MSR.
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@264
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@219
    39
using System.Globalization;
moel@219
    40
using System.Text;
moel@1
    41
moel@1
    42
namespace OpenHardwareMonitor.Hardware.CPU {
moel@191
    43
  internal sealed class IntelCPU : GenericCPU {
moel@46
    44
moel@219
    45
    private enum Microarchitecture {
moel@219
    46
      Unknown,
moel@264
    47
      NetBurst,
moel@219
    48
      Core,
moel@219
    49
      Atom,
moel@249
    50
      Nehalem,
moel@249
    51
      SandyBridge
moel@219
    52
    }
moel@219
    53
moel@195
    54
    private readonly Sensor[] coreTemperatures;
moel@306
    55
    private readonly Sensor packageTemperature;
moel@195
    56
    private readonly Sensor[] coreClocks;
moel@195
    57
    private readonly Sensor busClock;
moel@63
    58
moel@219
    59
    private readonly Microarchitecture microarchitecture;
moel@219
    60
    private readonly double timeStampCounterMultiplier;
moel@79
    61
moel@1
    62
    private const uint IA32_THERM_STATUS_MSR = 0x019C;
moel@4
    63
    private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
moel@44
    64
    private const uint IA32_PERF_STATUS = 0x0198;
moel@46
    65
    private const uint MSR_PLATFORM_INFO = 0xCE;
moel@306
    66
    private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
moel@1
    67
moel@69
    68
    private float[] Floats(float f) {
moel@69
    69
      float[] result = new float[coreCount];
moel@69
    70
      for (int i = 0; i < coreCount; i++)
moel@69
    71
        result[i] = f;
moel@69
    72
      return result;
moel@69
    73
    }
moel@69
    74
moel@249
    75
    private float[] GetTjMaxFromMSR() {
moel@249
    76
      uint eax, edx;
moel@249
    77
      float[] result = new float[coreCount];
moel@249
    78
      for (int i = 0; i < coreCount; i++) {
moel@249
    79
        if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
moel@249
    80
          out edx, 1UL << cpuid[i][0].Thread)) {
moel@249
    81
          result[i] = (eax >> 16) & 0xFF;
moel@249
    82
        } else {
moel@249
    83
          result[i] = 100;
moel@249
    84
        }
moel@249
    85
      }
moel@249
    86
      return result;
moel@249
    87
    }
moel@249
    88
moel@191
    89
    public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
moel@191
    90
      : base(processorIndex, cpuid, settings) 
moel@191
    91
    {
moel@219
    92
      // set tjMax
moel@69
    93
      float[] tjMax;
moel@49
    94
      switch (family) {
moel@49
    95
        case 0x06: {
moel@49
    96
            switch (model) {
moel@219
    97
              case 0x0F: // Intel Core 2 (65nm)
moel@219
    98
                microarchitecture = Microarchitecture.Core;
moel@49
    99
                switch (stepping) {
moel@49
   100
                  case 0x06: // B2
moel@49
   101
                    switch (coreCount) {
moel@49
   102
                      case 2:
moel@69
   103
                        tjMax = Floats(80 + 10); break;
moel@49
   104
                      case 4:
moel@69
   105
                        tjMax = Floats(90 + 10); break;
moel@49
   106
                      default:
moel@69
   107
                        tjMax = Floats(85 + 10); break;
moel@49
   108
                    }
moel@69
   109
                    tjMax = Floats(80 + 10); break;
moel@49
   110
                  case 0x0B: // G0
moel@69
   111
                    tjMax = Floats(90 + 10); break;
moel@49
   112
                  case 0x0D: // M0
moel@69
   113
                    tjMax = Floats(85 + 10); break;
moel@49
   114
                  default:
moel@69
   115
                    tjMax = Floats(85 + 10); break;
moel@49
   116
                } break;
moel@219
   117
              case 0x17: // Intel Core 2 (45nm)
moel@219
   118
                microarchitecture = Microarchitecture.Core;
moel@69
   119
                tjMax = Floats(100); break;
moel@114
   120
              case 0x1C: // Intel Atom (45nm)
moel@219
   121
                microarchitecture = Microarchitecture.Atom;
moel@114
   122
                switch (stepping) {
moel@114
   123
                  case 0x02: // C0
moel@114
   124
                    tjMax = Floats(90); break;
moel@114
   125
                  case 0x0A: // A0, B0
moel@114
   126
                    tjMax = Floats(100); break;
moel@114
   127
                  default:
moel@114
   128
                    tjMax = Floats(90); break;
moel@191
   129
                } break;
moel@49
   130
              case 0x1A: // Intel Core i7 LGA1366 (45nm)
moel@49
   131
              case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
moel@249
   132
              case 0x1F: // Intel Core i5, i7 
moel@49
   133
              case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
moel@91
   134
              case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
moel@249
   135
              case 0x2E: // Intel Xeon Processor 7500 series
moel@219
   136
                microarchitecture = Microarchitecture.Nehalem;
moel@249
   137
                tjMax = GetTjMaxFromMSR();
moel@249
   138
                break;
moel@249
   139
              case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
moel@249
   140
              case 0x2D: // Next Generation Intel Xeon Processor
moel@249
   141
                microarchitecture = Microarchitecture.SandyBridge;
moel@249
   142
                tjMax = GetTjMaxFromMSR();
moel@49
   143
                break;
moel@49
   144
              default:
moel@219
   145
                microarchitecture = Microarchitecture.Unknown;
moel@219
   146
                tjMax = Floats(100); 
moel@219
   147
                break;
moel@49
   148
            }
moel@49
   149
          } break;
moel@264
   150
        case 0x0F: {
moel@264
   151
            switch (model) {
moel@264
   152
              case 0x00: // Pentium 4 (180nm)
moel@264
   153
              case 0x01: // Pentium 4 (130nm)
moel@264
   154
              case 0x02: // Pentium 4 (130nm)
moel@264
   155
              case 0x03: // Pentium 4, Celeron D (90nm)
moel@264
   156
              case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
moel@264
   157
              case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
moel@264
   158
                microarchitecture = Microarchitecture.NetBurst;
moel@264
   159
                tjMax = Floats(100); 
moel@264
   160
                break;
moel@264
   161
              default:
moel@264
   162
                microarchitecture = Microarchitecture.Unknown;
moel@264
   163
                tjMax = Floats(100);
moel@264
   164
                break;
moel@264
   165
            }
moel@264
   166
          } break;
moel@219
   167
        default:
moel@219
   168
          microarchitecture = Microarchitecture.Unknown;
moel@219
   169
          tjMax = Floats(100); 
moel@219
   170
          break;
moel@219
   171
      }
moel@219
   172
moel@219
   173
      // set timeStampCounterMultiplier
moel@219
   174
      switch (microarchitecture) {
moel@264
   175
        case Microarchitecture.NetBurst:
moel@219
   176
        case Microarchitecture.Atom:
moel@219
   177
        case Microarchitecture.Core: {
moel@219
   178
            uint eax, edx;
moel@236
   179
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@219
   180
              timeStampCounterMultiplier = 
moel@219
   181
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@219
   182
            }
moel@219
   183
          } break;
moel@249
   184
        case Microarchitecture.Nehalem: 
moel@249
   185
        case Microarchitecture.SandyBridge: {
moel@219
   186
            uint eax, edx;
moel@236
   187
            if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
moel@219
   188
              timeStampCounterMultiplier = (eax >> 8) & 0xff;
moel@219
   189
            }
moel@219
   190
          } break;
moel@264
   191
        default: {
moel@264
   192
            timeStampCounterMultiplier = 1;
moel@264
   193
            uint eax, edx;
moel@264
   194
            if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
moel@264
   195
              timeStampCounterMultiplier =
moel@264
   196
                ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
moel@264
   197
            }
moel@264
   198
          } break;
moel@49
   199
      }
moel@1
   200
moel@306
   201
      // check if processor supports a digital thermal sensor at core level
moel@191
   202
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@306
   203
        (cpuid[0][0].Data[6, 0] & 1) != 0) 
moel@306
   204
      {
moel@44
   205
        coreTemperatures = new Sensor[coreCount];
moel@44
   206
        for (int i = 0; i < coreTemperatures.Length; i++) {
moel@134
   207
          coreTemperatures[i] = new Sensor(CoreString(i), i,
moel@195
   208
            SensorType.Temperature, this, new [] { 
moel@63
   209
              new ParameterDescription(
moel@306
   210
                "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
moel@69
   211
                "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
moel@122
   212
              new ParameterDescription("TSlope [°C]", 
moel@122
   213
                "Temperature slope of the digital thermal sensor.\n" + 
moel@165
   214
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@155
   215
          ActivateSensor(coreTemperatures[i]);
moel@44
   216
        }
moel@44
   217
      } else {
moel@44
   218
        coreTemperatures = new Sensor[0];
moel@1
   219
      }
moel@49
   220
moel@306
   221
      // check if processor supports a digital thermal sensor at package level
moel@306
   222
      if (cpuid[0][0].Data.GetLength(0) > 6 &&
moel@306
   223
        (cpuid[0][0].Data[6, 0] & 0x40) != 0) 
moel@306
   224
      {
moel@306
   225
          packageTemperature = new Sensor("CPU Package", 
moel@306
   226
            coreTemperatures.Length, SensorType.Temperature, this, new[] { 
moel@306
   227
              new ParameterDescription(
moel@306
   228
                "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
moel@306
   229
                "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
moel@306
   230
              new ParameterDescription("TSlope [°C]", 
moel@306
   231
                "Temperature slope of the digital thermal sensor.\n" + 
moel@306
   232
                "Temperature = TjMax - TSlope * Value.", 1)}, settings);
moel@306
   233
        ActivateSensor(packageTemperature);
moel@306
   234
      } 
moel@306
   235
moel@191
   236
      busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
moel@44
   237
      coreClocks = new Sensor[coreCount];
moel@44
   238
      for (int i = 0; i < coreClocks.Length; i++) {
moel@49
   239
        coreClocks[i] =
moel@165
   240
          new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
moel@201
   241
        if (HasTimeStampCounter)
moel@79
   242
          ActivateSensor(coreClocks[i]);
moel@44
   243
      }
moel@191
   244
moel@191
   245
      Update();
moel@1
   246
    }
moel@1
   247
moel@191
   248
    protected override uint[] GetMSRs() {
moel@195
   249
      return new [] {
moel@191
   250
        MSR_PLATFORM_INFO,
moel@191
   251
        IA32_PERF_STATUS ,
moel@191
   252
        IA32_THERM_STATUS_MSR,
moel@306
   253
        IA32_TEMPERATURE_TARGET,
moel@306
   254
        IA32_PACKAGE_THERM_STATUS
moel@191
   255
      };
moel@1
   256
    }
moel@1
   257
moel@219
   258
    public override string GetReport() {
moel@219
   259
      StringBuilder r = new StringBuilder();
moel@219
   260
      r.Append(base.GetReport());
moel@219
   261
moel@264
   262
      r.Append("Microarchitecture: ");
moel@264
   263
      r.AppendLine(microarchitecture.ToString());
moel@219
   264
      r.Append("Time Stamp Counter Multiplier: ");
moel@219
   265
      r.AppendLine(timeStampCounterMultiplier.ToString(
moel@219
   266
        CultureInfo.InvariantCulture));
moel@219
   267
      r.AppendLine();
moel@219
   268
moel@219
   269
      return r.ToString();
moel@219
   270
    }
moel@219
   271
moel@191
   272
    public override void Update() {
moel@191
   273
      base.Update();
moel@1
   274
moel@1
   275
      for (int i = 0; i < coreTemperatures.Length; i++) {
moel@46
   276
        uint eax, edx;
moel@236
   277
        if (Ring0.RdmsrTx(
moel@191
   278
          IA32_THERM_STATUS_MSR, out eax, out edx,
moel@238
   279
            1UL << cpuid[i][0].Thread)) {
moel@1
   280
          // if reading is valid
moel@1
   281
          if ((eax & 0x80000000) != 0) {
moel@1
   282
            // get the dist from tjMax from bits 22:16
moel@63
   283
            float deltaT = ((eax & 0x007F0000) >> 16);
moel@63
   284
            float tjMax = coreTemperatures[i].Parameters[0].Value;
moel@63
   285
            float tSlope = coreTemperatures[i].Parameters[1].Value;
moel@63
   286
            coreTemperatures[i].Value = tjMax - tSlope * deltaT;
moel@24
   287
          } else {
moel@155
   288
            coreTemperatures[i].Value = null;
moel@1
   289
          }
moel@79
   290
        }
moel@24
   291
      }
moel@24
   292
moel@306
   293
      if (packageTemperature != null) {
moel@306
   294
        uint eax, edx;
moel@306
   295
        if (Ring0.RdmsrTx(
moel@315
   296
          IA32_PACKAGE_THERM_STATUS, out eax, out edx,
moel@306
   297
            1UL << cpuid[0][0].Thread)) {
moel@306
   298
          // get the dist from tjMax from bits 22:16
moel@306
   299
          float deltaT = ((eax & 0x007F0000) >> 16);
moel@306
   300
          float tjMax = packageTemperature.Parameters[0].Value;
moel@306
   301
          float tSlope = packageTemperature.Parameters[1].Value;
moel@306
   302
          packageTemperature.Value = tjMax - tSlope * deltaT;
moel@306
   303
        } else {
moel@306
   304
          packageTemperature.Value = null;
moel@306
   305
        }
moel@306
   306
      }
moel@306
   307
moel@201
   308
      if (HasTimeStampCounter) {
moel@191
   309
        double newBusClock = 0;
moel@191
   310
        uint eax, edx;
moel@191
   311
        for (int i = 0; i < coreClocks.Length; i++) {
moel@191
   312
          System.Threading.Thread.Sleep(1);
moel@236
   313
          if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
moel@238
   314
            1UL << cpuid[i][0].Thread)) 
moel@219
   315
          {
moel@219
   316
            newBusClock = 
moel@219
   317
              TimeStampCounterFrequency / timeStampCounterMultiplier;
moel@250
   318
            switch (microarchitecture) {
moel@250
   319
              case Microarchitecture.Nehalem: {
moel@250
   320
                  uint multiplier = eax & 0xff;
moel@250
   321
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   322
                } break;
moel@250
   323
              case Microarchitecture.SandyBridge: {
moel@250
   324
                  uint multiplier = (eax >> 8) & 0xff;
moel@250
   325
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   326
                } break;
moel@250
   327
              default: {
moel@250
   328
                  double multiplier = 
moel@250
   329
                    ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
moel@250
   330
                  coreClocks[i].Value = (float)(multiplier * newBusClock);
moel@250
   331
                } break;
moel@250
   332
            }         
moel@219
   333
          } else { 
moel@201
   334
            // if IA32_PERF_STATUS is not available, assume TSC frequency
moel@201
   335
            coreClocks[i].Value = (float)TimeStampCounterFrequency;
moel@46
   336
          }
moel@44
   337
        }
moel@191
   338
        if (newBusClock > 0) {
moel@191
   339
          this.busClock.Value = (float)newBusClock;
moel@191
   340
          ActivateSensor(this.busClock);
moel@191
   341
        }
moel@44
   342
      }
moel@46
   343
    }
moel@191
   344
  }
moel@1
   345
}