Hardware/CPU/IntelCPU.cs
author moel.mich
Sun, 26 Jun 2011 17:00:32 +0000
changeset 306 e9127c00ada1
parent 264 718555482989
child 315 158ec57434e8
permissions -rw-r--r--
Added support for package level temperature sensors on new Intel Sandy Bridge CPUs.
     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-2011
    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.Globalization;
    40 using System.Text;
    41 
    42 namespace OpenHardwareMonitor.Hardware.CPU {
    43   internal sealed class IntelCPU : GenericCPU {
    44 
    45     private enum Microarchitecture {
    46       Unknown,
    47       NetBurst,
    48       Core,
    49       Atom,
    50       Nehalem,
    51       SandyBridge
    52     }
    53 
    54     private readonly Sensor[] coreTemperatures;
    55     private readonly Sensor packageTemperature;
    56     private readonly Sensor[] coreClocks;
    57     private readonly Sensor busClock;
    58 
    59     private readonly Microarchitecture microarchitecture;
    60     private readonly double timeStampCounterMultiplier;
    61 
    62     private const uint IA32_THERM_STATUS_MSR = 0x019C;
    63     private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
    64     private const uint IA32_PERF_STATUS = 0x0198;
    65     private const uint MSR_PLATFORM_INFO = 0xCE;
    66     private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
    67 
    68     private float[] Floats(float f) {
    69       float[] result = new float[coreCount];
    70       for (int i = 0; i < coreCount; i++)
    71         result[i] = f;
    72       return result;
    73     }
    74 
    75     private float[] GetTjMaxFromMSR() {
    76       uint eax, edx;
    77       float[] result = new float[coreCount];
    78       for (int i = 0; i < coreCount; i++) {
    79         if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
    80           out edx, 1UL << cpuid[i][0].Thread)) {
    81           result[i] = (eax >> 16) & 0xFF;
    82         } else {
    83           result[i] = 100;
    84         }
    85       }
    86       return result;
    87     }
    88 
    89     public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
    90       : base(processorIndex, cpuid, settings) 
    91     {
    92       // set tjMax
    93       float[] tjMax;
    94       switch (family) {
    95         case 0x06: {
    96             switch (model) {
    97               case 0x0F: // Intel Core 2 (65nm)
    98                 microarchitecture = Microarchitecture.Core;
    99                 switch (stepping) {
   100                   case 0x06: // B2
   101                     switch (coreCount) {
   102                       case 2:
   103                         tjMax = Floats(80 + 10); break;
   104                       case 4:
   105                         tjMax = Floats(90 + 10); break;
   106                       default:
   107                         tjMax = Floats(85 + 10); break;
   108                     }
   109                     tjMax = Floats(80 + 10); break;
   110                   case 0x0B: // G0
   111                     tjMax = Floats(90 + 10); break;
   112                   case 0x0D: // M0
   113                     tjMax = Floats(85 + 10); break;
   114                   default:
   115                     tjMax = Floats(85 + 10); break;
   116                 } break;
   117               case 0x17: // Intel Core 2 (45nm)
   118                 microarchitecture = Microarchitecture.Core;
   119                 tjMax = Floats(100); break;
   120               case 0x1C: // Intel Atom (45nm)
   121                 microarchitecture = Microarchitecture.Atom;
   122                 switch (stepping) {
   123                   case 0x02: // C0
   124                     tjMax = Floats(90); break;
   125                   case 0x0A: // A0, B0
   126                     tjMax = Floats(100); break;
   127                   default:
   128                     tjMax = Floats(90); break;
   129                 } break;
   130               case 0x1A: // Intel Core i7 LGA1366 (45nm)
   131               case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
   132               case 0x1F: // Intel Core i5, i7 
   133               case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
   134               case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
   135               case 0x2E: // Intel Xeon Processor 7500 series
   136                 microarchitecture = Microarchitecture.Nehalem;
   137                 tjMax = GetTjMaxFromMSR();
   138                 break;
   139               case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
   140               case 0x2D: // Next Generation Intel Xeon Processor
   141                 microarchitecture = Microarchitecture.SandyBridge;
   142                 tjMax = GetTjMaxFromMSR();
   143                 break;
   144               default:
   145                 microarchitecture = Microarchitecture.Unknown;
   146                 tjMax = Floats(100); 
   147                 break;
   148             }
   149           } break;
   150         case 0x0F: {
   151             switch (model) {
   152               case 0x00: // Pentium 4 (180nm)
   153               case 0x01: // Pentium 4 (130nm)
   154               case 0x02: // Pentium 4 (130nm)
   155               case 0x03: // Pentium 4, Celeron D (90nm)
   156               case 0x04: // Pentium 4, Pentium D, Celeron D (90nm)
   157               case 0x06: // Pentium 4, Pentium D, Celeron D (65nm)
   158                 microarchitecture = Microarchitecture.NetBurst;
   159                 tjMax = Floats(100); 
   160                 break;
   161               default:
   162                 microarchitecture = Microarchitecture.Unknown;
   163                 tjMax = Floats(100);
   164                 break;
   165             }
   166           } break;
   167         default:
   168           microarchitecture = Microarchitecture.Unknown;
   169           tjMax = Floats(100); 
   170           break;
   171       }
   172 
   173       // set timeStampCounterMultiplier
   174       switch (microarchitecture) {
   175         case Microarchitecture.NetBurst:
   176         case Microarchitecture.Atom:
   177         case Microarchitecture.Core: {
   178             uint eax, edx;
   179             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   180               timeStampCounterMultiplier = 
   181                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   182             }
   183           } break;
   184         case Microarchitecture.Nehalem: 
   185         case Microarchitecture.SandyBridge: {
   186             uint eax, edx;
   187             if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
   188               timeStampCounterMultiplier = (eax >> 8) & 0xff;
   189             }
   190           } break;
   191         default: {
   192             timeStampCounterMultiplier = 1;
   193             uint eax, edx;
   194             if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
   195               timeStampCounterMultiplier =
   196                 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
   197             }
   198           } break;
   199       }
   200 
   201       // check if processor supports a digital thermal sensor at core level
   202       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   203         (cpuid[0][0].Data[6, 0] & 1) != 0) 
   204       {
   205         coreTemperatures = new Sensor[coreCount];
   206         for (int i = 0; i < coreTemperatures.Length; i++) {
   207           coreTemperatures[i] = new Sensor(CoreString(i), i,
   208             SensorType.Temperature, this, new [] { 
   209               new ParameterDescription(
   210                 "TjMax [°C]", "TjMax temperature of the core sensor.\n" + 
   211                 "Temperature = TjMax - TSlope * Value.", tjMax[i]), 
   212               new ParameterDescription("TSlope [°C]", 
   213                 "Temperature slope of the digital thermal sensor.\n" + 
   214                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   215           ActivateSensor(coreTemperatures[i]);
   216         }
   217       } else {
   218         coreTemperatures = new Sensor[0];
   219       }
   220 
   221       // check if processor supports a digital thermal sensor at package level
   222       if (cpuid[0][0].Data.GetLength(0) > 6 &&
   223         (cpuid[0][0].Data[6, 0] & 0x40) != 0) 
   224       {
   225           packageTemperature = new Sensor("CPU Package", 
   226             coreTemperatures.Length, SensorType.Temperature, this, new[] { 
   227               new ParameterDescription(
   228                 "TjMax [°C]", "TjMax temperature of the package sensor.\n" + 
   229                 "Temperature = TjMax - TSlope * Value.", tjMax[0]), 
   230               new ParameterDescription("TSlope [°C]", 
   231                 "Temperature slope of the digital thermal sensor.\n" + 
   232                 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
   233         ActivateSensor(packageTemperature);
   234       } 
   235 
   236       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
   237       coreClocks = new Sensor[coreCount];
   238       for (int i = 0; i < coreClocks.Length; i++) {
   239         coreClocks[i] =
   240           new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
   241         if (HasTimeStampCounter)
   242           ActivateSensor(coreClocks[i]);
   243       }
   244 
   245       Update();
   246     }
   247 
   248     protected override uint[] GetMSRs() {
   249       return new [] {
   250         MSR_PLATFORM_INFO,
   251         IA32_PERF_STATUS ,
   252         IA32_THERM_STATUS_MSR,
   253         IA32_TEMPERATURE_TARGET,
   254         IA32_PACKAGE_THERM_STATUS
   255       };
   256     }
   257 
   258     public override string GetReport() {
   259       StringBuilder r = new StringBuilder();
   260       r.Append(base.GetReport());
   261 
   262       r.Append("Microarchitecture: ");
   263       r.AppendLine(microarchitecture.ToString());
   264       r.Append("Time Stamp Counter Multiplier: ");
   265       r.AppendLine(timeStampCounterMultiplier.ToString(
   266         CultureInfo.InvariantCulture));
   267       r.AppendLine();
   268 
   269       return r.ToString();
   270     }
   271 
   272     public override void Update() {
   273       base.Update();
   274 
   275       for (int i = 0; i < coreTemperatures.Length; i++) {
   276         uint eax, edx;
   277         if (Ring0.RdmsrTx(
   278           IA32_THERM_STATUS_MSR, out eax, out edx,
   279             1UL << cpuid[i][0].Thread)) {
   280           // if reading is valid
   281           if ((eax & 0x80000000) != 0) {
   282             // get the dist from tjMax from bits 22:16
   283             float deltaT = ((eax & 0x007F0000) >> 16);
   284             float tjMax = coreTemperatures[i].Parameters[0].Value;
   285             float tSlope = coreTemperatures[i].Parameters[1].Value;
   286             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
   287           } else {
   288             coreTemperatures[i].Value = null;
   289           }
   290         }
   291       }
   292 
   293       if (packageTemperature != null) {
   294         uint eax, edx;
   295         if (Ring0.RdmsrTx(
   296           IA32_THERM_STATUS_MSR, out eax, out edx,
   297             1UL << cpuid[0][0].Thread)) {
   298           // get the dist from tjMax from bits 22:16
   299           float deltaT = ((eax & 0x007F0000) >> 16);
   300           float tjMax = packageTemperature.Parameters[0].Value;
   301           float tSlope = packageTemperature.Parameters[1].Value;
   302           packageTemperature.Value = tjMax - tSlope * deltaT;
   303         } else {
   304           packageTemperature.Value = null;
   305         }
   306       }
   307 
   308       if (HasTimeStampCounter) {
   309         double newBusClock = 0;
   310         uint eax, edx;
   311         for (int i = 0; i < coreClocks.Length; i++) {
   312           System.Threading.Thread.Sleep(1);
   313           if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
   314             1UL << cpuid[i][0].Thread)) 
   315           {
   316             newBusClock = 
   317               TimeStampCounterFrequency / timeStampCounterMultiplier;
   318             switch (microarchitecture) {
   319               case Microarchitecture.Nehalem: {
   320                   uint multiplier = eax & 0xff;
   321                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   322                 } break;
   323               case Microarchitecture.SandyBridge: {
   324                   uint multiplier = (eax >> 8) & 0xff;
   325                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   326                 } break;
   327               default: {
   328                   double multiplier = 
   329                     ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
   330                   coreClocks[i].Value = (float)(multiplier * newBusClock);
   331                 } break;
   332             }         
   333           } else { 
   334             // if IA32_PERF_STATUS is not available, assume TSC frequency
   335             coreClocks[i].Value = (float)TimeStampCounterFrequency;
   336           }
   337         }
   338         if (newBusClock > 0) {
   339           this.busClock.Value = (float)newBusClock;
   340           ActivateSensor(this.busClock);
   341         }
   342       }
   343     }
   344   }
   345 }