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 . 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@195: private readonly int thread; moel@90: moel@195: private readonly Vendor vendor = Vendor.Unknown; moel@90: moel@195: private readonly string cpuBrandString = ""; moel@195: private readonly string name = ""; moel@90: moel@195: private readonly uint[,] cpuidData = new uint[0, 0]; moel@195: private readonly uint[,] cpuidExtData = new uint[0, 0]; moel@90: moel@195: private readonly uint family; moel@195: private readonly uint model; moel@195: private readonly uint stepping; moel@90: moel@195: private readonly uint apicId; moel@90: moel@195: private readonly uint threadMaskWith; moel@195: private readonly uint coreMaskWith; moel@90: moel@195: private readonly uint processorId; moel@195: private readonly uint coreId; moel@195: private readonly uint threadId; moel@90: moel@195: public const uint CPUID_0 = 0; moel@195: public const 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@195: processorId = (apicId >> (int)(coreMaskWith + threadMaskWith)); moel@195: coreId = ((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: }