moel@90: /*
moel@90:   
moel@90:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@90: 
moel@90:   The contents of this file are subject to the Mozilla Public License Version
moel@90:   1.1 (the "License"); you may not use this file except in compliance with
moel@90:   the License. You may obtain a copy of the License at
moel@90:  
moel@90:   http://www.mozilla.org/MPL/
moel@90: 
moel@90:   Software distributed under the License is distributed on an "AS IS" basis,
moel@90:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@90:   for the specific language governing rights and limitations under the License.
moel@90: 
moel@90:   The Original Code is the Open Hardware Monitor code.
moel@90: 
moel@90:   The Initial Developer of the Original Code is 
moel@90:   Michael Möller <m.moeller@gmx.ch>.
moel@90:   Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@90:   the Initial Developer. All Rights Reserved.
moel@90: 
moel@90:   Contributor(s):
moel@90: 
moel@90:   Alternatively, the contents of this file may be used under the terms of
moel@90:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@90:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@90:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@90:   of those above. If you wish to allow use of your version of this file only
moel@90:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@90:   use your version of this file under the terms of the MPL, indicate your
moel@90:   decision by deleting the provisions above and replace them with the notice
moel@90:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@90:   the provisions above, a recipient may use your version of this file under
moel@90:   the terms of any one of the MPL, the GPL or the LGPL.
moel@90:  
moel@90: */
moel@90: 
moel@90: using System;
moel@90: using System.Text;
moel@90: 
moel@90: namespace OpenHardwareMonitor.Hardware.CPU {
moel@165: 
moel@165:   internal enum Vendor {
moel@90:     Unknown,
moel@90:     Intel,
moel@90:     AMD,
moel@90:   }
moel@165: 
moel@165:   internal class CPUID {
moel@90: 
moel@90:     private int thread;
moel@90: 
moel@124:     private Vendor vendor = Vendor.Unknown;
moel@90: 
moel@124:     private string cpuBrandString = "";
moel@124:     private string name = "";
moel@90: 
moel@124:     private uint[,] cpuidData = new uint[0, 0];
moel@124:     private uint[,] cpuidExtData = new uint[0, 0];
moel@90: 
moel@90:     private uint family;
moel@90:     private uint model;
moel@90:     private uint stepping;
moel@90: 
moel@90:     private uint apicId;
moel@90: 
moel@90:     private uint threadMaskWith;
moel@90:     private uint coreMaskWith;
moel@90: 
moel@90:     private uint processorId;
moel@90:     private uint coreId;
moel@90:     private uint threadId;
moel@90: 
moel@90:     public static uint CPUID_0 = 0;
moel@90:     public static uint CPUID_EXT = 0x80000000;
moel@90: 
moel@167:     private static void AppendRegister(StringBuilder b, uint value) {
moel@90:       b.Append((char)((value) & 0xff));
moel@90:       b.Append((char)((value >> 8) & 0xff));
moel@90:       b.Append((char)((value >> 16) & 0xff));
moel@90:       b.Append((char)((value >> 24) & 0xff));
moel@90:     }
moel@90: 
moel@167:     private static uint NextLog2(long x) {
moel@105:       if (x <= 0)
moel@105:         return 0;
moel@105: 
moel@105:       x--;
moel@105:       uint count = 0;
moel@105:       while (x > 0) {
moel@105:         x >>= 1;
moel@105:         count++;
moel@105:       }
moel@105: 
moel@105:       return count;
moel@105:     }
moel@105: 
moel@90:     public CPUID(int thread) {
moel@90:       this.thread = thread;
moel@90: 
moel@124:       uint maxCpuid = 0;
moel@124:       uint maxCpuidExt = 0;
moel@124: 
moel@90:       uint eax, ebx, ecx, edx;
moel@90: 
moel@112:       if (thread >= 32)
moel@167:         throw new ArgumentOutOfRangeException("thread");
moel@90:       UIntPtr mask = (UIntPtr)(1L << thread);
moel@90: 
moel@90:       if (WinRing0.CpuidTx(CPUID_0, 0,
moel@90:           out eax, out ebx, out ecx, out edx, mask)) {
moel@112:         if (eax > 0)
moel@112:           maxCpuid = eax;
moel@112:         else
moel@112:           return;
moel@112: 
moel@90:         StringBuilder vendorBuilder = new StringBuilder();
moel@90:         AppendRegister(vendorBuilder, ebx);
moel@90:         AppendRegister(vendorBuilder, edx);
moel@90:         AppendRegister(vendorBuilder, ecx);
moel@90:         string cpuVendor = vendorBuilder.ToString();
moel@90:         switch (cpuVendor) {
moel@90:           case "GenuineIntel":
moel@90:             vendor = Vendor.Intel;
moel@90:             break;
moel@90:           case "AuthenticAMD":
moel@90:             vendor = Vendor.AMD;
moel@90:             break;
moel@90:           default:
moel@90:             vendor = Vendor.Unknown;
moel@90:             break;
moel@90:         }
moel@90:         eax = ebx = ecx = edx = 0;
moel@90:         if (WinRing0.CpuidTx(CPUID_EXT, 0,
moel@112:           out eax, out ebx, out ecx, out edx, mask)) {
moel@112:           if (eax > CPUID_EXT)
moel@112:             maxCpuidExt = eax - CPUID_EXT;
moel@112:           else
moel@112:             return;
moel@124:         } else {
moel@167:           throw new ArgumentOutOfRangeException("thread");
moel@112:         }
moel@90:       } else {
moel@167:         throw new ArgumentOutOfRangeException("thread");
moel@90:       }
moel@90: 
moel@112:       maxCpuid = Math.Min(maxCpuid, 1024);
moel@112:       maxCpuidExt = Math.Min(maxCpuidExt, 1024);   
moel@90: 
moel@90:       cpuidData = new uint[maxCpuid + 1, 4];
moel@90:       for (uint i = 0; i < (maxCpuid + 1); i++)
moel@90:         WinRing0.CpuidTx(CPUID_0 + i, 0, 
moel@90:           out cpuidData[i, 0], out cpuidData[i, 1],
moel@90:           out cpuidData[i, 2], out cpuidData[i, 3], mask);
moel@90: 
moel@95:       cpuidExtData = new uint[maxCpuidExt + 1, 4];
moel@95:       for (uint i = 0; i < (maxCpuidExt + 1); i++)
moel@90:         WinRing0.CpuidTx(CPUID_EXT + i, 0, 
moel@90:           out cpuidExtData[i, 0], out cpuidExtData[i, 1], 
moel@90:           out cpuidExtData[i, 2], out cpuidExtData[i, 3], mask);
moel@90: 
moel@90:       StringBuilder nameBuilder = new StringBuilder();
moel@90:       for (uint i = 2; i <= 4; i++) {
moel@90:         if (WinRing0.CpuidTx(CPUID_EXT + i, 0, 
moel@90:           out eax, out ebx, out ecx, out edx, mask)) 
moel@90:         {
moel@90:           AppendRegister(nameBuilder, eax);
moel@90:           AppendRegister(nameBuilder, ebx);
moel@90:           AppendRegister(nameBuilder, ecx);
moel@90:           AppendRegister(nameBuilder, edx);
moel@90:         }
moel@90:       }
moel@90:       nameBuilder.Replace('\0', ' ');
moel@90:       cpuBrandString = nameBuilder.ToString().Trim();
moel@90:       nameBuilder.Replace("(R)", " ");
moel@90:       nameBuilder.Replace("(TM)", " ");
moel@90:       nameBuilder.Replace("(tm)", " ");
moel@90:       nameBuilder.Replace("CPU", "");
moel@90:       for (int i = 0; i < 10; i++) nameBuilder.Replace("  ", " ");
moel@90:       name = nameBuilder.ToString();
moel@90:       if (name.Contains("@"))
moel@90:         name = name.Remove(name.LastIndexOf('@'));
moel@95:       name = name.Trim();      
moel@90: 
moel@90:       this.family = ((cpuidData[1, 0] & 0x0FF00000) >> 20) +
moel@90:         ((cpuidData[1, 0] & 0x0F00) >> 8);
moel@90:       this.model = ((cpuidData[1, 0] & 0x0F0000) >> 12) +
moel@90:         ((cpuidData[1, 0] & 0xF0) >> 4);
moel@90:       this.stepping = (cpuidData[1, 0] & 0x0F);
moel@90: 
moel@90:       this.apicId = (cpuidData[1, 1] >> 24) & 0xFF;
moel@90: 
moel@90:       switch (vendor) {
moel@90:         case Vendor.Intel:
moel@90:           uint maxCoreAndThreadIdPerPackage = (cpuidData[1, 1] >> 16) & 0xFF;
moel@95:           uint maxCoreIdPerPackage;
moel@95:           if (maxCpuid >= 4)
moel@95:             maxCoreIdPerPackage = ((cpuidData[4, 0] >> 26) & 0x3F) + 1;
moel@95:           else
moel@95:             maxCoreIdPerPackage = 1;
moel@105:           threadMaskWith = 
moel@105:             NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage);
moel@105:           coreMaskWith = NextLog2(maxCoreIdPerPackage);
moel@90:           break;
moel@90:         case Vendor.AMD:
moel@95:           uint corePerPackage;
moel@95:           if (maxCpuidExt >= 8)
moel@95:             corePerPackage = (cpuidExtData[8, 2] & 0xFF) + 1;
moel@95:           else
moel@95:             corePerPackage = 1;
moel@90:           threadMaskWith = 0;
moel@105:           coreMaskWith = NextLog2(corePerPackage);
moel@90:           break;
moel@90:         default:
moel@90:           threadMaskWith = 0;
moel@90:           coreMaskWith = 0;
moel@90:           break;
moel@90:       }
moel@90: 
moel@90:       processorId = (uint)(apicId >> (int)(coreMaskWith + threadMaskWith));
moel@95:       coreId = (uint)((apicId >> (int)(threadMaskWith)) 
moel@102:         - (processorId << (int)(coreMaskWith)));
moel@95:       threadId = apicId
moel@95:         - (processorId << (int)(coreMaskWith + threadMaskWith))
moel@95:         - (coreId << (int)(threadMaskWith)); 
moel@90:     }
moel@90: 
moel@90:     public string Name {
moel@90:       get { return name; }
moel@90:     }
moel@90: 
moel@90:     public string BrandString {
moel@90:       get { return cpuBrandString; }
moel@90:     }
moel@90: 
moel@90:     public int Thread {
moel@90:       get { return thread; }
moel@90:     }
moel@90: 
moel@90:     public Vendor Vendor {
moel@90:       get { return vendor; }
moel@90:     }
moel@90: 
moel@90:     public uint Family {
moel@90:       get { return family; }
moel@90:     }
moel@90: 
moel@90:     public uint Model {
moel@90:       get { return model; }
moel@90:     }
moel@90: 
moel@90:     public uint Stepping {
moel@90:       get { return stepping; }
moel@90:     }
moel@90: 
moel@90:     public uint ApicId {
moel@90:       get { return apicId; }
moel@90:     }
moel@90: 
moel@90:     public uint ProcessorId {
moel@90:       get { return processorId; }
moel@90:     }
moel@90: 
moel@90:     public uint CoreId {
moel@90:       get { return coreId; }
moel@90:     }
moel@90: 
moel@90:     public uint ThreadId {
moel@90:       get { return threadId; }
moel@90:     }
moel@90: 
moel@90:     public uint[,] Data {
moel@90:       get { return cpuidData; }
moel@90:     }
moel@90: 
moel@90:     public uint[,] ExtData {
moel@90:       get { return cpuidExtData; }
moel@90:     }
moel@90:   }
moel@90: }