private void WriteDescription(StringBuilder brand, CpuIdRegister register) { if (register == null) { return; } int eax = register.Result[0]; int ebx = register.Result[1]; int ecx = register.Result[2]; int edx = register.Result[3]; Append(brand, eax & 0xFF); Append(brand, (eax >> 8) & 0xFF); Append(brand, (eax >> 16) & 0xFF); Append(brand, (eax >> 24) & 0xFF); Append(brand, ebx & 0xFF); Append(brand, (ebx >> 8) & 0xFF); Append(brand, (ebx >> 16) & 0xFF); Append(brand, (ebx >> 24) & 0xFF); Append(brand, ecx & 0xFF); Append(brand, (ecx >> 8) & 0xFF); Append(brand, (ecx >> 16) & 0xFF); Append(brand, (ecx >> 24) & 0xFF); Append(brand, edx & 0xFF); Append(brand, (edx >> 8) & 0xFF); Append(brand, (edx >> 16) & 0xFF); Append(brand, (edx >> 24) & 0xFF); }
private void GetCpuTopology(BasicCpu cpu) { CpuIdRegister apic = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (!Features["HTT"] || !Features["CMP"] || cpu.ExtendedFunctionCount < ExtendedFeatureIds - MaxExtendedFunction) { Topology.ApicId = (apic.Result[1] >> 24) & 0xFF; Topology.CoreTopology.Add(new CpuTopo(0, CpuTopoType.Core, 0)); Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId, CpuTopoType.Package, -1)); return; } CpuIdRegister extFeatureIds = cpu.CpuRegisters.GetCpuId(ExtendedFeatureIds, 0); int apicIdSize = (extFeatureIds.Result[2] >> 12) & 0xF; int coreBits; if (apicIdSize == 0) { // There are two possible places to get this: // - from LogicalProcessorCount = CPUID(01h).EBX[23:16] (Intel); or // - from NC = CPUID(80000008h).ECX[7:0] (from AMD). int mnlp = (extFeatureIds.Result[2] >> 16) & 0xF + 1; coreBits = Log2Pof2(mnlp); } else { coreBits = apicIdSize; } long coreMask = ~(-1 << coreBits); long pkgMask = ~coreMask; if (!Features["TOPX"] || cpu.ExtendedFunctionCount < ProcessorTopo - MaxExtendedFunction) { Topology.ApicId = (apic.Result[1] >> 24) & 0xFF; Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId & coreMask, CpuTopoType.Core, coreMask)); Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId >> coreBits, CpuTopoType.Package, pkgMask)); return; } // Topology Extensions CpuIdRegister topoCpu = cpu.CpuRegisters.GetCpuId(ProcessorTopo, 0); Topology.ApicId = topoCpu.Result[0]; int smt = ((topoCpu.Result[1] >> 8) & 0xFF) + 1; int smtBits = Log2Pof2(smt); int smtMask = ~(-1 << smtBits); int core = topoCpu.Result[1] & 0xFF; // [6] describes NodesPerProcessor, but doesn't describe how to calculate the actual socket number, which // this software provides as the "Package". So the Package for now may not reflect the number of sockets if // NodesPerProcessor is non-zero (1 node per processor). int die = topoCpu.Result[2] & 0xFF; // AMD calls this the NodeId. Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId & smtMask, CpuTopoType.Smt, smtMask)); Topology.CoreTopology.Add(new CpuTopo(core, CpuTopoType.Core, coreMask)); Topology.CoreTopology.Add(new CpuTopo(die, CpuTopoType.Node, coreMask)); Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId >> coreBits, CpuTopoType.Package, pkgMask)); }
private void GetExtendedTopology(BasicCpu cpu, int leaf) { int lwidth = 0; int level = 0; CpuIdRegister topo = cpu.CpuRegisters.GetCpuId(leaf, level); while (topo != null) { int ltype = (topo.Result[2] >> 8) & 0xFF; if (ltype == 0) { break; } int cwidth = topo.Result[0] & 0xF; int width = cwidth - lwidth; int mask = ~(-1 << width); int id = (int)((Topology.ApicId >> lwidth) & mask); Topology.CoreTopology.Add(new CpuTopo(id, (CpuTopoType)ltype, mask)); level++; lwidth = cwidth; topo = cpu.CpuRegisters.GetCpuId(leaf, level); } topo = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); int pwidth = Log2Pof2((topo.Result[1] >> 16) & 0xFF); int pmask = -1 << pwidth; Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId >> pwidth, CpuTopoType.Package, pmask)); }
private void GetLegacyCacheL1Instruction(BasicCpu cpu) { if (cpu.ExtendedFunctionCount < CacheTlb - MaxExtendedFunction) { return; } CpuIdRegister cacheTlb = cpu.CpuRegisters.GetCpuId(CacheTlb, 0); if (cacheTlb == null) { return; } int ways = (cacheTlb.Result[3] >> 16) & 0xFF; if (ways == 0) { return; } if (ways == 255) { ways = 0; } int lineSize = cacheTlb.Result[3] & 0xFF; int linesPerTag = (cacheTlb.Result[3] >> 8) & 0xFF; int size = (cacheTlb.Result[3] >> 24) & 0xFF; Topology.CacheTopology.Add(new CacheTopoCpu(1, CacheType.Instruction, ways, lineSize * linesPerTag, size)); }
public static string GetType(AuthenticAmdCpu cpu) { int brand = GetBrand(cpu); if (brand == 0) { return("AMD Engineering Sample"); } int str1 = (brand & 0x780000) >> 19; int str2 = (brand & 0xF00) >> 8; int pm = ((brand & 0x7F000) >> 12) - 1; int pg = (brand & 0x800000) >> 23; CpuIdRegister ext81Reg = cpu.Registers.GetCpuId(GenericIntelCpuBase.ExtendedInformationFunction, 0); int pkgType = (ext81Reg.Result[1] >> 28) & 0xF; CpuIdRegister ext88Reg = cpu.Registers.GetCpuId(GenericIntelCpuBase.ExtendedLmApicId, 0); int nc = ext88Reg.Result[2] & 0xFF; string pma = string.Format("{0:D02}", pm); string s1 = Family11hTree[pkgType][1][pg][nc][str1].Value; if (!string.IsNullOrEmpty(s1)) { string s2 = Family11hTree[pkgType][2][pg][nc][str2].Value; if (string.IsNullOrEmpty(s2)) { return(string.Format("{0}{1}", s1, pma)); } return(string.Format("{0}{1}{2}", s1, pma, s2)); } return("AMD Processor Model Unknown"); }
/// <summary> /// Initializes a new instance of the <see cref="CpuRegisters"/> class. /// </summary> /// <param name="data">The CPUID data.</param> /// <param name="offset">The offset into <paramref name="data"/> for the node in question.</param> /// <param name="length">The length of the cpu data <paramref name="data"/> for the node in question.</param> /// <exception cref="ArgumentNullException"><paramref name="data"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> is negative</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is negative</exception> /// <exception cref="ArgumentException"> /// The <paramref name="length"/> and <paramref name="offset"/> would exceed the boundaries of the array/buffer /// <paramref name="data"/>. /// </exception> /// <remarks> /// Creates CPU data based on the native CPU data read. /// </remarks> public CpuRegisters(CpuIdLib.CpuIdInfo[] data, int offset, int length) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), "offset is negative"); } if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length), "length is negative"); } if (offset > data.Length - length) { throw new ArgumentException("The length and offset would exceed the boundaries of the array/buffer"); } for (int i = 0; i < length; i++) { int r = offset + i; CpuIdRegister result = new CpuIdRegister(data[r].veax, data[r].vecx, new int[] { data[r].peax, data[r].pebx, data[r].pecx, data[r].pedx }); AddRegister(result); } }
private int GetMaxNumberOfLogicalProcessors(BasicCpu cpu) { if (Features["HTT"]) { CpuIdRegister apic = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); return((apic.Result[1] >> 16) & 0xFF); } return(1); }
private void GetLegacyCacheL1InstructionTlb(BasicCpu cpu) { if (cpu.ExtendedFunctionCount < CacheTlb - MaxExtendedFunction) { return; } CpuIdRegister cacheTlb = cpu.CpuRegisters.GetCpuId(CacheTlb, 0); if (cacheTlb == null) { return; } int ways2m = (cacheTlb.Result[0] >> 8) & 0xFF; if (ways2m != 0) { if (ways2m == 255) { ways2m = 0; } int entries2m = cacheTlb.Result[0] & 0xFF; Topology.CacheTopology.Add(new CacheTopoTlb(1, CacheType.InstructionTlb2M4M, ways2m, entries2m)); } int ways4k = (cacheTlb.Result[1] >> 8) & 0xFF; if (ways4k != 0) { if (ways4k == 255) { ways4k = 0; } int entries4k = cacheTlb.Result[1] & 0xFF; Topology.CacheTopology.Add(new CacheTopoTlb(1, CacheType.InstructionTlb4k, ways4k, entries4k)); } if (cpu.ExtendedFunctionCount < CacheTlb1G - MaxExtendedFunction) { return; } CpuIdRegister cacheTlb1g = cpu.CpuRegisters.GetCpuId(CacheTlb1G, 0); if (cacheTlb1g == null) { return; } int ways1g = GetL2Associativity((cacheTlb1g.Result[0] >> 12) & 0xF); if (ways1g >= 0) { int entries1g = cacheTlb1g.Result[0] & 0xFFF; Topology.CacheTopology.Add(new CacheTopoTlb(1, CacheType.InstructionTlb1G, ways1g, entries1g)); } }
private string GetReservedFeatureName(CpuIdRegister register, int result, int bit) { if (register.SubFunction == 0) { return(string.Format("CPUID({0:X2}h).{1}[{2}]", register.Function, GetRegisterName(result), bit)); } return(string.Format("CPUID(EAX={0:X2}h,ECX={1:X2}h).{2}[{3}]", register.Function, register.SubFunction, GetRegisterName(result), bit)); }
/// <summary> /// Gets the cache topology leaf. /// </summary> /// <param name="leaf">The leaf number to use.</param> /// <exception cref="NotSupportedException"> /// A cache entry is fully associative, with the number of sets not one. /// </exception> /// <remarks> /// The Intel leaf 4, and AMD leaf 8000001D have the same implementation, this method provides for common code /// between the two. If the exception <see cref="NotSupportedException"/> occurs, this should be reported with a /// CPUID dump for investigation. /// </remarks> protected void GetCacheTopologyLeaf(int leaf) { int subleaf = 0; CpuIdRegister cache = m_Cpu.CpuRegisters.GetCpuId(leaf, subleaf); while (cache != null && (cache.Result[0] & 0xF) != 0) { int ltype = cache.Result[0] & 0xF; CacheType ctype = CacheType.Invalid; switch (ltype) { case 1: ctype = CacheType.Data; break; case 2: ctype = CacheType.Instruction; break; case 3: ctype = CacheType.Unified; break; } if (ctype != CacheType.Invalid) { bool fullyAssoc = (cache.Result[0] & 0x200) != 0; int sets = cache.Result[2] + 1; if (fullyAssoc && sets != 1) { throw new NotSupportedException("A cache entry is fully associative, with the number of sets not one"); } int level = (cache.Result[0] >> 5) & 0x7; int lineSize = (cache.Result[1] & 0xFFF) + 1; int partitions = ((cache.Result[1] >> 12) & 0x3FF) + 1; int ways = ((cache.Result[1] >> 22) & 0x3FF) + 1; CacheTopoCpu cacheTopoCpu = new CacheTopoCpu(level, ctype, ways, lineSize, sets, partitions); int numSharingCache = Log2Pof2(((cache.Result[0] >> 14) & 0xFFF) + 1); cacheTopoCpu.Mask = ~(-1 << numSharingCache); Topology.CacheTopology.Add(cacheTopoCpu); } subleaf++; cache = m_Cpu.CpuRegisters.GetCpuId(leaf, subleaf); } }
public override CpuIdRegister GetCpuId(int function, int subfunction) { CpuIdRegister result = base.GetCpuId(function, subfunction); if (result == null) { // It's not cached, so query the CPU for it. Note, we assume that each EAX/ECX pair always returns the // same result for the same CPU core/thread. CpuIdLib.cpuid(function, subfunction, out int eax, out int ebx, out int ecx, out int edx); result = new CpuIdRegister(function, subfunction, new int[] { eax, ebx, ecx, edx }); AddRegister(result); } return(result); }
private void GetLegacyCacheL2DataTlb(BasicCpu cpu) { if (cpu.ExtendedFunctionCount < CacheL2Tlb - MaxExtendedFunction) { return; } CpuIdRegister cacheL2Tlb = cpu.CpuRegisters.GetCpuId(CacheL2Tlb, 0); if (cacheL2Tlb == null) { return; } int ways2m = GetL2Associativity((cacheL2Tlb.Result[0] >> 28) & 0xF); if (ways2m >= 0) { int entries2m = (cacheL2Tlb.Result[0] >> 16) & 0xFFF; Topology.CacheTopology.Add(new CacheTopoTlb(2, CacheType.DataTlb2M4M, ways2m, entries2m)); } int ways4k = GetL2Associativity((cacheL2Tlb.Result[1] >> 28) & 0xF); if (ways4k >= 0) { int entries4k = (cacheL2Tlb.Result[1] >> 16) & 0xFFF; Topology.CacheTopology.Add(new CacheTopoTlb(2, CacheType.DataTlb4k, ways4k, entries4k)); } if (cpu.ExtendedFunctionCount < CacheTlb1G - MaxExtendedFunction) { return; } CpuIdRegister cacheTlb1g = cpu.CpuRegisters.GetCpuId(CacheTlb1G, 0); if (cacheTlb1g == null) { return; } int ways1g = GetL2Associativity((cacheTlb1g.Result[1] >> 28) & 0xF); if (ways1g >= 0) { int entries1g = (cacheTlb1g.Result[1] >> 16) & 0xFFF; Topology.CacheTopology.Add(new CacheTopoTlb(2, CacheType.DataTlb1G, ways1g, entries1g)); } }
protected void AddRegister(CpuIdRegister result) { if (result == null) { throw new ArgumentNullException(nameof(result)); } if (!m_Registers.TryGetValue(result.Function, out List <CpuIdRegister> registers)) { registers = new List <CpuIdRegister>(); m_Registers.Add(result.Function, registers); } registers.Add(result); m_RegisterList.Add(result); }
/// <summary> /// Tests a bit in the feature flag. /// </summary> /// <param name="feature">The name of the CPU feature, e.g. "FPU".</param> /// <param name="register">The feature register obtained from a query of CPUID.</param> /// <param name="result">The register to query, 0 is EAX, to 3 for EDX.</param> /// <param name="bit">The bit to test for.</param> /// <param name="invert">Inverts the result if <see langword="true"/>, otherwise feature is set if the bit is one.</param> protected void TestFeature(string feature, CpuIdRegister register, int result, int bit, bool invert) { bool value = (register.Result[result] & (1 << bit)) != 0; if (invert) { value = !value; } Features[feature] = value; #if DEBUG if (!m_MainFunction.Set(register.Function, register.SubFunction, result, 1 << bit)) { throw new InvalidOperationException("Bit was already set"); } #endif }
private void CheckReservedBitMask(CpuIdRegister register, int result, int mask) { int bit = 0; uint checkMask = unchecked ((uint)mask); while (checkMask != 0) { if ((checkMask & 0x01) != 0 && !m_MainFunction.Set(register.Function, register.SubFunction, result, 1 << bit)) { string message = string.Format("CPUID[EAX={0:X2}h,ECX={1:X2}h].{2}[{3}] already set", register.Function, register.SubFunction, GetRegisterName(result), bit); throw new InvalidOperationException(message); } checkMask >>= 1; bit++; } }
/// <summary> /// Adds a bit field that a feature is reserved, only if it is set. /// </summary> /// <param name="register">The feature register obtained from a query of CPUID.</param> /// <param name="result">The register to query, 0 is EAX, to 3 for EDX.</param> /// <param name="mask">The bit mask of reserved bits set to 1.</param> /// <remarks> /// This should be used after testing for all features, to ensure that any unknown features are tested for and /// set with the generic name <c>CPUID(XXh).REG[bit]</c> or <c>CPUID(EAX=XXh,ECX=XXh).REG[bit]</c>, where the /// REG is one of EAX, EBX, ECX, EDX and the bit is the bit given in <paramref name="mask"/> which is a bit /// field of reserved features. CPUs in the future may set these bits and so it's useful to see if there are new /// features which are not defined. Bits that are "don't care" in the specifications should not be part of the /// bit field, but as most bits are "reserved" are usually zero, so that future processors can set them as set /// when a new feature is defined. /// </remarks> protected void ReservedFeature(CpuIdRegister register, int result, int mask) { #if DEBUG CheckReservedBitMask(register, result, mask); #endif int bit = 0; uint checkMask = unchecked ((uint)(mask & register.Result[result])); while (checkMask != 0) { if ((checkMask & 0x01) != 0) { Features[GetReservedFeatureName(register, result, bit)] = true; } checkMask >>= 1; // Unsigned means zero is rolled into MSB, so we don't need to clear the MSB. bit++; } }
private string GetVendorId(CpuIdRegister register) { char[] vendorId = new char[12]; int ebx = register.Result[1]; int ecx = register.Result[2]; int edx = register.Result[3]; vendorId[0] = (char)(ebx & 0xFF); vendorId[1] = (char)((ebx >> 8) & 0xFF); vendorId[2] = (char)((ebx >> 16) & 0xFF); vendorId[3] = (char)((ebx >> 24) & 0xFF); vendorId[4] = (char)(edx & 0xFF); vendorId[5] = (char)((edx >> 8) & 0xFF); vendorId[6] = (char)((edx >> 16) & 0xFF); vendorId[7] = (char)((edx >> 24) & 0xFF); vendorId[8] = (char)(ecx & 0xFF); vendorId[9] = (char)((ecx >> 8) & 0xFF); vendorId[10] = (char)((ecx >> 16) & 0xFF); vendorId[11] = (char)((ecx >> 24) & 0xFF); return(new string(vendorId)); }
private void GetProcessorSignature(BasicCpu cpu) { if (cpu.FunctionCount == 0) { return; } CpuIdRegister feature = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (feature == null) { return; } m_ProcessorSignature = feature.Result[0] & 0x0FFF3FFF; m_ExtendedFamily = (m_ProcessorSignature >> 20) & 0xFF; m_ExtendedModel = (m_ProcessorSignature >> 16) & 0xF; m_ProcessorType = (m_ProcessorSignature >> 12) & 0x3; m_FamilyCode = (m_ProcessorSignature >> 8) & 0xF; m_ModelNumber = (m_ProcessorSignature >> 4) & 0xF; m_SteppingId = m_ProcessorSignature & 0xF; }
private void AddCpuRegister(XmlNode registerNode) { if (!TryGetHexValue(registerNode.Attributes["eax"]?.Value, out int function)) { return; } if (!TryGetHexValue(registerNode.Attributes["ecx"]?.Value, out int subfunction)) { return; } string registerOutput = registerNode.InnerText; if (string.IsNullOrWhiteSpace(registerOutput)) { return; } string[] registerValues = registerOutput.Split(','); if (registerValues.Length != 4) { return; } int[] registers = new int[4]; int i = 0; foreach (string registerValue in registerValues) { if (!TryGetHexValue(registerValue, out registers[i])) { return; } i++; } CpuIdRegister result = new CpuIdRegister(function, subfunction, registers); AddRegister(result); }
private void GetProcessorSignature(BasicCpu cpu) { if (cpu.FunctionCount == 0) { return; } CpuIdRegister feature = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (feature == null) { return; } int eax = feature.Result[0]; int ebx = feature.Result[1]; if ((eax & 0xf00) == 0x300) { // Sounds crazy, but someone's emulating an i386. Major Stepping is the Model property. m_ProcessorSignature = eax & 0xFFFF; m_ProcessorType = (m_ProcessorSignature >> 12) & 0xF; m_FamilyCode = (m_ProcessorSignature >> 8) & 0xF; m_ModelNumber = (m_ProcessorSignature >> 4) & 0xF; m_SteppingId = m_ProcessorSignature & 0xF; } else { m_ProcessorSignature = eax & 0x0FFF3FFF; m_ExtendedFamily = (m_ProcessorSignature >> 20) & 0xFF; m_ExtendedModel = (m_ProcessorSignature >> 16) & 0xF; m_ProcessorType = (m_ProcessorSignature >> 12) & 0x3; m_FamilyCode = (m_ProcessorSignature >> 8) & 0xF; m_ModelNumber = (m_ProcessorSignature >> 4) & 0xF; m_SteppingId = m_ProcessorSignature & 0xF; m_Brand = ebx & 0xFF; } }
private void FindExtendedFeatures(BasicCpu cpu) { if (cpu.ExtendedFunctionCount < 1) { return; } CpuIdRegister extfeat = cpu.CpuRegisters.GetCpuId(ExtendedInformationFunction, 0); if (extfeat != null) { TestFeature("AHF64", extfeat, 2, 0); TestFeature("ABM", extfeat, 2, 5); TestFeature("PREFETCHW", extfeat, 2, 8); ReservedFeature(extfeat, 2, unchecked ((int)0xFFFFFEDE)); TestFeature("SYSCALL", extfeat, 3, 11); TestFeature("XD", extfeat, 3, 20); TestFeature("1GB_PAGE", extfeat, 3, 26); TestFeature("RDTSCP", extfeat, 3, 27); TestFeature("LM", extfeat, 3, 29); ReservedFeature(extfeat, 3, unchecked ((int)0xD3EFF7FF)); } }
private void GetLegacyTopology(CpuIdRegister apic, CpuIdRegister topo) { int maxApic = (apic.Result[1] >> 16) & 0xFF; int maxCore = ((topo.Result[0] >> 26) & 0x3F) + 1; int smtWidth = Log2Pof2(maxApic / maxCore); long smtMask = ~(-1 << smtWidth); long smtId = Topology.ApicId & smtMask; Topology.CoreTopology.Add(new CpuTopo(smtId, CpuTopoType.Smt, smtMask)); int coreWidth = Log2Pof2(maxCore); long coreMask = ~(-1 << coreWidth); long coreId = (Topology.ApicId >> smtWidth) & coreMask; Topology.CoreTopology.Add(new CpuTopo(coreId, CpuTopoType.Core, coreMask)); int pkgWidth = smtWidth + coreWidth; // Should be the same as maxApic. long pkgId = Topology.ApicId >> pkgWidth; long pkgMask = -1 << pkgWidth; Topology.CoreTopology.Add(new CpuTopo(pkgId, CpuTopoType.Package, pkgMask)); }
private void GetCacheTopology(BasicCpu cpu) { if (cpu.FunctionCount >= LegacyCache) { bool leafTlb = false; bool leafCpu = false; bool noExtraCache = false; CpuIdRegister cache = cpu.CpuRegisters.GetCpuId(LegacyCache, 0); if (cache != null && (cache.Result[0] & 0xFF) == 0x01) { GetLegacyCacheTopology(cache.Result[0] & unchecked ((int)0xFFFFFF00), ref leafCpu, ref leafTlb, ref noExtraCache); GetLegacyCacheTopology(cache.Result[1], ref leafCpu, ref leafTlb, ref noExtraCache); GetLegacyCacheTopology(cache.Result[2], ref leafCpu, ref leafTlb, ref noExtraCache); GetLegacyCacheTopology(cache.Result[3], ref leafCpu, ref leafTlb, ref noExtraCache); } FixLegacyCacheMask(noExtraCache); if (leafCpu && cpu.FunctionCount > LegacyTopology) { GetCacheTopologyLeaf(LegacyTopology); } } }
private void Initialize(ICpuRegisters register) { CpuRegisters = register; CpuIdRegister vendorFunction = register.GetCpuId(VendorIdFunction, 0); if (vendorFunction == null) { return; } FunctionCount = vendorFunction.Result[0]; VendorId = GetVendorId(vendorFunction); CpuIdRegister extendedFunction = register.GetCpuId(ExtendedFunction, 0); if (extendedFunction == null) { return; } if ((extendedFunction.Result[0] & ExtendedFunction) != 0) { ExtendedFunctionCount = extendedFunction.Result[0] & 0x7FFFFFFF; } }
private void FindFeatures(BasicCpu cpu) { if (cpu.FunctionCount < FeatureInformationFunction) { return; } CpuIdRegister features = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (features != null) { TestFeature("FPU", features, 3, 0); TestFeature("VME", features, 3, 1); TestFeature("DE", features, 3, 2); TestFeature("PSE", features, 3, 3); TestFeature("TSC", features, 3, 4); TestFeature("MSR", features, 3, 5); TestFeature("PAE", features, 3, 6); TestFeature("MCE", features, 3, 7); TestFeature("CX8", features, 3, 8); TestFeature("APIC", features, 3, 9); TestFeature("SEP", features, 3, 11); TestFeature("MTRR", features, 3, 12); TestFeature("PGE", features, 3, 13); TestFeature("MCA", features, 3, 14); TestFeature("CMOV", features, 3, 15); TestFeature("PAT", features, 3, 16); TestFeature("PSE-36", features, 3, 17); TestFeature("PSN", features, 3, 18); TestFeature("CLFSH", features, 3, 19); TestFeature("DS", features, 3, 21); TestFeature("ACPI", features, 3, 22); TestFeature("MMX", features, 3, 23); TestFeature("FXSR", features, 3, 24); TestFeature("SSE", features, 3, 25); TestFeature("SSE2", features, 3, 26); TestFeature("SS", features, 3, 27); TestFeature("HTT", features, 3, 28); TestFeature("TM", features, 3, 29); TestFeature("IA64", features, 3, 30); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("PBE", features, 3, 31); if (Features["SEP"] && ProcessorSignature < 0x633) { Features["SEP"] = false; } ReservedFeature(features, 3, 0x00100400); TestFeature("SSE3", features, 2, 0); TestFeature("PCLMULQDQ", features, 2, 1); TestFeature("DTES64", features, 2, 2); TestFeature("MONITOR", features, 2, 3); TestFeature("DS-CPL", features, 2, 4); TestFeature("VMX", features, 2, 5); TestFeature("SMX", features, 2, 6); TestFeature("EIST", features, 2, 7); TestFeature("TM2", features, 2, 8); TestFeature("SSSE3", features, 2, 9); TestFeature("CNXT-ID", features, 2, 10); TestFeature("SDBG", features, 2, 11); TestFeature("FMA", features, 2, 12); TestFeature("CMPXCHG16B", features, 2, 13); TestFeature("xTPR", features, 2, 14); TestFeature("PDCM", features, 2, 15); TestFeature("PCID", features, 2, 17); TestFeature("DCA", features, 2, 18); TestFeature("SSE4.1", features, 2, 19); TestFeature("SSE4.2", features, 2, 20); TestFeature("x2APIC", features, 2, 21); TestFeature("MOVBE", features, 2, 22); TestFeature("POPCNT", features, 2, 23); TestFeature("TSC-DEADLINE", features, 2, 24); TestFeature("AESNI", features, 2, 25); TestFeature("XSAVE", features, 2, 26); TestFeature("OSXSAVE", features, 2, 27); TestFeature("AVX", features, 2, 28); TestFeature("F16C", features, 2, 29); TestFeature("RDRAND", features, 2, 30); TestFeature("HYPERVISOR", features, 2, 31); // Wikipedia https://en.wikipedia.org/wiki/CPUID ReservedFeature(features, 2, 0x00010000); } FindExtendedFeatures(cpu); if (cpu.FunctionCount < ExtendedFeatureFunction) { return; } CpuIdRegister features7 = cpu.CpuRegisters.GetCpuId(ExtendedFeatureFunction, 0); if (features7 != null) { TestFeature("FSGSBASE", features7, 1, 0); TestFeature("IA32_TSC_ADJUST", features7, 1, 1); TestFeature("SGX", features7, 1, 2); TestFeature("BMI1", features7, 1, 3); TestFeature("HLE", features7, 1, 4); TestFeature("AVX2", features7, 1, 5); TestFeature("FDP_EXCPTN_ONLY", features7, 1, 6); TestFeature("SMEP", features7, 1, 7); TestFeature("BMI2", features7, 1, 8); TestFeature("ERMS", features7, 1, 9); TestFeature("INVPCID", features7, 1, 10); TestFeature("RTM", features7, 1, 11); TestFeature("PQM", features7, 1, 12); TestFeature("FPU-CS Dep", features7, 1, 13); TestFeature("MPX", features7, 1, 14); TestFeature("PQE", features7, 1, 15); TestFeature("AVX512F", features7, 1, 16); TestFeature("AVX512DQ", features7, 1, 17); TestFeature("RDSEED", features7, 1, 18); TestFeature("ADX", features7, 1, 19); TestFeature("SMAP", features7, 1, 20); TestFeature("AVX512_IFMA", features7, 1, 21); TestFeature("CLFLUSHOPT", features7, 1, 23); TestFeature("CLWB", features7, 1, 24); TestFeature("INTEL_PT", features7, 1, 25); TestFeature("AVX512PF", features7, 1, 26); TestFeature("AVX512ER", features7, 1, 27); TestFeature("AVX512CD", features7, 1, 28); TestFeature("SHA", features7, 1, 29); TestFeature("AVX512BW", features7, 1, 30); TestFeature("AVX512VL", features7, 1, 31); ReservedFeature(features7, 1, 0x00400000); TestFeature("PREFETCHWT1", features7, 2, 0); TestFeature("AVX512_VBMI", features7, 2, 1); TestFeature("UMIP", features7, 2, 2); TestFeature("PKU", features7, 2, 3); TestFeature("OSPKE", features7, 2, 4); TestFeature("WAITPKG", features7, 2, 5); TestFeature("AVX512_VBMI2", features7, 2, 6); TestFeature("CET_SS", features7, 2, 7); TestFeature("GFNI", features7, 2, 8); TestFeature("VAES", features7, 2, 9); TestFeature("VPCLMULQDQ", features7, 2, 10); TestFeature("AVX512_VNNI", features7, 2, 11); TestFeature("AVX512_BITALG", features7, 2, 12); TestFeature("AVX512_VPOPCNTDQ", features7, 2, 14); TestFeature("5L_PAGE", features7, 2, 15); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("RDPID", features7, 2, 22); TestFeature("CLDEMOTE", features7, 2, 25); TestFeature("MOVDIRI", features7, 2, 27); TestFeature("MOVDIR64B", features7, 2, 28); TestFeature("ENQCMD", features7, 2, 29); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("SGX_LC", features7, 2, 30); TestFeature("PKS", features7, 2, 31); ReservedFeature(features7, 2, 0x05BF2000); TestFeature("AVX512_4VNNIW", features7, 3, 2); TestFeature("AVX512_4FMAPS", features7, 3, 3); TestFeature("FSRM", features7, 3, 4); TestFeature("AVX512_VP2INTERSECT", features7, 3, 8); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("SRBDS_CTRL", features7, 3, 9); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("MD_CLEAR", features7, 3, 10); TestFeature("TSX_FORCE_ABORT", features7, 3, 13); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("SERIALIZE", features7, 3, 14); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("Hybrid", features7, 3, 15); TestFeature("TSXLDTRK", features7, 3, 16); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("PCONFIG", features7, 3, 18); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("LBR", features7, 3, 19); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("CET_IBT", features7, 3, 20); TestFeature("AMX_BF16", features7, 3, 22); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("AMX_TILE", features7, 3, 24); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("AMX_INT8", features7, 3, 25); // Wikipedia https://en.wikipedia.org/wiki/CPUID TestFeature("IBRS_IBPB", features7, 3, 26); TestFeature("STIBP", features7, 3, 27); TestFeature("L1D_FLUSH", features7, 3, 28); TestFeature("IA32_ARCH_CAPABILITIES", features7, 3, 29); TestFeature("IA32_CORE_CAPABILITIES", features7, 3, 30); TestFeature("SSBD", features7, 3, 31); ReservedFeature(features7, 3, 0x00A218E3); if (features7.Result[0] > 0) { CpuIdRegister features7s1 = cpu.CpuRegisters.GetCpuId(ExtendedFeatureFunction, 1); if (features7s1 != null) { TestFeature("AVX_BF16", features7s1, 0, 5); // Wikipedia https://en.wikipedia.org/wiki/CPUID ReservedFeature(features7s1, 0, unchecked ((int)0xFFFFFFDF)); ReservedFeature(features7s1, 1, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7s1, 2, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7s1, 3, unchecked ((int)0xFFFFFFFF)); } for (int subfunction = 2; subfunction < features7.Result[0]; subfunction++) { CpuIdRegister features7sX = cpu.CpuRegisters.GetCpuId(ExtendedFeatureFunction, subfunction); if (features7sX != null) { ReservedFeature(features7sX, 0, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 1, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 2, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 3, unchecked ((int)0xFFFFFFFF)); } } } } if (cpu.FunctionCount < ExtendedProcessorState) { return; } CpuIdRegister features13 = cpu.CpuRegisters.GetCpuId(ExtendedProcessorState, 1); if (features13 != null) { TestFeature("XSAVEOPT", features13, 0, 0); TestFeature("XSAVEC", features13, 0, 1); TestFeature("XGETBV", features13, 0, 2); TestFeature("XSAVES", features13, 0, 3); } }
private void GetCpuTopology(BasicCpu cpu) { if (!Features["HTT"] || !Features["APIC"]) { if (Features["x2APIC"] && cpu.FunctionCount >= ExtendedTopology) { CpuIdRegister x2apic = cpu.CpuRegisters.GetCpuId(ExtendedTopology, 0); Topology.ApicId = x2apic.Result[3]; } else if (cpu.FunctionCount >= FeatureInformationFunction) { CpuIdRegister apic = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); Topology.ApicId = (apic.Result[1] >> 24) & 0xFF; } else { Topology.ApicId = -1; return; } int mnlpbits = Log2Pof2(GetMaxNumberOfLogicalProcessors(cpu)); Topology.CoreTopology.Add(new CpuTopo(0, CpuTopoType.Core, ~(-1 << mnlpbits))); Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId, CpuTopoType.Package, -1 << mnlpbits)); return; } if (Features["x2APIC"] && cpu.FunctionCount >= ExtendedTopology2) { CpuIdRegister x2apic = cpu.CpuRegisters.GetCpuId(ExtendedTopology, 0); Topology.ApicId = x2apic.Result[3]; GetExtendedTopology(cpu, ExtendedTopology2); } else if (Features["x2APIC"] && cpu.FunctionCount >= ExtendedTopology) { CpuIdRegister x2apic = cpu.CpuRegisters.GetCpuId(ExtendedTopology, 0); Topology.ApicId = x2apic.Result[3]; GetExtendedTopology(cpu, ExtendedTopology); } else if (cpu.FunctionCount >= LegacyTopology) { CpuIdRegister apic = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); CpuIdRegister topo = cpu.CpuRegisters.GetCpuId(LegacyTopology, 0); Topology.ApicId = (apic.Result[1] >> 24) & 0xFF; GetLegacyTopology(apic, topo); } else { CpuIdRegister apic = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (Features["APIC"]) { Topology.ApicId = (apic.Result[1] >> 24) & 0xFF; } else { Topology.ApicId = 0; } int mnlpbits = Log2Pof2(GetMaxNumberOfLogicalProcessors(cpu)); Topology.CoreTopology.Add(new CpuTopo(0, CpuTopoType.Core, ~(-1 << mnlpbits))); Topology.CoreTopology.Add(new CpuTopo(Topology.ApicId, CpuTopoType.Package, -1 << mnlpbits)); } }
private void FindExtendedFeatures(BasicCpu cpu) { if (cpu.ExtendedFunctionCount < 1) { return; } CpuIdRegister extfeat = cpu.CpuRegisters.GetCpuId(ExtendedInformationFunction, 0); if (extfeat != null) { TestFeature("AHF64", extfeat, 2, 0); TestFeature("CMP", extfeat, 2, 1); // CmpLegacy TestFeature("SVM", extfeat, 2, 2); TestFeature("ExtApicSpace", extfeat, 2, 3); TestFeature("AM", extfeat, 2, 4); TestFeature("ABM", extfeat, 2, 5); TestFeature("SSE4A", extfeat, 2, 6); TestFeature("MisAlignSSE", extfeat, 2, 7); TestFeature("PREFETCHW", extfeat, 2, 8); TestFeature("OSVW", extfeat, 2, 9); TestFeature("IBS", extfeat, 2, 10); TestFeature("XOP", extfeat, 2, 11); TestFeature("SKINIT", extfeat, 2, 12); TestFeature("WDT", extfeat, 2, 13); TestFeature("LWP", extfeat, 2, 15); TestFeature("FMA4", extfeat, 2, 16); TestFeature("TCE", extfeat, 2, 17); // [9] TestFeature("NODEID", extfeat, 2, 19); // [9] TestFeature("TBM", extfeat, 2, 21); // [9] TestFeature("TOPX", extfeat, 2, 22); // TopologyExtensions TestFeature("PerfCtrExtCore", extfeat, 2, 23); TestFeature("PerfCtrExtNB", extfeat, 2, 24); TestFeature("StreamPerfMon", extfeat, 2, 25); // [6a], now reserved TestFeature("DBE", extfeat, 2, 26); TestFeature("PerfTSC", extfeat, 2, 27); TestFeature("PerfL2I", extfeat, 2, 28); // Sandpile.org TestFeature("MONITORX", extfeat, 2, 29); TestFeature("ADMSK", extfeat, 2, 30); // [10] ReservedFeature(extfeat, 2, unchecked ((int)0x80144000)); TestFeature("SYSCALL", extfeat, 3, 11); TestFeature("MP", extfeat, 3, 19); // [17a], now reserved TestFeature("XD", extfeat, 3, 20); TestFeature("MMXEXT", extfeat, 3, 22); TestFeature("FFXSR", extfeat, 3, 25); TestFeature("1GB_PAGE", extfeat, 3, 26); TestFeature("RDTSCP", extfeat, 3, 27); TestFeature("LM", extfeat, 3, 29); TestFeature("3DNowExt", extfeat, 3, 30); TestFeature("3DNow", extfeat, 3, 31); // 3DNowPrefetch ECX[8] || EDX[29] || EDX[31] Features["PREFETCHW"] |= Features["LM"] || Features["3DNow"]; // The following are duplicated from 0000_0001h.EDX // 0: FPU 8: CX8 16: PAT 24: FXSR // 1: VME 9: APIC 17: PSE-36 25: // 2: DE 10: (RSVD) 18: (RSVD) 26: // 3: PSE 11: SEP 19: 27: // 4: TSC 12: MTRR 20: 28: (RSVD) // 5: MSR 13: PGE 21: (RSVD) 29: // 6: PAE 14: MCA 22: 30: // 7: MCE 15: CMOV 23: MMX 31: ReservedFeature(extfeat, 3, 0x10240400); } if (cpu.ExtendedFunctionCount < ExtendedLmApicId - MaxExtendedFunction) { return; } CpuIdRegister extfeat8 = cpu.CpuRegisters.GetCpuId(ExtendedLmApicId, 0); if (extfeat8 != null) { TestFeature("CLZERO", extfeat8, 1, 0); TestFeature("IRPERF", extfeat8, 1, 1); // Instruction Retired Counter TestFeature("ASRFPEP", extfeat8, 1, 2); // Error Pointer Zero/Restore TestFeature("INVLPGB", extfeat8, 1, 3); TestFeature("RDPRU", extfeat8, 1, 4); TestFeature("MBE", extfeat8, 1, 6); // [10] TestFeature("MCOMMIT", extfeat8, 1, 8); TestFeature("WBNOINVD", extfeat8, 1, 9); TestFeature("IBPB", extfeat8, 1, 12); // [10] TestFeature("INT_WBINVD", extfeat8, 1, 13); // [10] TestFeature("IBRS", extfeat8, 1, 14); // [10] TestFeature("STIBP", extfeat8, 1, 15); // [10] TestFeature("IBRS_ALL", extfeat8, 1, 16); // Sandpile.org TestFeature("STIBP_ALL", extfeat8, 1, 17); // [10] TestFeature("IBRS_PREF", extfeat8, 1, 18); // [10] TestFeature("IBRS_SMP", extfeat8, 1, 19); // [10] TestFeature("EFER.LMSLE", extfeat8, 1, 20); TestFeature("INVLPGB_NESTED", extfeat8, 1, 21); TestFeature("PPIN", extfeat8, 1, 23); // [10] TestFeature("SSBD", extfeat8, 1, 24); // [10] ReservedFeature(extfeat8, 1, unchecked ((int)0xFE400CA0)); } if (cpu.ExtendedFunctionCount < ExtendedEncMem - MaxExtendedFunction) { return; } CpuIdRegister extfeat1f = cpu.CpuRegisters.GetCpuId(ExtendedEncMem, 0); if (extfeat1f != null) { TestFeature("SME", extfeat1f, 0, 0); TestFeature("SEV", extfeat1f, 0, 1); TestFeature("PageFlushMsr", extfeat1f, 0, 2); TestFeature("ES", extfeat1f, 0, 3); TestFeature("SNP", extfeat1f, 0, 4); TestFeature("VMPL", extfeat1f, 0, 5); TestFeature("VTE", extfeat1f, 0, 16); ReservedFeature(extfeat1f, 0, unchecked ((int)0xFFFEFFC0)); } }
private void FindFeatures(BasicCpu cpu) { if (cpu.FunctionCount < FeatureInformationFunction) { return; } CpuIdRegister features = cpu.CpuRegisters.GetCpuId(FeatureInformationFunction, 0); if (features != null) { TestFeature("FPU", features, 3, 0); TestFeature("VME", features, 3, 1); TestFeature("DE", features, 3, 2); TestFeature("PSE", features, 3, 3); TestFeature("TSC", features, 3, 4); TestFeature("MSR", features, 3, 5); TestFeature("PAE", features, 3, 6); TestFeature("MCE", features, 3, 7); TestFeature("CX8", features, 3, 8); TestFeature("SEP", features, 3, 11); TestFeature("MTRR", features, 3, 12); TestFeature("MCA", features, 3, 14); TestFeature("CMOV", features, 3, 15); TestFeature("PAT", features, 3, 16); TestFeature("PSE-36", features, 3, 17); TestFeature("CLFSH", features, 3, 19); TestFeature("MMX", features, 3, 23); TestFeature("FXSR", features, 3, 24); TestFeature("SSE", features, 3, 25); TestFeature("SSE2", features, 3, 26); TestFeature("HTT", features, 3, 28); if (Family == 5 && Model == 0) { // [17] says AMD K5 Model 0, bit 9 is for PGE, where bit 13 is reserved. TestFeature("PGE", features, 3, 9); } else { TestFeature("APIC", features, 3, 9); TestFeature("PGE", features, 3, 13); } ReservedFeature(features, 3, unchecked ((int)0xE8740400)); TestFeature("SSE3", features, 2, 0); TestFeature("PCLMULQDQ", features, 2, 1); TestFeature("MONITOR", features, 2, 3); TestFeature("SSSE3", features, 2, 9); TestFeature("FMA", features, 2, 12); TestFeature("CMPXCHG16B", features, 2, 13); TestFeature("PCID", features, 2, 17); TestFeature("SSE4.1", features, 2, 19); TestFeature("SSE4.2", features, 2, 20); TestFeature("x2APIC", features, 2, 21); // [8] TestFeature("MOVBE", features, 2, 22); TestFeature("POPCNT", features, 2, 23); TestFeature("AESNI", features, 2, 25); TestFeature("XSAVE", features, 2, 26); TestFeature("OSXSAVE", features, 2, 27); TestFeature("AVX", features, 2, 28); TestFeature("F16C", features, 2, 29); TestFeature("RDRAND", features, 2, 30); TestFeature("HYPERVISOR", features, 2, 31); ReservedFeature(features, 2, 0x0105CDF4); } FindExtendedFeatures(cpu); if (cpu.FunctionCount < ExtendedFeatureFunction) { return; } CpuIdRegister features7 = cpu.CpuRegisters.GetCpuId(ExtendedFeatureFunction, 0); if (features7 != null) { TestFeature("FSGSBASE", features7, 1, 0); TestFeature("BMI1", features7, 1, 3); TestFeature("AVX2", features7, 1, 5); TestFeature("SMEP", features7, 1, 7); TestFeature("BMI2", features7, 1, 8); TestFeature("INVPCID", features7, 1, 10); TestFeature("PQM", features7, 1, 12); TestFeature("PQE", features7, 1, 15); TestFeature("RDSEED", features7, 1, 18); TestFeature("ADX", features7, 1, 19); TestFeature("SMAP", features7, 1, 20); // [6] has an error, bit 22 is not RDPID as given on p606 TestFeature("CLFLUSHOPT", features7, 1, 23); TestFeature("CLWB", features7, 1, 24); TestFeature("SHA", features7, 1, 29); ReservedFeature(features7, 1, unchecked ((int)0xDE636A56)); TestFeature("UMIP", features7, 2, 2); TestFeature("PKU", features7, 2, 3); TestFeature("OSPKE", features7, 2, 4); TestFeature("CET_SS", features7, 2, 7); TestFeature("VAES", features7, 2, 9); TestFeature("VPCLMULQDQ", features7, 2, 10); ReservedFeature(features7, 2, unchecked ((int)0xFFBFF963)); TestFeature("RDPID", features7, 3, 22); ReservedFeature(features7, 3, unchecked ((int)0xFFBFFFFF)); if (features7.Result[0] > 0) { for (int subfunction = 1; subfunction < features7.Result[0]; subfunction++) { CpuIdRegister features7sX = cpu.CpuRegisters.GetCpuId(ExtendedFeatureFunction, subfunction); if (features7sX != null) { ReservedFeature(features7sX, 0, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 1, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 2, unchecked ((int)0xFFFFFFFF)); ReservedFeature(features7sX, 3, unchecked ((int)0xFFFFFFFF)); } } } } if (cpu.FunctionCount < ExtendedProcessorState) { return; } CpuIdRegister features13 = cpu.CpuRegisters.GetCpuId(ExtendedProcessorState, 1); if (features13 != null) { TestFeature("XSAVEOPT", features13, 0, 0); TestFeature("XSAVEC", features13, 0, 1); TestFeature("XGETBV", features13, 0, 2); TestFeature("XSAVES", features13, 0, 3); } }
/// <summary> /// Tests a bit in the feature flag. /// </summary> /// <param name="feature">The name of the CPU feature, e.g. "FPU".</param> /// <param name="register">The feature register obtained from a query of CPUID.</param> /// <param name="result">The register to query, 0 is EAX, to 3 for EDX.</param> /// <param name="bit">The bit to test for.</param> protected void TestFeature(string feature, CpuIdRegister register, int result, int bit) { TestFeature(feature, register, result, bit, false); }