Added support for Fintek F71858 chips. Corrected the number of fans for Fintek.
     3   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
     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
 
     9   http://www.mozilla.org/MPL/
 
    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.
 
    15   The Original Code is the Open Hardware Monitor code.
 
    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-2010
 
    20   the Initial Developer. All Rights Reserved.
 
    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.
 
    39 using System.Collections.Generic;
 
    41 using System.Diagnostics;
 
    42 using System.Reflection;
 
    43 using System.Runtime.InteropServices;
 
    44 using System.Threading;
 
    47 namespace OpenHardwareMonitor.Hardware.CPU {
 
    48   public class IntelCPU : Hardware, IHardware {
 
    55     private uint stepping;
 
    57     private Sensor[] coreTemperatures;
 
    59     private Sensor totalLoad;
 
    60     private Sensor[] coreLoads;
 
    61     private Sensor[] coreClocks;
 
    62     private Sensor busClock;
 
    63     private uint logicalProcessors;
 
    64     private uint logicalProcessorsPerCore;
 
    65     private uint coreCount;
 
    66     private ulong affinityMask;
 
    68     private CPULoad cpuLoad;
 
    70     private ulong lastCount;    
 
    71     private long lastTime;
 
    72     private uint maxNehalemMultiplier = 0;
 
    74     private const uint IA32_THERM_STATUS_MSR = 0x019C;
 
    75     private const uint IA32_TEMPERATURE_TARGET = 0x01A2;
 
    76     private const uint IA32_PERF_STATUS = 0x0198;
 
    77     private const uint MSR_PLATFORM_INFO = 0xCE;
 
    79     private string CoreString(int i) {
 
    83         return "CPU Core #" + (i + 1);
 
    86     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 
    87     private static extern bool GetProcessAffinityMask(IntPtr handle, 
 
    88       out IntPtr processMask, out IntPtr systemMask);
 
    90     public IntelCPU(string name, uint family, uint model, uint stepping, 
 
    91       uint[,] cpuidData, uint[,] cpuidExtData) {
 
    94       this.icon = Utilities.EmbeddedResources.GetImage("cpu.png");
 
    98       this.stepping = stepping;
 
   100       logicalProcessors = 0;
 
   101       if (cpuidData.GetLength(0) > 0x0B) {
 
   102         uint eax, ebx, ecx, edx;
 
   103         WinRing0.CpuidEx(0x0B, 0, out eax, out ebx, out ecx, out edx);
 
   104         logicalProcessorsPerCore = ebx & 0xFF;
 
   105         if (logicalProcessorsPerCore > 0) {
 
   106           WinRing0.CpuidEx(0x0B, 1, out eax, out ebx, out ecx, out edx);
 
   107           logicalProcessors = ebx & 0xFF;
 
   110       if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x04) {
 
   111         uint coresPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
 
   112         uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;        
 
   113         logicalProcessorsPerCore = logicalPerPackage / coresPerPackage;
 
   114         logicalProcessors = logicalPerPackage;
 
   116       if (logicalProcessors <= 0 && cpuidData.GetLength(0) > 0x01) {
 
   117         uint logicalPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
 
   118         logicalProcessorsPerCore = logicalPerPackage;
 
   119         logicalProcessors = logicalPerPackage;
 
   121       if (logicalProcessors <= 0) {
 
   122         logicalProcessors = 1;
 
   123         logicalProcessorsPerCore = 1;
 
   126       IntPtr processMask, systemMask;
 
   127       GetProcessAffinityMask(Process.GetCurrentProcess().Handle,
 
   128         out processMask, out systemMask);
 
   129       affinityMask = (ulong)systemMask;
 
   131       // correct values in case HypeThreading is disabled
 
   132       if (logicalProcessorsPerCore > 1) {
 
   133         ulong affinity = affinityMask;
 
   134         int availableLogicalProcessors = 0;
 
   135         while (affinity != 0) {
 
   136           if ((affinity & 0x1) > 0)
 
   137             availableLogicalProcessors++;
 
   140         while (logicalProcessorsPerCore > 1 &&
 
   141           availableLogicalProcessors < logicalProcessors) {
 
   142           logicalProcessors >>= 1;
 
   143           logicalProcessorsPerCore >>= 1;
 
   147       coreCount = logicalProcessors / logicalProcessorsPerCore;
 
   153               case 0x0F: // Intel Core (65nm)
 
   158                         tjMax = 80 + 10; break;
 
   160                         tjMax = 90 + 10; break;
 
   162                         tjMax = 85 + 10; break;
 
   164                     tjMax = 80 + 10; break;
 
   166                     tjMax = 90 + 10; break;
 
   168                     tjMax = 85 + 10; break;
 
   170                     tjMax = 85 + 10; break;
 
   172               case 0x17: // Intel Core (45nm)
 
   174               case 0x1C: // Intel Atom 
 
   176               case 0x1A: // Intel Core i7 LGA1366 (45nm)
 
   177               case 0x1E: // Intel Core i5, i7 LGA1156 (45nm)
 
   178               case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm)
 
   180                 if (WinRing0.Rdmsr(IA32_TEMPERATURE_TARGET, out eax, out edx)) {
 
   181                   tjMax = (eax >> 16) & 0xFF;
 
   185                 if (WinRing0.Rdmsr(MSR_PLATFORM_INFO, out eax, out edx)) {
 
   186                   maxNehalemMultiplier = (eax >> 8) & 0xff;
 
   193         default: tjMax = 100; break;
 
   196       // check if processor supports a digital thermal sensor
 
   197       if (cpuidData.GetLength(0) > 6 && (cpuidData[6, 0] & 1) != 0) {
 
   198         coreTemperatures = new Sensor[coreCount];
 
   199         for (int i = 0; i < coreTemperatures.Length; i++) {
 
   200           coreTemperatures[i] = new Sensor(CoreString(i), i, tjMax,
 
   201             SensorType.Temperature, this, new ParameterDescription[] { 
 
   202               new ParameterDescription(
 
   203                 "TjMax", "TjMax temperature of the core.\n" + 
 
   204                 "Temperature = TjMax - TSlope * Value.", tjMax), 
 
   205               new ParameterDescription(
 
   206                 "TSlope", "Temperature slope of the digital thermal sensor.\n" + 
 
   207                 "Temperature = TjMax - TSlope * Value.", 1)});
 
   210         coreTemperatures = new Sensor[0];
 
   214         totalLoad = new Sensor("CPU Total", 0, SensorType.Load, this);
 
   217       coreLoads = new Sensor[coreCount];
 
   218       for (int i = 0; i < coreLoads.Length; i++)
 
   219         coreLoads[i] = new Sensor(CoreString(i), i + 1,
 
   220           SensorType.Load, this);     
 
   221       cpuLoad = new CPULoad(coreCount, logicalProcessorsPerCore);
 
   222       if (cpuLoad.IsAvailable) {
 
   223         foreach (Sensor sensor in coreLoads)
 
   224           ActivateSensor(sensor);
 
   225         if (totalLoad != null)
 
   226           ActivateSensor(totalLoad);
 
   231       busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this);      
 
   232       coreClocks = new Sensor[coreCount];
 
   233       for (int i = 0; i < coreClocks.Length; i++) {
 
   235           new Sensor(CoreString(i), i + 1, SensorType.Clock, this);
 
   236         ActivateSensor(coreClocks[i]);
 
   246     public string Identifier {
 
   247       get { return "/intelcpu/0"; }
 
   254     private void AppendMSRData(StringBuilder r, uint msr, int core) {
 
   256       if (WinRing0.RdmsrTx(msr, out eax, out edx,
 
   257          (UIntPtr)(1 << (int)(logicalProcessorsPerCore * core)))) {
 
   259         r.Append((msr).ToString("X8"));
 
   261         r.Append((edx).ToString("X8"));
 
   263         r.Append((eax).ToString("X8"));
 
   268     public string GetReport() {
 
   269       StringBuilder r = new StringBuilder();
 
   271       r.AppendLine("Intel CPU");
 
   273       r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
 
   274       r.AppendFormat("Number of Cores: {0}{1}", coreCount, 
 
   275         Environment.NewLine);
 
   276       r.AppendFormat("Threads per Core: {0}{1}", logicalProcessorsPerCore,
 
   277         Environment.NewLine);
 
   278       r.AppendFormat("Affinity Mask: 0x{0}{1}", affinityMask.ToString("X"),
 
   279         Environment.NewLine);  
 
   282       for (int i = 0; i < coreCount; i++) {
 
   283         r.AppendLine("MSR Core #" + (i + 1));
 
   285         r.AppendLine(" MSR       EDX       EAX");
 
   286         AppendMSRData(r, MSR_PLATFORM_INFO, i);
 
   287         AppendMSRData(r, IA32_PERF_STATUS, i);
 
   288         AppendMSRData(r, IA32_THERM_STATUS_MSR, i);
 
   289         AppendMSRData(r, IA32_TEMPERATURE_TARGET, i);
 
   296     public void Update() {
 
   298       for (int i = 0; i < coreTemperatures.Length; i++) {
 
   300         if (WinRing0.RdmsrTx(
 
   301           IA32_THERM_STATUS_MSR, out eax, out edx, 
 
   302             (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) 
 
   304           // if reading is valid
 
   305           if ((eax & 0x80000000) != 0) {
 
   306             // get the dist from tjMax from bits 22:16
 
   307             float deltaT = ((eax & 0x007F0000) >> 16);
 
   308             float tjMax = coreTemperatures[i].Parameters[0].Value;
 
   309             float tSlope = coreTemperatures[i].Parameters[1].Value;
 
   310             coreTemperatures[i].Value = tjMax - tSlope * deltaT;
 
   311             ActivateSensor(coreTemperatures[i]);
 
   313             DeactivateSensor(coreTemperatures[i]);
 
   318       if (cpuLoad.IsAvailable) {
 
   320         for (int i = 0; i < coreLoads.Length; i++)
 
   321           coreLoads[i].Value = cpuLoad.GetCoreLoad(i);
 
   322         if (totalLoad != null)
 
   323           totalLoad.Value = cpuLoad.GetTotalLoad();
 
   327       bool valid = WinRing0.RdtscTx(out lsb, out msb, (UIntPtr)1);
 
   328       long time = Stopwatch.GetTimestamp();
 
   329       ulong count = ((ulong)msb << 32) | lsb;
 
   330       double delta = ((double)(time - lastTime)) / Stopwatch.Frequency;
 
   331       if (valid && delta > 0.5) {
 
   332         double maxClock = (count - lastCount) / (1e6 * delta);
 
   335         for (int i = 0; i < coreClocks.Length; i++) {
 
   336           System.Threading.Thread.Sleep(1);
 
   337           if (WinRing0.RdmsrTx(IA32_PERF_STATUS, out eax, out edx,
 
   338             (UIntPtr)(1 << (int)(logicalProcessorsPerCore * i)))) {
 
   339             if (maxNehalemMultiplier > 0) { // Core i3, i5, i7
 
   340               uint nehalemMultiplier = eax & 0xff;
 
   341               coreClocks[i].Value =
 
   342                 (float)(nehalemMultiplier * maxClock / maxNehalemMultiplier);
 
   343               busClock = (float)(maxClock / maxNehalemMultiplier);
 
   345               uint multiplier = (eax >> 8) & 0x1f;
 
   346               uint maxMultiplier = (edx >> 8) & 0x1f;
 
   347               // factor = multiplier * 2 to handle non integer multipliers 
 
   348               uint factor = (multiplier << 1) | ((eax >> 14) & 1);
 
   349               uint maxFactor = (maxMultiplier << 1) | ((edx >> 14) & 1);
 
   351                 coreClocks[i].Value = (float)(factor * maxClock / maxFactor);
 
   352                 busClock = (float)(2 * maxClock / maxFactor);
 
   355           } else { // Intel Pentium 4
 
   356             // if IA32_PERF_STATUS is not available, assume maxClock
 
   357             coreClocks[i].Value = (float)maxClock;
 
   361           this.busClock.Value = (float)busClock;
 
   362           ActivateSensor(this.busClock);