/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.x86; import org.jnode.util.NumberUtils; import org.jnode.vm.CpuID; import org.vmmagic.unboxed.Word; /** * Class used to identify the current processor. * * @author Ewout Prangsma (epr@users.sourceforge.net) */ public class X86CpuID extends CpuID { public static final int FEAT_FPU = (1 << 0); public static final int FEAT_VME = (1 << 1); public static final int FEAT_DE = (1 << 2); public static final int FEAT_PSE = (1 << 3); public static final int FEAT_TSC = (1 << 4); public static final int FEAT_MSR = (1 << 5); public static final int FEAT_PAE = (1 << 6); public static final int FEAT_MCE = (1 << 7); public static final int FEAT_CX8 = (1 << 8); public static final int FEAT_APIC = (1 << 9); public static final int FEAT_SEP = (1 << 11); public static final int FEAT_MTRR = (1 << 12); public static final int FEAT_PGE = (1 << 13); public static final int FEAT_MCA = (1 << 14); public static final int FEAT_CMOV = (1 << 15); public static final int FEAT_PAT = (1 << 16); public static final int FEAT_PSE36 = (1 << 17); public static final int FEAT_PSN = (1 << 18); public static final int FEAT_CLFSH = (1 << 19); public static final int FEAT_DS = (1 << 21); public static final int FEAT_ACPI = (1 << 22); public static final int FEAT_MMX = (1 << 23); public static final int FEAT_FXSR = (1 << 24); public static final int FEAT_SSE = (1 << 25); public static final int FEAT_SSE2 = (1 << 26); public static final int FEAT_SS = (1 << 27); public static final int FEAT_HTT = (1 << 28); public static final int FEAT_TM = (1 << 29); public static final int FEAT_PBE = (1 << 31); // Extended features public static final long FEAT_PNI = (1L << 32); // Prescott New Instructions (SSE3) public static final long FEAT_PCLMULQDQ = (1L << 33); // PCLMULQDQ support public static final long FEAT_DTES64 = (1L << 34); // 64-bit debug store (edx bit 21) public static final long FEAT_MONITOR = (1L << 35); // MONITOR and MWAIT instructions (SSE3) public static final long FEAT_DS_CPL = (1L << 36); // CPL qualified debug store public static final long FEAT_VMX = (1L << 37); // Virtual Machine eXtensions public static final long FEAT_SMX = (1L << 38); // Safer Mode Extensions (LaGrande) public static final long FEAT_EST = (1L << 39); // Enhanced SpeedStep public static final long FEAT_TM2 = (1L << 40); // Thermal Monitor 2 public static final long FEAT_SSSE3 = (1L << 41); // Supplemental SSE3 instructions public static final long FEAT_CNXTID = (1L << 42); // Context ID public static final long FEAT_HYPERVISOR = (1L << 63); // Running on a hypervisor (always 0 on a real CPU, but also with some hypervisors) // Family codes public static final int FAM_486 = 0x04; public static final int FAM_PENTIUM = 0x05; public static final int FAM_PENTIUM_2_3 = 0x06; public static final int FAM_PENTIUM4 = 0x0F; /** * The cpu id data */ private final int[] data; /** * Vendor of the processor */ private String vendor; private final int steppingID; private final int model; private final int family; private final int features; private final long exFeatures; private final String brand; private String hypervisorVendor; /** * Create a cpu id that contains the data of a processor identified by the given processor id. * * @param procId "i586", "pentium" for Pentium, "i686", "pentium2" for Pentium II, "pentium3" for * Pentium III "pentium4" for Pentium 4 can be null * @return New cpu id. */ public static X86CpuID createID(String procId) { // Handle default if (procId == null) { procId = "pentium"; } final int[] id; if (procId.equals("pentium4")) { // Pentium 4 id = new int[12]; id[0] = 0x02; id[7] = FEAT_FPU | FEAT_PSE | FEAT_CMOV | FEAT_SSE | FEAT_SSE2; } else if (procId.equals("pentium3")) { // Pentium 3 id = new int[16]; id[0] = 0x03; id[7] = FEAT_FPU | FEAT_PSE | FEAT_CMOV | FEAT_SSE; } else if (procId.equals("pentium2")) { // Pentium 2 id = new int[12]; id[0] = 0x02; id[7] = FEAT_FPU | FEAT_PSE | FEAT_CMOV; } else { // Pentium id = new int[8]; id[0] = 0x01; id[7] = FEAT_FPU | FEAT_PSE; } // Set name GenuineIntel id[1] = 0x756e6547; id[2] = 0x6c65746e; id[3] = 0x49656e69; return new X86CpuID(id, "?"); } /** * Initialize this instance */ X86CpuID(int[] data, String brand) { this.data = data; this.brand = brand; final int eax = data[4]; this.steppingID = eax & 0xF; this.model = (eax >> 4) & 0xF; this.family = (eax >> 8) & 0xF; this.features = data[7]; this.exFeatures = features | (((long) data[6]) << 32); } /** * Load a new CpuID from the current CPU. * * @return */ static X86CpuID loadFromCurrentCpu() { // Load low values (eax=0) int[] regs = new int[4]; UnsafeX86.getCPUID(Word.zero(), regs); final int count = regs[0] + 1; int[] data = new int[count * 4]; int index = 0; for (int i = 0; i < count; i++) { UnsafeX86.getCPUID(Word.fromIntZeroExtend(i), regs); data[index++] = regs[0]; data[index++] = regs[1]; data[index++] = regs[2]; data[index++] = regs[3]; } // Load extended functions (0x80000000) String brand = "?"; final Word extendedBase = Word.fromIntZeroExtend(0x80000000); UnsafeX86.getCPUID(extendedBase, regs); Word max = Word.fromIntZeroExtend(regs[0]); if (max.GE(extendedBase.add(4))) { // Load brand 0x80000002..0x80000004 final StringBuilder buf = new StringBuilder(); for (int i = 0; i < 3; i++) { UnsafeX86.getCPUID(extendedBase.add(2 + i), regs); intToString(buf, regs[0]); intToString(buf, regs[1]); intToString(buf, regs[2]); intToString(buf, regs[3]); } brand = buf.toString().trim(); } X86CpuID id = new X86CpuID(data, brand); id.detectHyperV(); return id; } /** * Try to detect if we're running in HyperV. * * @return true if we're running in HyperV, false otherwise. */ public boolean detectHyperV() { if (!hasHYPERVISOR()) return false; int[] regs = new int[4]; UnsafeX86.getCPUID(Word.fromIntZeroExtend(0x40000001), regs); if (regs[0] != 0x31237648) return false; // Found 'Hv#1' Hypervisor vendor neutral identification UnsafeX86.getCPUID(Word.fromIntZeroExtend(0x40000000), regs); final StringBuilder buf = new StringBuilder(); intToString(buf, regs[1]); // ebx intToString(buf, regs[2]); // ecx intToString(buf, regs[3]); // edx hypervisorVendor = buf.toString().trim(); return true; } /** * Processor vendor string */ public String getName() { return getVendor(); } /** * Processor brand string */ public String getBrand() { return brand; } /** * Gets the processor name. * * @return The processor name */ public String getVendor() { if (vendor == null) { final StringBuilder buf = new StringBuilder(); intToString(buf, data[1]); intToString(buf, data[3]); intToString(buf, data[2]); vendor = buf.toString(); } return vendor; } /** * Is this the id of an Intel CPU. * * @return {@code true} for an Intel CPU, otherwise {@code false} */ public boolean isIntel() { return getVendor().equals(X86Vendor.INTEL.getId()); } /** * Is this the id of an AMD CPU. * * @return {@code true} for an AMD CPU, otherwise {@code false} */ public boolean isAMD() { return getVendor().equals(X86Vendor.AMD.getId()); } private static final void intToString(StringBuilder buf, int value) { buf.append((char) (value & 0xFF)); buf.append((char) ((value >> 8) & 0xFF)); buf.append((char) ((value >> 16) & 0xFF)); buf.append((char) ((value >>> 24) & 0xFF)); } /** * @return Returns the family. */ public final int getFamily() { return this.family; } /** * @return Returns the model. */ public final int getModel() { return this.model; } /** * @return Returns the steppingID. */ public final int getSteppingID() { return this.steppingID; } /** * @return Returns the features. */ public final int getFeatures() { return this.features; } /** * Has this CPU a given feature. * * @param feature * @return boolean */ public final boolean hasFeature(long feature) { return ((this.exFeatures & feature) == feature); } /** * Gets the number of logical processors. * This method will only return more then 1 of this processor * has the Hyper Threading feature. * * @return The number of logical processors. */ public final int getLogicalProcessors() { if (hasFeature(FEAT_HTT)) { // EBX bits 16-23 when EAX == 1 return (data[5] >> 16) & 0xFF; } else { return 1; } } /** * Calculate the physical package id for the given APIC id. * * @param apicId * @return the physical package id. */ public final int getPhysicalPackageId(int apicId) { int index_lsb = 0; int index_msb = 31; final int numLogicalProcessors = getLogicalProcessors(); int tmp = numLogicalProcessors; while ((tmp & 1) == 0) { tmp >>= 1; index_lsb++; } tmp = numLogicalProcessors; while ((tmp & 0x80000000) == 0) { tmp <<= 1; index_msb--; } if (index_lsb != index_msb) { index_msb++; } return ((data[5] >> 24) & 0xFF) >> index_msb; } /** * Has this CPU a given feature. * * @param feature * @return boolean */ public final boolean hasFeature(int feature) { return ((this.features & feature) == feature); } public final boolean hasFPU() { return hasFeature(FEAT_FPU); } public final boolean hasVME() { return hasFeature(FEAT_VME); } public final boolean hasDE() { return hasFeature(FEAT_DE); } public final boolean hasPSE() { return hasFeature(FEAT_PSE); } public final boolean hasTSC() { return hasFeature(FEAT_TSC); } public final boolean hasMSR() { return hasFeature(FEAT_MSR); } public final boolean hasPAE() { return hasFeature(FEAT_PAE); } public final boolean hasMCE() { return hasFeature(FEAT_MCE); } public final boolean hasCX8() { return hasFeature(FEAT_CX8); } public final boolean hasAPIC() { return hasFeature(FEAT_APIC); } public final boolean hasSEP() { return hasFeature(FEAT_SEP); } public final boolean hasMTRR() { return hasFeature(FEAT_MTRR); } public final boolean hasPGE() { return hasFeature(FEAT_PGE); } public final boolean hasMCA() { return hasFeature(FEAT_MCA); } public final boolean hasCMOV() { return hasFeature(FEAT_CMOV); } public final boolean hasPAT() { return hasFeature(FEAT_PAT); } public final boolean hasPSE36() { return hasFeature(FEAT_PSE36); } public final boolean hasPSN() { return hasFeature(FEAT_PSN); } public final boolean hasCLFSH() { return hasFeature(FEAT_CLFSH); } public final boolean hasDS() { return hasFeature(FEAT_DS); } public final boolean hasACPI() { return hasFeature(FEAT_ACPI); } public final boolean hasMMX() { return hasFeature(FEAT_MMX); } public final boolean hasFXSR() { return hasFeature(FEAT_FXSR); } public final boolean hasSSE() { return hasFeature(FEAT_SSE); } public final boolean hasSSE2() { return hasFeature(FEAT_SSE2); } public final boolean hasSS() { return hasFeature(FEAT_SS); } public final boolean hasHTT() { return hasFeature(FEAT_HTT); } public final boolean hasTM() { return hasFeature(FEAT_TM); } public final boolean hasPBE() { return hasFeature(FEAT_PBE); } // Extended features public final boolean hasEST() { return hasFeature(FEAT_EST); } public final boolean hasTM2() { return hasFeature(FEAT_TM2); } public final boolean hasCNXTID() { return hasFeature(FEAT_CNXTID); } public final boolean hasHYPERVISOR() { return hasFeature(FEAT_HYPERVISOR); } /** * Convert all features to a human readable string. * * @return The available features. */ private final String getFeatureString() { final StringBuilder buf = new StringBuilder(); getFeatureString(buf, FEAT_FPU, "FPU"); getFeatureString(buf, FEAT_VME, "VME"); getFeatureString(buf, FEAT_DE, "DE"); getFeatureString(buf, FEAT_PSE, "PSE"); getFeatureString(buf, FEAT_TSC, "TSC"); getFeatureString(buf, FEAT_MSR, "MSR"); getFeatureString(buf, FEAT_PAE, "PAE"); getFeatureString(buf, FEAT_MCE, "MCE"); getFeatureString(buf, FEAT_CX8, "CX8"); getFeatureString(buf, FEAT_APIC, "APIC"); getFeatureString(buf, FEAT_SEP, "SEP"); getFeatureString(buf, FEAT_MTRR, "MTRR"); getFeatureString(buf, FEAT_PGE, "PGE"); getFeatureString(buf, FEAT_MCA, "MCA"); getFeatureString(buf, FEAT_CMOV, "CMOV"); getFeatureString(buf, FEAT_PAT, "PAT"); getFeatureString(buf, FEAT_PSE36, "PSE36"); getFeatureString(buf, FEAT_PSN, "PSN"); getFeatureString(buf, FEAT_CLFSH, "CLFSH"); getFeatureString(buf, FEAT_DS, "DS"); getFeatureString(buf, FEAT_ACPI, "ACPI"); getFeatureString(buf, FEAT_MMX, "MMX"); getFeatureString(buf, FEAT_FXSR, "FXSR"); getFeatureString(buf, FEAT_SSE, "SSE"); getFeatureString(buf, FEAT_SSE2, "SSE2"); getFeatureString(buf, FEAT_SS, "SS"); getFeatureString(buf, FEAT_HTT, "HTT"); getFeatureString(buf, FEAT_TM, "TM"); getFeatureString(buf, FEAT_PBE, "PBE"); // Extended features getFeatureString(buf, FEAT_PNI, "PNI"); getFeatureString(buf, FEAT_PCLMULQDQ, "PCLMULQDQ"); getFeatureString(buf, FEAT_DTES64, "DTES64"); getFeatureString(buf, FEAT_MONITOR, "MONITOR"); getFeatureString(buf, FEAT_DS_CPL, "DS_CPL"); getFeatureString(buf, FEAT_VMX, "VMX"); getFeatureString(buf, FEAT_SMX, "SMX"); getFeatureString(buf, FEAT_EST, "EST"); getFeatureString(buf, FEAT_TM2, "TM2"); getFeatureString(buf, FEAT_SSSE3, "SSSE3"); getFeatureString(buf, FEAT_CNXTID, "CNXTID"); getFeatureString(buf, FEAT_HYPERVISOR, "HYPERVISOR"); return buf.toString(); } private final void getFeatureString(StringBuilder buf, int feature, String featName) { if (hasFeature(feature)) { if (buf.length() > 0) { buf.append(','); } buf.append(featName); } } private final void getFeatureString(StringBuilder buf, long feature, String featName) { if (hasFeature(feature)) { if (buf.length() > 0) { buf.append(','); } buf.append(featName); } } /** * Convert to a string representation. * * @see java.lang.Object#toString() */ public String toString() { final StringBuilder sb = new StringBuilder(); sb.append("CPUID"); sb.append('\n'); sb.append(" name : "); sb.append(getName()); sb.append('\n'); sb.append(" brand : "); sb.append(getBrand()); sb.append('\n'); sb.append(" family : "); sb.append(getFamily()); sb.append('\n'); sb.append(" model : "); sb.append(getModel()); sb.append('\n'); sb.append(" step : "); sb.append(getSteppingID()); sb.append('\n'); if (hasFeature(FEAT_HTT)) { sb.append(" #log.proc: "); sb.append(getLogicalProcessors()); sb.append('\n'); } if (hypervisorVendor != null) { sb.append(" hyperv. : "); sb.append(hypervisorVendor); sb.append('\n'); } sb.append(" features : "); sb.append(getFeatureString()); sb.append('\n'); sb.append(" raw : "); sb.append(NumberUtils.hex(data, 8)); sb.append('\n'); return sb.toString(); } }