moel@90: /* moel@90: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@90: moel@427: Copyright (C) 2009-2014 Michael Möller moel@344: 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@427: if (thread >= 64) moel@167: throw new ArgumentOutOfRangeException("thread"); moel@238: ulong mask = 1UL << thread; moel@90: moel@236: if (Opcode.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@236: if (Opcode.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@236: Opcode.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@236: Opcode.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@236: if (Opcode.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@329: nameBuilder.Replace("(tm)", ""); moel@90: nameBuilder.Replace("CPU", ""); moel@329: nameBuilder.Replace("Quad-Core Processor", ""); moel@329: nameBuilder.Replace("Six-Core Processor", ""); moel@329: nameBuilder.Replace("Eight-Core Processor", ""); 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: }