Added experimental support for the Nuvoton NCT6791D super I/O chip.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2009-2013 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.Globalization;
15 namespace OpenHardwareMonitor.Hardware.CPU {
16 internal sealed class IntelCPU : GenericCPU {
18 private enum Microarchitecture {
29 private readonly Sensor[] coreTemperatures;
30 private readonly Sensor packageTemperature;
31 private readonly Sensor[] coreClocks;
32 private readonly Sensor busClock;
33 private readonly Sensor[] powerSensors;
35 private readonly Microarchitecture microarchitecture;
36 private readonly double timeStampCounterMultiplier;
38 private const uint IA32_THERM_STATUS_MSR = 0x019C;
39 private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
40 private const uint IA32_PERF_STATUS = 0x0198;
41 private const uint MSR_PLATFORM_INFO = 0xCE;
42 private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1;
43 private const uint MSR_RAPL_POWER_UNIT = 0x606;
44 private const uint MSR_PKG_ENERY_STATUS = 0x611;
45 private const uint MSR_DRAM_ENERGY_STATUS = 0x619;
46 private const uint MSR_PP0_ENERY_STATUS = 0x639;
47 private const uint MSR_PP1_ENERY_STATUS = 0x641;
49 private readonly uint[] energyStatusMSRs = { MSR_PKG_ENERY_STATUS,
50 MSR_PP0_ENERY_STATUS, MSR_PP1_ENERY_STATUS, MSR_DRAM_ENERGY_STATUS };
51 private readonly string[] powerSensorLabels =
52 { "CPU Package", "CPU Cores", "CPU Graphics", "CPU DRAM" };
53 private float energyUnitMultiplier = 0;
54 private DateTime[] lastEnergyTime;
55 private uint[] lastEnergyConsumed;
58 private float[] Floats(float f) {
59 float[] result = new float[coreCount];
60 for (int i = 0; i < coreCount; i++)
65 private float[] GetTjMaxFromMSR() {
67 float[] result = new float[coreCount];
68 for (int i = 0; i < coreCount; i++) {
69 if (Ring0.RdmsrTx(IA32_TEMPERATURE_TARGET, out eax,
70 out edx, 1UL << cpuid[i][0].Thread)) {
71 result[i] = (eax >> 16) & 0xFF;
79 public IntelCPU(int processorIndex, CPUID[][] cpuid, ISettings settings)
80 : base(processorIndex, cpuid, settings) {
86 case 0x0F: // Intel Core 2 (65nm)
87 microarchitecture = Microarchitecture.Core;
92 tjMax = Floats(80 + 10); break;
94 tjMax = Floats(90 + 10); break;
96 tjMax = Floats(85 + 10); break;
98 tjMax = Floats(80 + 10); break;
100 tjMax = Floats(90 + 10); break;
102 tjMax = Floats(85 + 10); break;
104 tjMax = Floats(85 + 10); break;
106 case 0x17: // Intel Core 2 (45nm)
107 microarchitecture = Microarchitecture.Core;
108 tjMax = Floats(100); break;
109 case 0x1C: // Intel Atom (45nm)
110 microarchitecture = Microarchitecture.Atom;
113 tjMax = Floats(90); break;
115 tjMax = Floats(100); break;
117 tjMax = Floats(90); break;
119 case 0x1A: // Intel Core i7 LGA1366 (45nm)
120 case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
121 case 0x1F: // Intel Core i5, i7
122 case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
123 case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core
124 case 0x2E: // Intel Xeon Processor 7500 series (45nm)
125 case 0x2F: // Intel Xeon Processor (32nm)
126 microarchitecture = Microarchitecture.Nehalem;
127 tjMax = GetTjMaxFromMSR();
129 case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm)
130 case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm)
131 microarchitecture = Microarchitecture.SandyBridge;
132 tjMax = GetTjMaxFromMSR();
134 case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm)
135 microarchitecture = Microarchitecture.IvyBridge;
136 tjMax = GetTjMaxFromMSR();
138 case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm)
141 microarchitecture = Microarchitecture.Haswell;
142 tjMax = GetTjMaxFromMSR();
145 microarchitecture = Microarchitecture.Unknown;
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;
162 microarchitecture = Microarchitecture.Unknown;
168 microarchitecture = Microarchitecture.Unknown;
173 // set timeStampCounterMultiplier
174 switch (microarchitecture) {
175 case Microarchitecture.NetBurst:
176 case Microarchitecture.Atom:
177 case Microarchitecture.Core: {
179 if (Ring0.Rdmsr(IA32_PERF_STATUS, out eax, out edx)) {
180 timeStampCounterMultiplier =
181 ((edx >> 8) & 0x1f) + 0.5 * ((edx >> 14) & 1);
184 case Microarchitecture.Nehalem:
185 case Microarchitecture.SandyBridge:
186 case Microarchitecture.IvyBridge:
187 case Microarchitecture.Haswell: {
189 if (Ring0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
190 timeStampCounterMultiplier = (eax >> 8) & 0xff;
194 timeStampCounterMultiplier = 0;
198 // check if processor supports a digital thermal sensor at core level
199 if (cpuid[0][0].Data.GetLength(0) > 6 &&
200 (cpuid[0][0].Data[6, 0] & 1) != 0 &&
201 microarchitecture != Microarchitecture.Unknown)
203 coreTemperatures = new Sensor[coreCount];
204 for (int i = 0; i < coreTemperatures.Length; i++) {
205 coreTemperatures[i] = new Sensor(CoreString(i), i,
206 SensorType.Temperature, this, new[] {
207 new ParameterDescription(
208 "TjMax [°C]", "TjMax temperature of the core sensor.\n" +
209 "Temperature = TjMax - TSlope * Value.", tjMax[i]),
210 new ParameterDescription("TSlope [°C]",
211 "Temperature slope of the digital thermal sensor.\n" +
212 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
213 ActivateSensor(coreTemperatures[i]);
216 coreTemperatures = new Sensor[0];
219 // check if processor supports a digital thermal sensor at package level
220 if (cpuid[0][0].Data.GetLength(0) > 6 &&
221 (cpuid[0][0].Data[6, 0] & 0x40) != 0 &&
222 microarchitecture != Microarchitecture.Unknown)
224 packageTemperature = new Sensor("CPU Package",
225 coreTemperatures.Length, SensorType.Temperature, this, new[] {
226 new ParameterDescription(
227 "TjMax [°C]", "TjMax temperature of the package sensor.\n" +
228 "Temperature = TjMax - TSlope * Value.", tjMax[0]),
229 new ParameterDescription("TSlope [°C]",
230 "Temperature slope of the digital thermal sensor.\n" +
231 "Temperature = TjMax - TSlope * Value.", 1)}, settings);
232 ActivateSensor(packageTemperature);
235 busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings);
236 coreClocks = new Sensor[coreCount];
237 for (int i = 0; i < coreClocks.Length; i++) {
239 new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings);
240 if (HasTimeStampCounter && microarchitecture != Microarchitecture.Unknown)
241 ActivateSensor(coreClocks[i]);
244 if (microarchitecture == Microarchitecture.SandyBridge ||
245 microarchitecture == Microarchitecture.IvyBridge ||
246 microarchitecture == Microarchitecture.Haswell)
248 powerSensors = new Sensor[energyStatusMSRs.Length];
249 lastEnergyTime = new DateTime[energyStatusMSRs.Length];
250 lastEnergyConsumed = new uint[energyStatusMSRs.Length];
253 if (Ring0.Rdmsr(MSR_RAPL_POWER_UNIT, out eax, out edx))
254 energyUnitMultiplier = 1.0f / (1 << (int)((eax >> 8) & 0x1FF));
256 if (energyUnitMultiplier != 0) {
257 for (int i = 0; i < energyStatusMSRs.Length; i++) {
258 if (!Ring0.Rdmsr(energyStatusMSRs[i], out eax, out edx))
261 lastEnergyTime[i] = DateTime.UtcNow;
262 lastEnergyConsumed[i] = eax;
263 powerSensors[i] = new Sensor(powerSensorLabels[i], i,
264 SensorType.Power, this, settings);
265 ActivateSensor(powerSensors[i]);
273 protected override uint[] GetMSRs() {
277 IA32_THERM_STATUS_MSR,
278 IA32_TEMPERATURE_TARGET,
279 IA32_PACKAGE_THERM_STATUS,
281 MSR_PKG_ENERY_STATUS,
282 MSR_DRAM_ENERGY_STATUS,
283 MSR_PP0_ENERY_STATUS,
288 public override string GetReport() {
289 StringBuilder r = new StringBuilder();
290 r.Append(base.GetReport());
292 r.Append("Microarchitecture: ");
293 r.AppendLine(microarchitecture.ToString());
294 r.Append("Time Stamp Counter Multiplier: ");
295 r.AppendLine(timeStampCounterMultiplier.ToString(
296 CultureInfo.InvariantCulture));
302 public override void Update() {
305 for (int i = 0; i < coreTemperatures.Length; i++) {
308 IA32_THERM_STATUS_MSR, out eax, out edx,
309 1UL << cpuid[i][0].Thread)) {
310 // if reading is valid
311 if ((eax & 0x80000000) != 0) {
312 // get the dist from tjMax from bits 22:16
313 float deltaT = ((eax & 0x007F0000) >> 16);
314 float tjMax = coreTemperatures[i].Parameters[0].Value;
315 float tSlope = coreTemperatures[i].Parameters[1].Value;
316 coreTemperatures[i].Value = tjMax - tSlope * deltaT;
318 coreTemperatures[i].Value = null;
323 if (packageTemperature != null) {
326 IA32_PACKAGE_THERM_STATUS, out eax, out edx,
327 1UL << cpuid[0][0].Thread)) {
328 // get the dist from tjMax from bits 22:16
329 float deltaT = ((eax & 0x007F0000) >> 16);
330 float tjMax = packageTemperature.Parameters[0].Value;
331 float tSlope = packageTemperature.Parameters[1].Value;
332 packageTemperature.Value = tjMax - tSlope * deltaT;
334 packageTemperature.Value = null;
338 if (HasTimeStampCounter && timeStampCounterMultiplier > 0) {
339 double newBusClock = 0;
341 for (int i = 0; i < coreClocks.Length; i++) {
342 System.Threading.Thread.Sleep(1);
343 if (Ring0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
344 1UL << cpuid[i][0].Thread)) {
346 TimeStampCounterFrequency / timeStampCounterMultiplier;
347 switch (microarchitecture) {
348 case Microarchitecture.Nehalem: {
349 uint multiplier = eax & 0xff;
350 coreClocks[i].Value = (float)(multiplier * newBusClock);
352 case Microarchitecture.SandyBridge:
353 case Microarchitecture.IvyBridge:
354 case Microarchitecture.Haswell: {
355 uint multiplier = (eax >> 8) & 0xff;
356 coreClocks[i].Value = (float)(multiplier * newBusClock);
360 ((eax >> 8) & 0x1f) + 0.5 * ((eax >> 14) & 1);
361 coreClocks[i].Value = (float)(multiplier * newBusClock);
365 // if IA32_PERF_STATUS is not available, assume TSC frequency
366 coreClocks[i].Value = (float)TimeStampCounterFrequency;
369 if (newBusClock > 0) {
370 this.busClock.Value = (float)newBusClock;
371 ActivateSensor(this.busClock);
375 if (powerSensors != null) {
376 foreach (Sensor sensor in powerSensors) {
381 if (!Ring0.Rdmsr(energyStatusMSRs[sensor.Index], out eax, out edx))
384 DateTime time = DateTime.UtcNow;
385 uint energyConsumed = eax;
387 (float)(time - lastEnergyTime[sensor.Index]).TotalSeconds;
388 if (deltaTime < 0.01)
391 sensor.Value = energyUnitMultiplier * unchecked(
392 energyConsumed - lastEnergyConsumed[sensor.Index]) / deltaTime;
393 lastEnergyTime[sensor.Index] = time;
394 lastEnergyConsumed[sensor.Index] = energyConsumed;