1627 lines
74 KiB
C
1627 lines
74 KiB
C
/*********************************************************
|
|
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
|
*
|
|
* This program 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 version 2.1 and no later version.
|
|
*
|
|
* This program 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 Lesser GNU General Public
|
|
* License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*********************************************************/
|
|
|
|
/*********************************************************
|
|
* The contents of this file are subject to the terms of the Common
|
|
* Development and Distribution License (the "License") version 1.0
|
|
* and no later version. You may not use this file except in
|
|
* compliance with the License.
|
|
*
|
|
* You can obtain a copy of the License at
|
|
* http://www.opensource.org/licenses/cddl1.php
|
|
*
|
|
* See the License for the specific language governing permissions
|
|
* and limitations under the License.
|
|
*
|
|
*********************************************************/
|
|
|
|
#ifndef _X86CPUID_H_
|
|
#define _X86CPUID_H_
|
|
|
|
/* http://www.sandpile.org/ia32/cpuid.htm */
|
|
|
|
#include "vm_basic_types.h"
|
|
#include "community_source.h"
|
|
#include "x86vendor.h"
|
|
#include "vm_assert.h"
|
|
|
|
/*
|
|
* The linux kernel's ptrace.h stupidly defines the bare
|
|
* EAX/EBX/ECX/EDX, which wrecks havoc with our preprocessor tricks.
|
|
*/
|
|
#undef EAX
|
|
#undef EBX
|
|
#undef ECX
|
|
#undef EDX
|
|
|
|
typedef struct CPUIDRegs {
|
|
uint32 eax, ebx, ecx, edx;
|
|
} CPUIDRegs;
|
|
|
|
typedef union CPUIDRegsUnion {
|
|
uint32 array[4];
|
|
CPUIDRegs regs;
|
|
} CPUIDRegsUnion;
|
|
|
|
/*
|
|
* Results of calling cpuid(eax, ecx) on all host logical CPU.
|
|
*/
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable :4200) // non-std extension: zero-sized array in struct
|
|
#endif
|
|
|
|
typedef
|
|
#include "vmware_pack_begin.h"
|
|
struct CPUIDReply {
|
|
/*
|
|
* Unique host logical CPU identifier. It does not change across queries, so
|
|
* we use it to correlate the replies of multiple queries.
|
|
*/
|
|
uint64 tag; // OUT
|
|
|
|
CPUIDRegs regs; // OUT
|
|
}
|
|
#include "vmware_pack_end.h"
|
|
CPUIDReply;
|
|
|
|
typedef
|
|
#include "vmware_pack_begin.h"
|
|
struct CPUIDQuery {
|
|
uint32 eax; // IN
|
|
uint32 ecx; // IN
|
|
uint32 numLogicalCPUs; // IN/OUT
|
|
CPUIDReply logicalCPUs[0]; // OUT
|
|
}
|
|
#include "vmware_pack_end.h"
|
|
CPUIDQuery;
|
|
|
|
/*
|
|
* CPUID levels the monitor caches.
|
|
*
|
|
* The first parameter defines whether the level has its default masks
|
|
* generated from the values in this file. Any level which is marked
|
|
* as FALSE here *must* have all monitor support types set to NA. A
|
|
* static assert in lib/cpuidcompat/cpuidcompat.c will check this.
|
|
*
|
|
* The fourth parameter is a "sub leaf count", where 0 means that ecx
|
|
* is ignored, otherwise is the count of sub-leaves cached/supported.
|
|
*/
|
|
|
|
#define CPUID_CACHED_LEVELS \
|
|
CPUIDLEVEL(TRUE, 0, 0, 0) \
|
|
CPUIDLEVEL(TRUE, 1, 1, 0) \
|
|
CPUIDLEVEL(FALSE, 2, 2, 0) \
|
|
CPUIDLEVEL(FALSE, 4, 4, 7) \
|
|
CPUIDLEVEL(FALSE, 5, 5, 0) \
|
|
CPUIDLEVEL(FALSE, 6, 6, 0) \
|
|
CPUIDLEVEL(TRUE, 7, 7, 1) \
|
|
CPUIDLEVEL(FALSE, A, 0xA, 0) \
|
|
CPUIDLEVEL(FALSE, B, 0xB, 2) \
|
|
CPUIDLEVEL(TRUE, D, 0xD, 4) \
|
|
CPUIDLEVEL(FALSE, 400, 0x40000000, 0) \
|
|
CPUIDLEVEL(FALSE, 401, 0x40000001, 0) \
|
|
CPUIDLEVEL(FALSE, 402, 0x40000002, 0) \
|
|
CPUIDLEVEL(FALSE, 403, 0x40000003, 0) \
|
|
CPUIDLEVEL(FALSE, 404, 0x40000004, 0) \
|
|
CPUIDLEVEL(FALSE, 405, 0x40000005, 0) \
|
|
CPUIDLEVEL(FALSE, 406, 0x40000006, 0) \
|
|
CPUIDLEVEL(FALSE, 410, 0x40000010, 0) \
|
|
CPUIDLEVEL(FALSE, 80, 0x80000000, 0) \
|
|
CPUIDLEVEL(TRUE, 81, 0x80000001, 0) \
|
|
CPUIDLEVEL(FALSE, 82, 0x80000002, 0) \
|
|
CPUIDLEVEL(FALSE, 83, 0x80000003, 0) \
|
|
CPUIDLEVEL(FALSE, 84, 0x80000004, 0) \
|
|
CPUIDLEVEL(FALSE, 85, 0x80000005, 0) \
|
|
CPUIDLEVEL(FALSE, 86, 0x80000006, 0) \
|
|
CPUIDLEVEL(FALSE, 87, 0x80000007, 0) \
|
|
CPUIDLEVEL(FALSE, 88, 0x80000008, 0) \
|
|
CPUIDLEVEL(TRUE, 8A, 0x8000000A, 0) \
|
|
CPUIDLEVEL(FALSE, 819, 0x80000019, 0) \
|
|
CPUIDLEVEL(FALSE, 81A, 0x8000001A, 0) \
|
|
CPUIDLEVEL(FALSE, 81B, 0x8000001B, 0) \
|
|
CPUIDLEVEL(FALSE, 81C, 0x8000001C, 0) \
|
|
CPUIDLEVEL(FALSE, 81D, 0x8000001D, 5) \
|
|
CPUIDLEVEL(FALSE, 81E, 0x8000001E, 0)
|
|
|
|
#define CPUID_ALL_LEVELS CPUID_CACHED_LEVELS
|
|
|
|
/* Define cached CPUID levels in the form: CPUID_LEVEL_<ShortName> */
|
|
typedef enum {
|
|
#define CPUIDLEVEL(t, s, v, c) CPUID_LEVEL_##s,
|
|
CPUID_CACHED_LEVELS
|
|
#undef CPUIDLEVEL
|
|
CPUID_NUM_CACHED_LEVELS
|
|
} CpuidCachedLevel;
|
|
|
|
/* Enum to translate between shorthand name and actual CPUID level value. */
|
|
enum {
|
|
#define CPUIDLEVEL(t, s, v, c) CPUID_LEVEL_VAL_##s = v,
|
|
CPUID_ALL_LEVELS
|
|
#undef CPUIDLEVEL
|
|
};
|
|
|
|
|
|
/* Named feature leaves */
|
|
#define CPUID_FEATURE_INFORMATION 0x01
|
|
#define CPUID_PROCESSOR_TOPOLOGY 4
|
|
#define CPUID_MWAIT_FEATURES 5
|
|
#define CPUID_XSAVE_FEATURES 0xd
|
|
#define CPUID_HYPERVISOR_LEVEL_0 0x40000000
|
|
#define CPUID_SVM_FEATURES 0x8000000a
|
|
|
|
|
|
/*
|
|
* CPUID result registers
|
|
*/
|
|
|
|
#define CPUID_REGS \
|
|
CPUIDREG(EAX, eax) \
|
|
CPUIDREG(EBX, ebx) \
|
|
CPUIDREG(ECX, ecx) \
|
|
CPUIDREG(EDX, edx)
|
|
|
|
typedef enum {
|
|
#define CPUIDREG(uc, lc) CPUID_REG_##uc,
|
|
CPUID_REGS
|
|
#undef CPUIDREG
|
|
CPUID_NUM_REGS
|
|
} CpuidReg;
|
|
|
|
#define CPUID_INTEL_VENDOR_STRING "GenuntelineI"
|
|
#define CPUID_AMD_VENDOR_STRING "AuthcAMDenti"
|
|
#define CPUID_CYRIX_VENDOR_STRING "CyriteadxIns"
|
|
#define CPUID_VIA_VENDOR_STRING "CentaulsaurH"
|
|
|
|
#define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING "Microsoft Hv"
|
|
#define CPUID_KVM_HYPERVISOR_VENDOR_STRING "KVMKVMKVM\0\0\0"
|
|
#define CPUID_VMWARE_HYPERVISOR_VENDOR_STRING "VMwareVMware"
|
|
#define CPUID_XEN_HYPERVISOR_VENDOR_STRING "XenVMMXenVMM"
|
|
|
|
#define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel"
|
|
#define CPUID_AMD_VENDOR_STRING_FIXED "AuthenticAMD"
|
|
#define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead"
|
|
#define CPUID_VIA_VENDOR_STRING_FIXED "CentaurHauls"
|
|
|
|
/*
|
|
* FIELD can be defined to process the CPUID information provided
|
|
* in the following CPUID_FIELD_DATA macro. The first parameter is
|
|
* the CPUID level of the feature (must be defined in
|
|
* CPUID_ALL_LEVELS, above. The second parameter is the CPUID result
|
|
* register in which the field is returned (defined in CPUID_REGS).
|
|
* The third field is the vendor(s) this feature applies to. "COMMON"
|
|
* means all vendors apply. UNKNOWN may not be used here. The fourth
|
|
* and fifth parameters are the bit position of the field and the
|
|
* width, respectively. The sixth is the text name of the field.
|
|
*
|
|
* The seventh parameters specifies the monitor support
|
|
* characteristics for this field. The value must be a valid
|
|
* CpuidFieldSupported value (omitting CPUID_FIELD_SUPPORT_ for
|
|
* convenience). The meaning of those values are described below.
|
|
*
|
|
* The eighth parameter describes whether the feature is capable of
|
|
* being used by usermode code (TRUE), or just CPL0 kernel code
|
|
* (FALSE).
|
|
*
|
|
* FLAG is defined identically to FIELD, but its accessors are more
|
|
* appropriate for 1-bit flags, and compile-time asserts enforce that
|
|
* the size is 1 bit wide.
|
|
*/
|
|
|
|
|
|
/*
|
|
* CpuidFieldSupported is made up of the following values:
|
|
*
|
|
* NO: A feature/field that IS NOT SUPPORTED by the monitor. Even
|
|
* if the host supports this feature, we will never expose it to
|
|
* the guest.
|
|
*
|
|
* YES: A feature/field that IS SUPPORTED by the monitor. If the
|
|
* host supports this feature, we will expose it to the guest. If
|
|
* not, then we will not set the feature.
|
|
*
|
|
* ANY: A feature/field that IS ALWAYS SUPPORTED by the monitor.
|
|
* Even if the host does not support the feature, the monitor can
|
|
* expose the feature to the guest. As with "YES", the guest cpuid
|
|
* value defaults to the host/evc cpuid value. But usually the
|
|
* guest cpuid value is recomputed at power on, ignoring the default
|
|
* value.
|
|
*
|
|
*
|
|
* NA: Only legal for levels not masked/tested by default (see
|
|
* above for this definition). Such fields must always be marked
|
|
* as NA.
|
|
*
|
|
* These distinctions, when combined with the feature's CPL3
|
|
* properties can be translated into a common CPUID mask string as
|
|
* follows:
|
|
*
|
|
* NO + CPL3 --> "R" (Reserved). We don't support the feature,
|
|
* but we can't properly hide this from applications when using
|
|
* direct execution or HV with apps that do try/catch/fail, so we
|
|
* must still perform compatibility checks.
|
|
*
|
|
* NO + !CPL3 --> "0" (Masked). We can hide this from the guest.
|
|
*
|
|
* YES --> "H" (Host). We support the feature, so show it to the
|
|
* guest if the host has the feature.
|
|
*
|
|
* ANY/NA --> "X" (Ignore). By default, don't perform checks for
|
|
* this feature bit. Per-GOS masks may choose to set this bit in
|
|
* the guest. (e.g. the APIC feature bit is always set to 1.)
|
|
*
|
|
* See lib/cpuidcompat/cpuidcompat.c for any possible overrides to
|
|
* these defaults.
|
|
*/
|
|
typedef enum {
|
|
CPUID_FIELD_SUPPORTED_NO,
|
|
CPUID_FIELD_SUPPORTED_YES,
|
|
CPUID_FIELD_SUPPORTED_ANY,
|
|
CPUID_FIELD_SUPPORTED_NA,
|
|
CPUID_NUM_FIELD_SUPPORTEDS
|
|
} CpuidFieldSupported;
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_0 \
|
|
FIELD( 0, 0, EAX, 0, 32, NUMLEVELS, ANY, FALSE) \
|
|
FIELD( 0, 0, EBX, 0, 32, VENDOR1, YES, TRUE) \
|
|
FIELD( 0, 0, ECX, 0, 32, VENDOR3, YES, TRUE) \
|
|
FIELD( 0, 0, EDX, 0, 32, VENDOR2, YES, TRUE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_1 \
|
|
FIELD( 1, 0, EAX, 0, 4, STEPPING, ANY, FALSE) \
|
|
FIELD( 1, 0, EAX, 4, 4, MODEL, ANY, FALSE) \
|
|
FIELD( 1, 0, EAX, 8, 4, FAMILY, YES, FALSE) \
|
|
FIELD( 1, 0, EAX, 12, 2, TYPE, ANY, FALSE) \
|
|
FIELD( 1, 0, EAX, 16, 4, EXTENDED_MODEL, ANY, FALSE) \
|
|
FIELD( 1, 0, EAX, 20, 8, EXTENDED_FAMILY, YES, FALSE) \
|
|
FIELD( 1, 0, EBX, 0, 8, BRAND_ID, ANY, FALSE) \
|
|
FIELD( 1, 0, EBX, 8, 8, CLFL_SIZE, ANY, FALSE) \
|
|
FIELD( 1, 0, EBX, 16, 8, LCPU_COUNT, ANY, FALSE) \
|
|
FIELD( 1, 0, EBX, 24, 8, APICID, ANY, FALSE) \
|
|
FLAG( 1, 0, ECX, 0, 1, SSE3, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 1, 1, PCLMULQDQ, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 2, 1, DTES64, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 3, 1, MWAIT, YES, FALSE) \
|
|
FLAG( 1, 0, ECX, 4, 1, DSCPL, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 5, 1, VMX, YES, FALSE) \
|
|
FLAG( 1, 0, ECX, 6, 1, SMX, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 7, 1, EIST, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 8, 1, TM2, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 9, 1, SSSE3, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 10, 1, CNXTID, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 11, 1, SDBG, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 12, 1, FMA, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 13, 1, CMPXCHG16B, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 14, 1, xTPR, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 15, 1, PDCM, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 17, 1, PCID, YES, FALSE) \
|
|
FLAG( 1, 0, ECX, 18, 1, DCA, NO, FALSE) \
|
|
FLAG( 1, 0, ECX, 19, 1, SSE41, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 20, 1, SSE42, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 21, 1, x2APIC, ANY, FALSE) \
|
|
FLAG( 1, 0, ECX, 22, 1, MOVBE, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 23, 1, POPCNT, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 24, 1, TSC_DEADLINE, ANY, FALSE) \
|
|
FLAG( 1, 0, ECX, 25, 1, AES, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 26, 1, XSAVE, YES, FALSE) \
|
|
FLAG( 1, 0, ECX, 27, 1, OSXSAVE, ANY, FALSE) \
|
|
FLAG( 1, 0, ECX, 28, 1, AVX, YES, FALSE) \
|
|
FLAG( 1, 0, ECX, 29, 1, F16C, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 30, 1, RDRAND, YES, TRUE) \
|
|
FLAG( 1, 0, ECX, 31, 1, HYPERVISOR, ANY, TRUE) \
|
|
FLAG( 1, 0, EDX, 0, 1, FPU, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 1, 1, VME, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 2, 1, DE, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 3, 1, PSE, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 4, 1, TSC, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 5, 1, MSR, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 6, 1, PAE, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 7, 1, MCE, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 8, 1, CX8, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 9, 1, APIC, ANY, FALSE) \
|
|
FLAG( 1, 0, EDX, 11, 1, SEP, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 12, 1, MTRR, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 13, 1, PGE, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 14, 1, MCA, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 15, 1, CMOV, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 16, 1, PAT, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 17, 1, PSE36, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 18, 1, PSN, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 19, 1, CLFSH, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 21, 1, DS, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 22, 1, ACPI, ANY, FALSE) \
|
|
FLAG( 1, 0, EDX, 23, 1, MMX, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 24, 1, FXSR, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 25, 1, SSE, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 26, 1, SSE2, YES, TRUE) \
|
|
FLAG( 1, 0, EDX, 27, 1, SS, YES, FALSE) \
|
|
FLAG( 1, 0, EDX, 28, 1, HTT, ANY, FALSE) \
|
|
FLAG( 1, 0, EDX, 29, 1, TM, NO, FALSE) \
|
|
FLAG( 1, 0, EDX, 30, 1, IA64, NO, FALSE) \
|
|
FLAG( 1, 0, EDX, 31, 1, PBE, NO, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_2 \
|
|
FIELD( 2, 0, EAX, 0, 8, LEAF2_COUNT, NA, FALSE) \
|
|
FIELD( 2, 0, EAX, 8, 8, LEAF2_CACHE1, NA, FALSE) \
|
|
FIELD( 2, 0, EAX, 16, 8, LEAF2_CACHE2, NA, FALSE) \
|
|
FIELD( 2, 0, EAX, 24, 8, LEAF2_CACHE3, NA, FALSE) \
|
|
FIELD( 2, 0, EBX, 0, 8, LEAF2_CACHE4, NA, FALSE) \
|
|
FIELD( 2, 0, EBX, 8, 8, LEAF2_CACHE5, NA, FALSE) \
|
|
FIELD( 2, 0, EBX, 16, 8, LEAF2_CACHE6, NA, FALSE) \
|
|
FIELD( 2, 0, EBX, 24, 8, LEAF2_CACHE7, NA, FALSE) \
|
|
FIELD( 2, 0, ECX, 0, 8, LEAF2_CACHE8, NA, FALSE) \
|
|
FIELD( 2, 0, ECX, 8, 8, LEAF2_CACHE9, NA, FALSE) \
|
|
FIELD( 2, 0, ECX, 16, 8, LEAF2_CACHE10, NA, FALSE) \
|
|
FIELD( 2, 0, ECX, 24, 8, LEAF2_CACHE11, NA, FALSE) \
|
|
FIELD( 2, 0, EDX, 0, 8, LEAF2_CACHE12, NA, FALSE) \
|
|
FIELD( 2, 0, EDX, 8, 8, LEAF2_CACHE13, NA, FALSE) \
|
|
FIELD( 2, 0, EDX, 16, 8, LEAF2_CACHE14, NA, FALSE) \
|
|
FIELD( 2, 0, EDX, 24, 8, LEAF2_CACHE15, NA, FALSE) \
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_4 \
|
|
FIELD( 4, 0, EAX, 0, 5, LEAF4_CACHE_TYPE, NA, FALSE) \
|
|
FIELD( 4, 0, EAX, 5, 3, LEAF4_CACHE_LEVEL, NA, FALSE) \
|
|
FLAG( 4, 0, EAX, 8, 1, LEAF4_CACHE_SELF_INIT, NA, FALSE) \
|
|
FLAG( 4, 0, EAX, 9, 1, LEAF4_CACHE_FULLY_ASSOC, NA, FALSE) \
|
|
FIELD( 4, 0, EAX, 14, 12, LEAF4_CACHE_NUMHT_SHARING, NA, FALSE) \
|
|
FIELD( 4, 0, EAX, 26, 6, LEAF4_CORE_COUNT, NA, FALSE) \
|
|
FIELD( 4, 0, EBX, 0, 12, LEAF4_CACHE_LINE, NA, FALSE) \
|
|
FIELD( 4, 0, EBX, 12, 10, LEAF4_CACHE_PART, NA, FALSE) \
|
|
FIELD( 4, 0, EBX, 22, 10, LEAF4_CACHE_WAYS, NA, FALSE) \
|
|
FIELD( 4, 0, ECX, 0, 32, LEAF4_CACHE_SETS, NA, FALSE) \
|
|
FLAG( 4, 0, EDX, 0, 1, LEAF4_CACHE_WBINVD_NOT_GUARANTEED, NA, FALSE) \
|
|
FLAG( 4, 0, EDX, 1, 1, LEAF4_CACHE_IS_INCLUSIVE, NA, FALSE) \
|
|
FLAG( 4, 0, EDX, 2, 1, LEAF4_CACHE_COMPLEX_INDEXING, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_5 \
|
|
FIELD( 5, 0, EAX, 0, 16, MWAIT_MIN_SIZE, NA, FALSE) \
|
|
FIELD( 5, 0, EBX, 0, 16, MWAIT_MAX_SIZE, NA, FALSE) \
|
|
FLAG( 5, 0, ECX, 0, 1, MWAIT_EXTENSIONS, NA, FALSE) \
|
|
FLAG( 5, 0, ECX, 1, 1, MWAIT_INTR_BREAK, NA, FALSE) \
|
|
FIELD( 5, 0, EDX, 0, 4, MWAIT_C0_SUBSTATE, NA, FALSE) \
|
|
FIELD( 5, 0, EDX, 4, 4, MWAIT_C1_SUBSTATE, NA, FALSE) \
|
|
FIELD( 5, 0, EDX, 8, 4, MWAIT_C2_SUBSTATE, NA, FALSE) \
|
|
FIELD( 5, 0, EDX, 12, 4, MWAIT_C3_SUBSTATE, NA, FALSE) \
|
|
FIELD( 5, 0, EDX, 16, 4, MWAIT_C4_SUBSTATE, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_6 \
|
|
FLAG( 6, 0, EAX, 0, 1, THERMAL_SENSOR, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 1, 1, TURBO_MODE, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 2, 1, APIC_INVARIANT, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 4, 1, PLN, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 5, 1, ECMD, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 6, 1, PTM, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 7, 1, HWP, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 8, 1, HWP_NOTIFICATION, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 9, 1, HWP_ACTIVITY_WINDOW, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 10, 1, HWP_ENERGY_PERFORMANCE_PREFERENCE, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 11, 1, HWP_PACKAGE_LEVEL_REQUEST, NA, FALSE) \
|
|
FLAG( 6, 0, EAX, 13, 1, HDC, NA, FALSE) \
|
|
FIELD( 6, 0, EBX, 0, 4, NUM_INTR_THRESHOLDS, NA, FALSE) \
|
|
FLAG( 6, 0, ECX, 0, 1, HW_COORD_FEEDBACK, NA, FALSE) \
|
|
FLAG( 6, 0, ECX, 3, 1, ENERGY_PERF_BIAS, NA, FALSE)
|
|
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_7 \
|
|
FLAG( 7, 0, EBX, 0, 1, FSGSBASE, YES, FALSE) \
|
|
FLAG( 7, 0, EBX, 1, 1, TSC_ADJUST, ANY, FALSE) \
|
|
FLAG( 7, 0, EBX, 3, 1, BMI1, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 4, 1, HLE, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 5, 1, AVX2, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 7, 1, SMEP, YES, FALSE) \
|
|
FLAG( 7, 0, EBX, 8, 1, BMI2, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 9, 1, ENFSTRG, YES, FALSE) \
|
|
FLAG( 7, 0, EBX, 10, 1, INVPCID, YES, FALSE) \
|
|
FLAG( 7, 0, EBX, 11, 1, RTM, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 12, 1, PQM, NO, FALSE) \
|
|
FLAG( 7, 0, EBX, 13, 1, FP_SEGMENT_ZERO, ANY, TRUE) \
|
|
FLAG( 7, 0, EBX, 15, 1, PQE, NO, FALSE) \
|
|
FLAG( 7, 0, EBX, 18, 1, RDSEED, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 19, 1, ADX, YES, TRUE) \
|
|
FLAG( 7, 0, EBX, 20, 1, SMAP, YES, FALSE)
|
|
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_A \
|
|
FIELD( A, 0, EAX, 0, 8, PMC_VERSION, NA, FALSE) \
|
|
FIELD( A, 0, EAX, 8, 8, PMC_NUM_GEN, NA, FALSE) \
|
|
FIELD( A, 0, EAX, 16, 8, PMC_WIDTH_GEN, NA, FALSE) \
|
|
FIELD( A, 0, EAX, 24, 8, PMC_EBX_LENGTH, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 0, 1, PMC_CORE_CYCLES, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 1, 1, PMC_INSTR_RETIRED, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 2, 1, PMC_REF_CYCLES, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 3, 1, PMC_LAST_LVL_CREF, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 4, 1, PMC_LAST_LVL_CMISS, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 5, 1, PMC_BR_INST_RETIRED, NA, FALSE) \
|
|
FLAG( A, 0, EBX, 6, 1, PMC_BR_MISS_RETIRED, NA, FALSE) \
|
|
FIELD( A, 0, EDX, 0, 5, PMC_NUM_FIXED, NA, FALSE) \
|
|
FIELD( A, 0, EDX, 5, 8, PMC_WIDTH_FIXED, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_B \
|
|
FIELD( B, 0, EAX, 0, 5, TOPOLOGY_MASK_WIDTH, NA, FALSE) \
|
|
FIELD( B, 0, EBX, 0, 16, TOPOLOGY_CPUS_SHARING_LEVEL, NA, FALSE) \
|
|
FIELD( B, 0, ECX, 0, 8, TOPOLOGY_LEVEL_NUMBER, NA, FALSE) \
|
|
FIELD( B, 0, ECX, 8, 8, TOPOLOGY_LEVEL_TYPE, NA, FALSE) \
|
|
FIELD( B, 0, EDX, 0, 32, TOPOLOGY_X2APIC_ID, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_D \
|
|
FLAG( D, 0, EAX, 0, 1, XCR0_MASTER_LEGACY_FP, YES, FALSE) \
|
|
FLAG( D, 0, EAX, 1, 1, XCR0_MASTER_SSE, YES, FALSE) \
|
|
FLAG( D, 0, EAX, 2, 1, XCR0_MASTER_YMM_H, YES, FALSE) \
|
|
FIELD( D, 0, EAX, 3, 29, XCR0_MASTER_LOWER, NO, FALSE) \
|
|
FIELD( D, 0, EBX, 0, 32, XSAVE_ENABLED_SIZE, ANY, FALSE) \
|
|
FIELD( D, 0, ECX, 0, 32, XSAVE_MAX_SIZE, YES, FALSE) \
|
|
FIELD( D, 0, EDX, 0, 29, XCR0_MASTER_UPPER, NO, FALSE) \
|
|
FLAG( D, 0, EDX, 30, 1, XCR0_MASTER_LWP, NO, FALSE) \
|
|
FLAG( D, 0, EDX, 31, 1, XCR0_MASTER_EXTENDED_XSAVE, NO, FALSE) \
|
|
FLAG( D, 1, EAX, 0, 1, XSAVEOPT, YES, FALSE) \
|
|
FLAG( D, 1, EAX, 1, 1, XSAVEC, NO, FALSE) \
|
|
FLAG( D, 1, EAX, 2, 1, XGETBV_ECX1, NO, FALSE) \
|
|
FLAG( D, 1, EAX, 3, 1, XSAVES, NO, FALSE) \
|
|
FIELD( D, 1, EBX, 0, 32, XSAVE_XSS_SIZE, NO, FALSE) \
|
|
FIELD( D, 1, ECX, 0, 32, XSS_LOWER, NO, FALSE) \
|
|
FIELD( D, 1, EDX, 0, 32, XSS_UPPER, NO, FALSE) \
|
|
FIELD( D, 2, EAX, 0, 32, XSAVE_YMM_SIZE, YES, FALSE) \
|
|
FIELD( D, 2, EBX, 0, 32, XSAVE_YMM_OFFSET, YES, FALSE) \
|
|
FIELD( D, 2, ECX, 0, 32, XSAVE_YMM_RSVD1, YES, FALSE) \
|
|
FIELD( D, 2, EDX, 0, 32, XSAVE_YMM_RSVD2, YES, FALSE) \
|
|
FIELD( D, 62, EAX, 0, 32, XSAVE_LWP_SIZE, NO, FALSE) \
|
|
FIELD( D, 62, EBX, 0, 32, XSAVE_LWP_OFFSET, NO, FALSE) \
|
|
FIELD( D, 62, ECX, 0, 32, XSAVE_LWP_RSVD1, NO, FALSE) \
|
|
FIELD( D, 62, EDX, 0, 32, XSAVE_LWP_RSVD2, NO, FALSE)
|
|
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_400 \
|
|
FIELD(400, 0, EAX, 0, 32, NUM_HYP_LEVELS, NA, FALSE) \
|
|
FIELD(400, 0, EBX, 0, 32, HYPERVISOR1, NA, FALSE) \
|
|
FIELD(400, 0, ECX, 0, 32, HYPERVISOR2, NA, FALSE) \
|
|
FIELD(400, 0, EDX, 0, 32, HYPERVISOR3, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_410 \
|
|
FIELD(410, 0, EAX, 0, 32, TSC_HZ, NA, FALSE) \
|
|
FIELD(410, 0, EBX, 0, 32, ACPIBUS_HZ, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_80 \
|
|
FIELD( 80, 0, EAX, 0, 32, NUM_EXT_LEVELS, NA, FALSE) \
|
|
FIELD( 80, 0, EBX, 0, 32, LEAF80_VENDOR1, NA, FALSE) \
|
|
FIELD( 80, 0, ECX, 0, 32, LEAF80_VENDOR3, NA, FALSE) \
|
|
FIELD( 80, 0, EDX, 0, 32, LEAF80_VENDOR2, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_81 \
|
|
FIELD( 81, 0, EAX, 0, 32, UNKNOWN81EAX, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 0, 4, LEAF81_STEPPING, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 4, 4, LEAF81_MODEL, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 8, 4, LEAF81_FAMILY, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 12, 2, LEAF81_TYPE, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 16, 4, LEAF81_EXTENDED_MODEL, ANY, FALSE) \
|
|
FIELD( 81, 0, EAX, 20, 8, LEAF81_EXTENDED_FAMILY, ANY, FALSE) \
|
|
FIELD( 81, 0, EBX, 0, 32, UNKNOWN81EBX, ANY, FALSE) \
|
|
FIELD( 81, 0, EBX, 0, 16, LEAF81_BRAND_ID, ANY, FALSE) \
|
|
FIELD( 81, 0, EBX, 16, 16, UNDEF, ANY, FALSE) \
|
|
FLAG( 81, 0, ECX, 0, 1, LAHF64, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 1, 1, CMPLEGACY, ANY, FALSE) \
|
|
FLAG( 81, 0, ECX, 2, 1, SVM, YES, FALSE) \
|
|
FLAG( 81, 0, ECX, 3, 1, EXTAPICSPC, YES, FALSE) \
|
|
FLAG( 81, 0, ECX, 4, 1, CR8AVAIL, YES, FALSE) \
|
|
FLAG( 81, 0, ECX, 5, 1, ABM, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 6, 1, SSE4A, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 7, 1, MISALIGNED_SSE, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 8, 1, 3DNPREFETCH, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 9, 1, OSVW, ANY, FALSE) \
|
|
FLAG( 81, 0, ECX, 10, 1, IBS, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 11, 1, XOP, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 12, 1, SKINIT, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 13, 1, WATCHDOG, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 15, 1, LWP, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 16, 1, FMA4, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 17, 1, TCE, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 19, 1, NODEID_MSR, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 21, 1, TBM, YES, TRUE) \
|
|
FLAG( 81, 0, ECX, 22, 1, TOPOLOGY, NO, FALSE) \
|
|
FLAG( 81, 0, ECX, 23, 1, PERFCORE, ANY, TRUE) \
|
|
FLAG( 81, 0, EDX, 0, 1, LEAF81_FPU, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 1, 1, LEAF81_VME, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 2, 1, LEAF81_DE, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 3, 1, LEAF81_PSE, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 4, 1, LEAF81_TSC, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 5, 1, LEAF81_MSR, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 6, 1, LEAF81_PAE, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 7, 1, LEAF81_MCE, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 8, 1, LEAF81_CX8, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 9, 1, LEAF81_APIC, ANY, FALSE) \
|
|
FLAG( 81, 0, EDX, 11, 1, SYSC, ANY, TRUE) \
|
|
FLAG( 81, 0, EDX, 12, 1, LEAF81_MTRR, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 13, 1, LEAF81_PGE, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 14, 1, LEAF81_MCA, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 15, 1, LEAF81_CMOV, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 16, 1, LEAF81_PAT, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 17, 1, LEAF81_PSE36, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 20, 1, NX, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 22, 1, MMXEXT, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 23, 1, LEAF81_MMX, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 24, 1, LEAF81_FXSR, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 25, 1, FFXSR, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 26, 1, PDPE1GB, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 27, 1, RDTSCP, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 29, 1, LM, YES, FALSE) \
|
|
FLAG( 81, 0, EDX, 30, 1, 3DNOWPLUS, YES, TRUE) \
|
|
FLAG( 81, 0, EDX, 31, 1, 3DNOW, YES, TRUE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_82 \
|
|
FIELD( 82, 0, EAX, 0, 32, LEAF82_BRAND_STRING_EAX, NA, FALSE) \
|
|
FIELD( 82, 0, EBX, 0, 32, LEAF82_BRAND_STRING_EBX, NA, FALSE) \
|
|
FIELD( 82, 0, ECX, 0, 32, LEAF82_BRAND_STRING_ECX, NA, FALSE) \
|
|
FIELD( 82, 0, EDX, 0, 32, LEAF82_BRAND_STRING_EDX, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_83 \
|
|
FIELD( 83, 0, EAX, 0, 32, LEAF83_BRAND_STRING_EAX, NA, FALSE) \
|
|
FIELD( 83, 0, EBX, 0, 32, LEAF83_BRAND_STRING_EBX, NA, FALSE) \
|
|
FIELD( 83, 0, ECX, 0, 32, LEAF83_BRAND_STRING_ECX, NA, FALSE) \
|
|
FIELD( 83, 0, EDX, 0, 32, LEAF83_BRAND_STRING_EDX, NA, FALSE)
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_84 \
|
|
FIELD( 84, 0, EAX, 0, 32, LEAF84_BRAND_STRING_EAX, NA, FALSE) \
|
|
FIELD( 84, 0, EBX, 0, 32, LEAF84_BRAND_STRING_EBX, NA, FALSE) \
|
|
FIELD( 84, 0, ECX, 0, 32, LEAF84_BRAND_STRING_ECX, NA, FALSE) \
|
|
FIELD( 84, 0, EDX, 0, 32, LEAF84_BRAND_STRING_EDX, NA, FALSE)
|
|
|
|
#define CPUID_8A_EDX_11 \
|
|
FLAG( 8A, 0, EDX, 11, 1, SVMEDX_RSVD1, NO, FALSE)
|
|
#define CPUID_8A_EDX_14_31 \
|
|
FIELD( 8A, 0, EDX, 14, 18, SVMEDX_RSVD2, NO, FALSE)
|
|
|
|
/* LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_8x \
|
|
FIELD( 85, 0, EAX, 0, 8, ITLB_ENTRIES_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EAX, 8, 8, ITLB_ASSOC_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EAX, 16, 8, DTLB_ENTRIES_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EAX, 24, 8, DTLB_ASSOC_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EBX, 0, 8, ITLB_ENTRIES_4K_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EBX, 8, 8, ITLB_ASSOC_4K_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EBX, 16, 8, DTLB_ENTRIES_4K_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, EBX, 24, 8, DTLB_ASSOC_4K_PGS, NA, FALSE) \
|
|
FIELD( 85, 0, ECX, 0, 8, L1_DCACHE_LINE_SIZE, NA, FALSE) \
|
|
FIELD( 85, 0, ECX, 8, 8, L1_DCACHE_LINES_PER_TAG, NA, FALSE) \
|
|
FIELD( 85, 0, ECX, 16, 8, L1_DCACHE_ASSOC, NA, FALSE) \
|
|
FIELD( 85, 0, ECX, 24, 8, L1_DCACHE_SIZE, NA, FALSE) \
|
|
FIELD( 85, 0, EDX, 0, 8, L1_ICACHE_LINE_SIZE, NA, FALSE) \
|
|
FIELD( 85, 0, EDX, 8, 8, L1_ICACHE_LINES_PER_TAG, NA, FALSE) \
|
|
FIELD( 85, 0, EDX, 16, 8, L1_ICACHE_ASSOC, NA, FALSE) \
|
|
FIELD( 85, 0, EDX, 24, 8, L1_ICACHE_SIZE, NA, FALSE) \
|
|
FIELD( 86, 0, EAX, 0, 12, L2_ITLB_ENTRIES_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EAX, 12, 4, L2_ITLB_ASSOC_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EAX, 16, 12, L2_DTLB_ENTRIES_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EAX, 28, 4, L2_DTLB_ASSOC_2M4M_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EBX, 0, 12, L2_ITLB_ENTRIES_4K_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EBX, 12, 4, L2_ITLB_ASSOC_4K_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EBX, 16, 12, L2_DTLB_ENTRIES_4K_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, EBX, 28, 4, L2_DTLB_ASSOC_4K_PGS, NA, FALSE) \
|
|
FIELD( 86, 0, ECX, 0, 8, L2CACHE_LINE, NA, FALSE) \
|
|
FIELD( 86, 0, ECX, 8, 4, L2CACHE_LINE_PER_TAG, NA, FALSE) \
|
|
FIELD( 86, 0, ECX, 12, 4, L2CACHE_WAYS, NA, FALSE) \
|
|
FIELD( 86, 0, ECX, 16, 16, L2CACHE_SIZE, NA, FALSE) \
|
|
FIELD( 86, 0, EDX, 0, 8, L3CACHE_LINE, NA, FALSE) \
|
|
FIELD( 86, 0, EDX, 8, 4, L3CACHE_LINE_PER_TAG, NA, FALSE) \
|
|
FIELD( 86, 0, EDX, 12, 4, L3CACHE_WAYS, NA, FALSE) \
|
|
FIELD( 86, 0, EDX, 18, 14, L3CACHE_SIZE, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 0, 1, TS, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 1, 1, FID, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 2, 1, VID, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 3, 1, TTP, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 4, 1, LEAF87_TM, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 5, 1, STC, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 6, 1, 100MHZSTEPS, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 7, 1, HWPSTATE, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 8, 1, TSC_INVARIANT, NA, FALSE) \
|
|
FLAG( 87, 0, EDX, 9, 1, CORE_PERF_BOOST, NA, FALSE) \
|
|
FIELD( 88, 0, EAX, 0, 8, PHYS_BITS, NA, FALSE) \
|
|
FIELD( 88, 0, EAX, 8, 8, VIRT_BITS, NA, FALSE) \
|
|
FIELD( 88, 0, EAX, 16, 8, GUEST_PHYS_ADDR_SZ, NA, FALSE) \
|
|
FIELD( 88, 0, ECX, 0, 8, LEAF88_CORE_COUNT, NA, FALSE) \
|
|
FIELD( 88, 0, ECX, 12, 4, APICID_COREID_SIZE, NA, FALSE) \
|
|
FIELD( 8A, 0, EAX, 0, 8, SVM_REVISION, YES, FALSE) \
|
|
FLAG( 8A, 0, EAX, 8, 1, SVM_HYPERVISOR, NO, FALSE) \
|
|
FIELD( 8A, 0, EAX, 9, 23, SVMEAX_RSVD, NO, FALSE) \
|
|
FIELD( 8A, 0, EBX, 0, 32, SVM_NUM_ASIDS, YES, FALSE) \
|
|
FIELD( 8A, 0, ECX, 0, 32, SVMECX_RSVD, NO, FALSE) \
|
|
FLAG( 8A, 0, EDX, 0, 1, SVM_NPT, YES, FALSE) \
|
|
FLAG( 8A, 0, EDX, 1, 1, SVM_LBR, NO, FALSE) \
|
|
FLAG( 8A, 0, EDX, 2, 1, SVM_LOCK, ANY, FALSE) \
|
|
FLAG( 8A, 0, EDX, 3, 1, SVM_NRIP, YES, FALSE) \
|
|
FLAG( 8A, 0, EDX, 4, 1, SVM_TSC_RATE_MSR, NO, FALSE) \
|
|
FLAG( 8A, 0, EDX, 5, 1, SVM_VMCB_CLEAN, YES, FALSE) \
|
|
FLAG( 8A, 0, EDX, 6, 1, SVM_FLUSH_BY_ASID, YES, FALSE) \
|
|
FLAG( 8A, 0, EDX, 7, 1, SVM_DECODE_ASSISTS, YES, FALSE) \
|
|
FIELD( 8A, 0, EDX, 8, 2, SVMEDX_RSVD0, NO, FALSE) \
|
|
FLAG( 8A, 0, EDX, 10, 1, SVM_PAUSE_FILTER, NO, FALSE) \
|
|
CPUID_8A_EDX_11 \
|
|
FLAG( 8A, 0, EDX, 12, 1, SVM_PAUSE_THRESHOLD, NO, FALSE) \
|
|
FLAG( 8A, 0, EDX, 13, 1, SVM_AVIC, NO, FALSE) \
|
|
CPUID_8A_EDX_14_31
|
|
|
|
/* LEVEL, SUB-LEVEL, REG, POS, SIZE, NAME, MON SUPP, CPL3 */
|
|
#define CPUID_FIELD_DATA_LEVEL_81x \
|
|
FIELD(819, 0, EAX, 0, 12, L1_ITLB_ENTRIES_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EAX, 12, 4, L1_ITLB_ASSOC_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EAX, 16, 12, L1_DTLB_ENTRIES_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EAX, 28, 4, L1_DTLB_ASSOC_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EBX, 0, 12, L2_ITLB_ENTRIES_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EBX, 12, 4, L2_ITLB_ASSOC_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EBX, 16, 12, L2_DTLB_ENTRIES_1G_PGS, NA, FALSE) \
|
|
FIELD(819, 0, EBX, 28, 4, L2_DTLB_ASSOC_1G_PGS, NA, FALSE) \
|
|
FLAG( 81A, 0, EAX, 0, 1, FP128, NA, FALSE) \
|
|
FLAG( 81A, 0, EAX, 1, 1, MOVU, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 0, 1, IBS_FFV, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 1, 1, IBS_FETCHSAM, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 2, 1, IBS_OPSAM, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 3, 1, RW_OPCOUNT, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 4, 1, OPCOUNT, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 5, 1, BRANCH_TARGET_ADDR, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 6, 1, OPCOUNT_EXT, NA, FALSE) \
|
|
FLAG( 81B, 0, EAX, 7, 1, RIP_INVALID_CHECK, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 0, 1, LWP_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 1, 1, LWP_VAL_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 2, 1, LWP_IRE_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 3, 1, LWP_BRE_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 4, 1, LWP_DME_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 5, 1, LWP_CNH_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 6, 1, LWP_RNH_AVAIL, NA, FALSE) \
|
|
FLAG( 81C, 0, EAX, 31, 1, LWP_INT_AVAIL, NA, FALSE) \
|
|
FIELD(81C, 0, EBX, 0, 8, LWP_CB_SIZE, NA, FALSE) \
|
|
FIELD(81C, 0, EBX, 8, 8, LWP_EVENT_SIZE, NA, FALSE) \
|
|
FIELD(81C, 0, EBX, 16, 8, LWP_MAX_EVENTS, NA, FALSE) \
|
|
FIELD(81C, 0, EBX, 24, 8, LWP_EVENT_OFFSET, NA, FALSE) \
|
|
FIELD(81C, 0, ECX, 0, 4, LWP_LATENCY_MAX, NA, FALSE) \
|
|
FLAG( 81C, 0, ECX, 5, 1, LWP_DATA_ADDR_VALID, NA, FALSE) \
|
|
FIELD(81C, 0, ECX, 6, 3, LWP_LATENCY_ROUND, NA, FALSE) \
|
|
FIELD(81C, 0, ECX, 9, 7, LWP_VERSION, NA, FALSE) \
|
|
FIELD(81C, 0, ECX, 16, 8, LWP_MIN_BUF_SIZE, NA, FALSE) \
|
|
FLAG( 81C, 0, ECX, 28, 1, LWP_BRANCH_PRED, NA, FALSE) \
|
|
FLAG( 81C, 0, ECX, 29, 1, LWP_IP_FILTERING, NA, FALSE) \
|
|
FLAG( 81C, 0, ECX, 30, 1, LWP_CACHE_LEVEL, NA, FALSE) \
|
|
FLAG( 81C, 0, ECX, 31, 1, LWP_CACHE_LATENCY, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 0, 1, LWP_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 1, 1, LWP_VAL_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 2, 1, LWP_IRE_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 3, 1, LWP_BRE_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 4, 1, LWP_DME_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 5, 1, LWP_CNH_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 6, 1, LWP_RNH_SUPPORTED, NA, FALSE) \
|
|
FLAG( 81C, 0, EDX, 31, 1, LWP_INT_SUPPORTED, NA, FALSE) \
|
|
FIELD(81D, 0, EAX, 0, 5, LEAF81D_CACHE_TYPE, NA, FALSE) \
|
|
FIELD(81D, 0, EAX, 5, 3, LEAF81D_CACHE_LEVEL, NA, FALSE) \
|
|
FLAG( 81D, 0, EAX, 8, 1, LEAF81D_CACHE_SELF_INIT, NA, FALSE) \
|
|
FLAG( 81D, 0, EAX, 9, 1, LEAF81D_CACHE_FULLY_ASSOC, NA, FALSE) \
|
|
FIELD(81D, 0, EAX, 14, 12, LEAF81D_NUM_SHARING_CACHE, NA, FALSE) \
|
|
FIELD(81D, 0, EBX, 0, 12, LEAF81D_CACHE_LINE_SIZE, NA, FALSE) \
|
|
FIELD(81D, 0, EBX, 12, 10, LEAF81D_CACHE_PHYS_PARTITIONS, NA, FALSE) \
|
|
FIELD(81D, 0, EBX, 22, 10, LEAF81D_CACHE_WAYS, NA, FALSE) \
|
|
FIELD(81D, 0, ECX, 0, 32, LEAF81D_CACHE_NUM_SETS, NA, FALSE) \
|
|
FLAG( 81D, 0, EDX, 0, 1, LEAF81D_CACHE_WBINVD, NA, FALSE) \
|
|
FLAG( 81D, 0, EDX, 1, 1, LEAF81D_CACHE_INCLUSIVE, NA, FALSE) \
|
|
FIELD(81E, 0, EAX, 0, 32, EXTENDED_APICID, NA, FALSE) \
|
|
FIELD(81E, 0, EBX, 0, 8, COMPUTE_UNIT_ID, NA, FALSE) \
|
|
FIELD(81E, 0, EBX, 8, 2, CORES_PER_COMPUTE_UNIT, NA, FALSE) \
|
|
FIELD(81E, 0, ECX, 0, 8, NODEID_VAL, NA, FALSE) \
|
|
FIELD(81E, 0, ECX, 8, 3, NODES_PER_PKG, NA, FALSE)
|
|
|
|
#define INTEL_CPUID_FIELD_DATA
|
|
|
|
#define AMD_CPUID_FIELD_DATA
|
|
|
|
#define CPUID_FIELD_DATA \
|
|
CPUID_FIELD_DATA_LEVEL_0 \
|
|
CPUID_FIELD_DATA_LEVEL_1 \
|
|
CPUID_FIELD_DATA_LEVEL_2 \
|
|
CPUID_FIELD_DATA_LEVEL_4 \
|
|
CPUID_FIELD_DATA_LEVEL_5 \
|
|
CPUID_FIELD_DATA_LEVEL_6 \
|
|
CPUID_FIELD_DATA_LEVEL_7 \
|
|
CPUID_FIELD_DATA_LEVEL_A \
|
|
CPUID_FIELD_DATA_LEVEL_B \
|
|
CPUID_FIELD_DATA_LEVEL_D \
|
|
CPUID_FIELD_DATA_LEVEL_400 \
|
|
CPUID_FIELD_DATA_LEVEL_410 \
|
|
CPUID_FIELD_DATA_LEVEL_80 \
|
|
CPUID_FIELD_DATA_LEVEL_81 \
|
|
CPUID_FIELD_DATA_LEVEL_82 \
|
|
CPUID_FIELD_DATA_LEVEL_83 \
|
|
CPUID_FIELD_DATA_LEVEL_84 \
|
|
CPUID_FIELD_DATA_LEVEL_8x \
|
|
CPUID_FIELD_DATA_LEVEL_81x \
|
|
INTEL_CPUID_FIELD_DATA \
|
|
AMD_CPUID_FIELD_DATA
|
|
|
|
/*
|
|
* Define all field and flag values as an enum. The result is a full
|
|
* set of values taken from the table above in the form:
|
|
*
|
|
* CPUID_<name>_MASK == mask for feature/field
|
|
* CPUID_<name>_SHIFT == offset of field
|
|
*
|
|
* e.g. - CPUID_VIRT_BITS_MASK = 0xff00
|
|
* - CPUID_VIRT_BITS_SHIFT = 8
|
|
*
|
|
* Note: The MASK definitions must use some gymnastics to get
|
|
* around a warning when shifting left by 32.
|
|
*/
|
|
#define VMW_BIT_MASK(shift) (((1 << (shift - 1)) << 1) - 1)
|
|
|
|
#define FIELD(lvl, ecxIn, reg, bitpos, size, name, s, c3) \
|
|
CPUID_##name##_SHIFT = bitpos, \
|
|
CPUID_##name##_MASK = VMW_BIT_MASK(size) << bitpos, \
|
|
CPUID_INTERNAL_SHIFT_##name = bitpos, \
|
|
CPUID_INTERNAL_MASK_##name = VMW_BIT_MASK(size) << bitpos, \
|
|
CPUID_INTERNAL_REG_##name = CPUID_REG_##reg, \
|
|
CPUID_INTERNAL_EAXIN_##name = CPUID_LEVEL_VAL_##lvl, \
|
|
CPUID_INTERNAL_ECXIN_##name = ecxIn,
|
|
|
|
#define FLAG FIELD
|
|
|
|
enum {
|
|
/* Define data for every CPUID field we have */
|
|
CPUID_FIELD_DATA
|
|
};
|
|
#undef VMW_BIT_MASK
|
|
#undef FIELD
|
|
#undef FLAG
|
|
|
|
/*
|
|
* Legal CPUID config file mask characters. For a description of the
|
|
* cpuid masking system, please see:
|
|
*
|
|
* http://vmweb.vmware.com/~mts/cgi-bin/view.cgi/Apps/CpuMigrationChecks
|
|
*/
|
|
|
|
#define CPUID_MASK_HIDE_CHR '0'
|
|
#define CPUID_MASK_HIDE_STR "0"
|
|
#define CPUID_MASK_FORCE_CHR '1'
|
|
#define CPUID_MASK_FORCE_STR "1"
|
|
#define CPUID_MASK_PASS_CHR '-'
|
|
#define CPUID_MASK_PASS_STR "-"
|
|
#define CPUID_MASK_TRUE_CHR 'T'
|
|
#define CPUID_MASK_TRUE_STR "T"
|
|
#define CPUID_MASK_FALSE_CHR 'F'
|
|
#define CPUID_MASK_FALSE_STR "F"
|
|
#define CPUID_MASK_IGNORE_CHR 'X'
|
|
#define CPUID_MASK_IGNORE_STR "X"
|
|
#define CPUID_MASK_HOST_CHR 'H'
|
|
#define CPUID_MASK_HOST_STR "H"
|
|
#define CPUID_MASK_RSVD_CHR 'R'
|
|
#define CPUID_MASK_RSVD_STR "R"
|
|
#define CPUID_MASK_INSTALL_CHR 'I'
|
|
#define CPUID_MASK_INSTALL_STR "I"
|
|
|
|
/*
|
|
* When LM is disabled, we overlay the following masks onto the
|
|
* guest's default masks. Any level that is not defined below should
|
|
* be treated as all "-"s
|
|
*/
|
|
|
|
#define CPT_ID1ECX_LM_DISABLED "----:----:----:----:--0-:----:----:----"
|
|
#define CPT_ID81EDX_LM_DISABLED "--0-:----:----:----:----:----:----:----"
|
|
#define CPT_ID81ECX_LM_DISABLED "----:----:----:----:----:----:----:---0"
|
|
|
|
#define CPT_GET_LM_DISABLED_MASK(lvl, reg) \
|
|
((lvl == 1 && reg == CPUID_REG_ECX) ? CPT_ID1ECX_LM_DISABLED : \
|
|
(lvl == 0x80000001 && reg == CPUID_REG_ECX) ? CPT_ID81ECX_LM_DISABLED : \
|
|
(lvl == 0x80000001 && reg == CPUID_REG_EDX) ? CPT_ID81EDX_LM_DISABLED : \
|
|
NULL)
|
|
|
|
/*
|
|
* CPUID_MASK --
|
|
* CPUID_SHIFT --
|
|
* CPUID_ISSET --
|
|
* CPUID_GET --
|
|
* CPUID_SET --
|
|
* CPUID_CLEAR --
|
|
* CPUID_SETTO --
|
|
*
|
|
* Accessor macros for all CPUID consts/fields/flags. Level and reg are not
|
|
* required, but are used to force compile-time asserts which help verify that
|
|
* the flag is being used on the right CPUID input and result register.
|
|
*
|
|
* Note: ASSERT_ON_COMPILE is duplicated rather than factored into its own
|
|
* macro, because token concatenation does not work as expected if an input is
|
|
* #defined (e.g. APIC) when macros are nested. Also, compound statements
|
|
* within parenthes is a GCC extension, so we must use runtime asserts with
|
|
* other compilers.
|
|
*/
|
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
|
|
#define CPUID_MASK(eaxIn, reg, flag) \
|
|
({ \
|
|
ASSERT_ON_COMPILE(eaxIn == CPUID_INTERNAL_EAXIN_##flag && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##flag); \
|
|
CPUID_INTERNAL_MASK_##flag; \
|
|
})
|
|
|
|
#define CPUID_SHIFT(eaxIn, reg, flag) \
|
|
({ \
|
|
ASSERT_ON_COMPILE(eaxIn == CPUID_INTERNAL_EAXIN_##flag && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##flag); \
|
|
CPUID_INTERNAL_SHIFT_##flag; \
|
|
})
|
|
|
|
#define CPUID_ISSET(eaxIn, reg, flag, data) \
|
|
({ \
|
|
ASSERT_ON_COMPILE(eaxIn == CPUID_INTERNAL_EAXIN_##flag && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##flag); \
|
|
(((data) & CPUID_INTERNAL_MASK_##flag) != 0); \
|
|
})
|
|
|
|
#define CPUID_GET(eaxIn, reg, field, data) \
|
|
({ \
|
|
ASSERT_ON_COMPILE(eaxIn == CPUID_INTERNAL_EAXIN_##field && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##field); \
|
|
(((uint32)(data) & CPUID_INTERNAL_MASK_##field) >> \
|
|
CPUID_INTERNAL_SHIFT_##field); \
|
|
})
|
|
|
|
#else
|
|
|
|
/*
|
|
* CPUIDCheck --
|
|
*
|
|
* Return val after verifying parameters.
|
|
*/
|
|
|
|
static INLINE uint32
|
|
CPUIDCheck(int32 eaxIn, int32 eaxInCheck,
|
|
CpuidReg reg, CpuidReg regCheck, uint32 val)
|
|
{
|
|
ASSERT(eaxIn == eaxInCheck && reg == regCheck);
|
|
return val;
|
|
}
|
|
|
|
#define CPUID_MASK(eaxIn, reg, flag) \
|
|
CPUIDCheck(eaxIn, CPUID_INTERNAL_EAXIN_##flag, \
|
|
CPUID_REG_##reg, (CpuidReg)CPUID_INTERNAL_REG_##flag, \
|
|
CPUID_INTERNAL_MASK_##flag)
|
|
|
|
#define CPUID_SHIFT(eaxIn, reg, flag) \
|
|
CPUIDCheck(eaxIn, CPUID_INTERNAL_EAXIN_##flag, \
|
|
CPUID_REG_##reg, (CpuidReg)CPUID_INTERNAL_REG_##flag, \
|
|
CPUID_INTERNAL_SHIFT_##flag)
|
|
|
|
#define CPUID_ISSET(eaxIn, reg, flag, data) \
|
|
(CPUIDCheck(eaxIn, CPUID_INTERNAL_EAXIN_##flag, \
|
|
CPUID_REG_##reg, (CpuidReg)CPUID_INTERNAL_REG_##flag, \
|
|
CPUID_INTERNAL_MASK_##flag & (data)) != 0)
|
|
|
|
#define CPUID_GET(eaxIn, reg, field, data) \
|
|
CPUIDCheck(eaxIn, CPUID_INTERNAL_EAXIN_##field, \
|
|
CPUID_REG_##reg, (CpuidReg)CPUID_INTERNAL_REG_##field, \
|
|
((uint32)(data) & CPUID_INTERNAL_MASK_##field) >> \
|
|
CPUID_INTERNAL_SHIFT_##field)
|
|
|
|
#endif
|
|
|
|
|
|
#define CPUID_SET(eaxIn, reg, flag, dataPtr) \
|
|
do { \
|
|
ASSERT_ON_COMPILE( \
|
|
(uint32)eaxIn == (uint32)CPUID_INTERNAL_EAXIN_##flag && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##flag); \
|
|
*(dataPtr) |= CPUID_INTERNAL_MASK_##flag; \
|
|
} while (0)
|
|
|
|
#define CPUID_CLEAR(eaxIn, reg, flag, dataPtr) \
|
|
do { \
|
|
ASSERT_ON_COMPILE( \
|
|
(uint32)eaxIn == (uint32)CPUID_INTERNAL_EAXIN_##flag && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##flag); \
|
|
*(dataPtr) &= ~CPUID_INTERNAL_MASK_##flag; \
|
|
} while (0)
|
|
|
|
#define CPUID_SETTO(eaxIn, reg, field, dataPtr, val) \
|
|
do { \
|
|
uint32 _v = val; \
|
|
uint32 *_d = dataPtr; \
|
|
ASSERT_ON_COMPILE( \
|
|
(uint32)eaxIn == (uint32)CPUID_INTERNAL_EAXIN_##field && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##field); \
|
|
*_d = (*_d & ~CPUID_INTERNAL_MASK_##field) | \
|
|
(_v << CPUID_INTERNAL_SHIFT_##field); \
|
|
ASSERT(_v == (*_d & CPUID_INTERNAL_MASK_##field) >> \
|
|
CPUID_INTERNAL_SHIFT_##field); \
|
|
} while (0)
|
|
|
|
#define CPUID_SETTO_SAFE(eaxIn, reg, field, dataPtr, val) \
|
|
do { \
|
|
uint32 _v = val & \
|
|
(CPUID_INTERNAL_MASK_##field >> CPUID_INTERNAL_SHIFT_##field); \
|
|
uint32 *_d = dataPtr; \
|
|
ASSERT_ON_COMPILE( \
|
|
(uint32)eaxIn == (uint32)CPUID_INTERNAL_EAXIN_##field && \
|
|
CPUID_REG_##reg == (CpuidReg)CPUID_INTERNAL_REG_##field); \
|
|
*_d = (*_d & ~CPUID_INTERNAL_MASK_##field) | \
|
|
(_v << CPUID_INTERNAL_SHIFT_##field); \
|
|
} while (0)
|
|
|
|
|
|
/*
|
|
* Definitions of various fields' values and more complicated
|
|
* macros/functions for reading cpuid fields.
|
|
*/
|
|
|
|
#define CPUID_FAMILY_EXTENDED 15
|
|
|
|
/* Effective Intel CPU Families */
|
|
#define CPUID_FAMILY_486 4
|
|
#define CPUID_FAMILY_P5 5
|
|
#define CPUID_FAMILY_P6 6
|
|
#define CPUID_FAMILY_P4 15
|
|
|
|
/* Effective AMD CPU Families */
|
|
#define CPUID_FAMILY_5x86 4
|
|
#define CPUID_FAMILY_K5 5
|
|
#define CPUID_FAMILY_K6 5
|
|
#define CPUID_FAMILY_K7 6
|
|
#define CPUID_FAMILY_K8 15
|
|
#define CPUID_FAMILY_K8L 16
|
|
#define CPUID_FAMILY_K8MOBILE 17
|
|
#define CPUID_FAMILY_LLANO 18
|
|
#define CPUID_FAMILY_BOBCAT 20
|
|
#define CPUID_FAMILY_BULLDOZER 21 // Bulldozer Piledriver Steamroller
|
|
#define CPUID_FAMILY_KYOTO 22
|
|
|
|
/* Effective VIA CPU Families */
|
|
#define CPUID_FAMILY_C7 6
|
|
|
|
/* Intel model information */
|
|
#define CPUID_MODEL_PPRO 1
|
|
#define CPUID_MODEL_PII_03 3
|
|
#define CPUID_MODEL_PII_05 5
|
|
#define CPUID_MODEL_CELERON_06 6
|
|
#define CPUID_MODEL_PM_09 9
|
|
#define CPUID_MODEL_PM_0D 13
|
|
#define CPUID_MODEL_PM_0E 14 // Yonah / Sossaman
|
|
#define CPUID_MODEL_CORE_0F 15 // Conroe / Merom
|
|
#define CPUID_MODEL_CORE_17 0x17 // Penryn
|
|
#define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown
|
|
#define CPUID_MODEL_ATOM_1C 0x1c // Silverthorne / Diamondville
|
|
#define CPUID_MODEL_CORE_1D 0x1d // Dunnington
|
|
#define CPUID_MODEL_NEHALEM_1E 0x1e // Lynnfield
|
|
#define CPUID_MODEL_NEHALEM_1F 0x1f // Havendale
|
|
#define CPUID_MODEL_NEHALEM_25 0x25 // Westmere / Clarkdale
|
|
#define CPUID_MODEL_ATOM_26 0x26 // Lincroft
|
|
#define CPUID_MODEL_ATOM_27 0x27 // Saltwell
|
|
#define CPUID_MODEL_SANDYBRIDGE_2A 0x2a // Sandybridge (desktop/mobile)
|
|
#define CPUID_MODEL_SANDYBRIDGE_2D 0x2d // Sandybridge-EP
|
|
#define CPUID_MODEL_NEHALEM_2C 0x2c // Westmere-EP
|
|
#define CPUID_MODEL_NEHALEM_2E 0x2e // Nehalem-EX
|
|
#define CPUID_MODEL_NEHALEM_2F 0x2f // Westmere-EX
|
|
#define CPUID_MODEL_ATOM_35 0x35 // Cloverview
|
|
#define CPUID_MODEL_ATOM_36 0x36 // Cedarview
|
|
#define CPUID_MODEL_ATOM_37 0x37 // Bay Trail
|
|
#define CPUID_MODEL_SANDYBRIDGE_3A 0x3a // Ivy Bridge
|
|
#define CPUID_MODEL_SANDYBRIDGE_3E 0x3e // Ivy Bridge-EP
|
|
#define CPUID_MODEL_HASWELL_3C 0x3c // Haswell DT
|
|
#define CPUID_MODEL_HASWELL_45 0x45 // Haswell Ultrathin
|
|
#define CPUID_MODEL_HASWELL_46 0x46 // Haswell (Crystal Well)
|
|
#define CPUID_MODEL_ATOM_4A 0x4a // Future Silvermont
|
|
#define CPUID_MODEL_ATOM_4D 0x4d // Avoton
|
|
#define CPUID_MODEL_ATOM_5A 0x5a // Future Silvermont
|
|
#define CPUID_MODEL_ATOM_5D 0x5d // Future Silvermont
|
|
|
|
|
|
#define CPUID_MODEL_PIII_07 7
|
|
#define CPUID_MODEL_PIII_08 8
|
|
#define CPUID_MODEL_PIII_0A 10
|
|
|
|
/* AMD model information */
|
|
#define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (Opteron & Phenom)
|
|
#define CPUID_MODEL_SHANGHAI_04 0x04 // Shanghai RB
|
|
#define CPUID_MODEL_SHANGHAI_05 0x05 // Shanghai BL
|
|
#define CPUID_MODEL_SHANGHAI_06 0x06 // Shanghai DA
|
|
#define CPUID_MODEL_ISTANBUL_MAGNY_08 0x08 // Istanbul (6 core) & Magny-cours (12) HY
|
|
#define CPUID_MODEL_ISTANBUL_MAGNY_09 0x09 // HY - G34 package
|
|
#define CPUID_MODEL_PHAROAH_HOUND_0A 0x0A // Pharoah Hound
|
|
#define CPUID_MODEL_PILEDRIVER_1F 0x1F // Max piledriver model defined in BKDG
|
|
#define CPUID_MODEL_PILEDRIVER_10 0x10 // family == CPUID_FAMILY_BULLDOZER
|
|
#define CPUID_MODEL_PILEDRIVER_02 0x02 // family == CPUID_FAMILY_BULLDOZER
|
|
#define CPUID_MODEL_OPTERON_REVF_41 0x41 // family == CPUID_FAMILY_K8
|
|
#define CPUID_MODEL_KYOTO_00 0x00 // family == CPUID_FAMILY_KYOTO
|
|
|
|
/* VIA model information */
|
|
#define CPUID_MODEL_NANO 15 // Isaiah
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* CPUID_IsVendor{AMD,Intel,VIA} --
|
|
*
|
|
* Determines if the vendor string in cpuid id0 is from {AMD,Intel,VIA}.
|
|
*
|
|
* Results:
|
|
* True iff vendor string is CPUID_{AMD,INTEL,VIA}_VENDOR_STRING
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_IsRawVendor(CPUIDRegs *id0, const char* vendor)
|
|
{
|
|
// hard to get strcmp() in some environments, so do it in the raw
|
|
return (id0->ebx == *(const uint32 *) (vendor + 0) &&
|
|
id0->ecx == *(const uint32 *) (vendor + 4) &&
|
|
id0->edx == *(const uint32 *) (vendor + 8));
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_IsVendorAMD(CPUIDRegs *id0)
|
|
{
|
|
return CPUID_IsRawVendor(id0, CPUID_AMD_VENDOR_STRING);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_IsVendorIntel(CPUIDRegs *id0)
|
|
{
|
|
return CPUID_IsRawVendor(id0, CPUID_INTEL_VENDOR_STRING);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_IsVendorVIA(CPUIDRegs *id0)
|
|
{
|
|
return CPUID_IsRawVendor(id0, CPUID_VIA_VENDOR_STRING);
|
|
}
|
|
|
|
static INLINE uint32
|
|
CPUID_EFFECTIVE_FAMILY(uint32 v) /* %eax from CPUID with %eax=1. */
|
|
{
|
|
uint32 f = CPUID_GET(1, EAX, FAMILY, v);
|
|
return f != CPUID_FAMILY_EXTENDED ? f : f +
|
|
CPUID_GET(1, EAX, EXTENDED_FAMILY, v);
|
|
}
|
|
|
|
/* Normally only used when FAMILY==CPUID_FAMILY_EXTENDED, but Intel is
|
|
* now using the extended model field for FAMILY==CPUID_FAMILY_P6 to
|
|
* refer to the newer Core2 CPUs
|
|
*/
|
|
static INLINE uint32
|
|
CPUID_EFFECTIVE_MODEL(uint32 v) /* %eax from CPUID with %eax=1. */
|
|
{
|
|
uint32 m = CPUID_GET(1, EAX, MODEL, v);
|
|
uint32 em = CPUID_GET(1, EAX, EXTENDED_MODEL, v);
|
|
return m + (em << 4);
|
|
}
|
|
|
|
/*
|
|
* Notice that CPUID families for Intel and AMD overlap. The following macros
|
|
* should only be used AFTER the manufacturer has been established (through
|
|
* the use of CPUID standard function 0).
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_486(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_486;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_P5(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P5;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_P6(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P6;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_PENTIUM4(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P4;
|
|
}
|
|
|
|
/*
|
|
* Intel Pentium M processors are Yonah/Sossaman or an older P-M
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_UARCH_IS_PENTIUM_M(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_09 ||
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0D ||
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0E);
|
|
}
|
|
|
|
/*
|
|
* Intel Core processors are Merom, Conroe, Woodcrest, Clovertown,
|
|
* Penryn, Dunnington, Kentsfield, Yorktown, Harpertown, ........
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
uint32 model = CPUID_EFFECTIVE_MODEL(v);
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
model >= CPUID_MODEL_CORE_0F &&
|
|
(model < CPUID_MODEL_NEHALEM_1A ||
|
|
model == CPUID_MODEL_CORE_1D);
|
|
}
|
|
|
|
/*
|
|
* Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield, Clarkdale.
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_NEHALEM_1A ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_1E ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_1F ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_25 ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_2C ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_2E ||
|
|
effectiveModel == CPUID_MODEL_NEHALEM_2F);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_UARCH_IS_SANDYBRIDGE(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_SANDYBRIDGE_2A ||
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_2D ||
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_3E ||
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_3A);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_UARCH_IS_HASWELL(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_HASWELL_3C ||
|
|
effectiveModel == CPUID_MODEL_HASWELL_45 ||
|
|
effectiveModel == CPUID_MODEL_HASWELL_46);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_CENTERTON(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_ATOM_1C;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_AVOTON(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_ATOM_4D;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_WESTMERE(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_NEHALEM_25 || // Clarkdale
|
|
effectiveModel == CPUID_MODEL_NEHALEM_2C || // Westmere-EP
|
|
effectiveModel == CPUID_MODEL_NEHALEM_2F); // Westmere-EX
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_SANDYBRIDGE(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_SANDYBRIDGE_2A ||
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_2D);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_IVYBRIDGE(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) && (
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_3E ||
|
|
effectiveModel == CPUID_MODEL_SANDYBRIDGE_3A);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_HASWELL(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is Intel. */
|
|
uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v);
|
|
|
|
return CPUID_FAMILY_IS_P6(v) &&
|
|
(effectiveModel == CPUID_MODEL_HASWELL_3C ||
|
|
effectiveModel == CPUID_MODEL_HASWELL_45 ||
|
|
effectiveModel == CPUID_MODEL_HASWELL_46);
|
|
}
|
|
|
|
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K7(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K7;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K8(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K8EXT(uint32 eax)
|
|
{
|
|
/*
|
|
* We check for this pattern often enough that it's
|
|
* worth a separate function, for syntactic sugar.
|
|
*/
|
|
return CPUID_FAMILY_IS_K8(eax) &&
|
|
CPUID_GET(1, EAX, EXTENDED_MODEL, eax) != 0;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K8L(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8L ||
|
|
CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_LLANO;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_LLANO(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_LLANO;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K8MOBILE(uint32 eax)
|
|
{
|
|
/* Essentially a K8 (not K8L) part, but with mobile features. */
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8MOBILE;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_K8STAR(uint32 eax)
|
|
{
|
|
/*
|
|
* Read function name as "K8*", as in wildcard.
|
|
* Matches K8 or K8L or K8MOBILE
|
|
*/
|
|
return CPUID_FAMILY_IS_K8(eax) || CPUID_FAMILY_IS_K8L(eax) ||
|
|
CPUID_FAMILY_IS_K8MOBILE(eax);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_BOBCAT(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BOBCAT;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_BULLDOZER(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BULLDOZER;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_FAMILY_IS_KYOTO(uint32 eax)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_KYOTO;
|
|
}
|
|
|
|
/*
|
|
* AMD Barcelona (of either Opteron or Phenom kind).
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is AMD. */
|
|
return CPUID_EFFECTIVE_FAMILY(v) == CPUID_FAMILY_K8L &&
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02;
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_SHANGHAI(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is AMD. */
|
|
return CPUID_EFFECTIVE_FAMILY(v) == CPUID_FAMILY_K8L &&
|
|
(CPUID_MODEL_SHANGHAI_04 <= CPUID_EFFECTIVE_MODEL(v) &&
|
|
CPUID_EFFECTIVE_MODEL(v) <= CPUID_MODEL_SHANGHAI_06);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_ISTANBUL_MAGNY(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is AMD. */
|
|
return CPUID_EFFECTIVE_FAMILY(v) == CPUID_FAMILY_K8L &&
|
|
(CPUID_MODEL_ISTANBUL_MAGNY_08 <= CPUID_EFFECTIVE_MODEL(v) &&
|
|
CPUID_EFFECTIVE_MODEL(v) <= CPUID_MODEL_ISTANBUL_MAGNY_09);
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_PHAROAH_HOUND(uint32 v) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
/* Assumes the CPU manufacturer is AMD. */
|
|
return CPUID_EFFECTIVE_FAMILY(v) == CPUID_FAMILY_K8L &&
|
|
CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PHAROAH_HOUND_0A;
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_BULLDOZER(uint32 eax)
|
|
{
|
|
/*
|
|
* Bulldozer is models of family 0x15 that are below 10 excluding
|
|
* Piledriver 02.
|
|
*/
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BULLDOZER &&
|
|
CPUID_EFFECTIVE_MODEL(eax) < CPUID_MODEL_PILEDRIVER_10 &&
|
|
CPUID_EFFECTIVE_MODEL(eax) != CPUID_MODEL_PILEDRIVER_02;
|
|
}
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_PILEDRIVER(uint32 eax)
|
|
{
|
|
/* Piledriver is models 0x02 & 0x10 of family 0x15 (so far). */
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BULLDOZER &&
|
|
((CPUID_EFFECTIVE_MODEL(eax) >= CPUID_MODEL_PILEDRIVER_10 &&
|
|
CPUID_EFFECTIVE_MODEL(eax) <= CPUID_MODEL_PILEDRIVER_1F) ||
|
|
CPUID_EFFECTIVE_MODEL(eax) == CPUID_MODEL_PILEDRIVER_02);
|
|
}
|
|
|
|
|
|
|
|
|
|
static INLINE Bool
|
|
CPUID_MODEL_IS_KYOTO(uint32 eax)
|
|
{
|
|
/* Kyoto is models 0x00 of family 0x16 (so far). */
|
|
return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_KYOTO &&
|
|
CPUID_EFFECTIVE_MODEL(eax) == CPUID_MODEL_KYOTO_00;
|
|
}
|
|
|
|
#define CPUID_TYPE_PRIMARY 0
|
|
#define CPUID_TYPE_OVERDRIVE 1
|
|
#define CPUID_TYPE_SECONDARY 2
|
|
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_TYPE_NULL 0
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_TYPE_DATA 1
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_TYPE_INST 2
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_TYPE_UNIF 3
|
|
#define CPUID_LEAF4_CACHE_TYPE_NULL 0
|
|
#define CPUID_LEAF4_CACHE_TYPE_DATA 1
|
|
#define CPUID_LEAF4_CACHE_TYPE_INST 2
|
|
#define CPUID_LEAF4_CACHE_TYPE_UNIF 3
|
|
#define CPUID_LEAF4_CACHE_INDEXING_DIRECT 0
|
|
#define CPUID_LEAF4_CACHE_INDEXING_COMPLEX 1
|
|
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_SELF_INIT 0x00000100
|
|
#define CPUID_INTEL_ID4EAX_LEAF4_CACHE_FULLY_ASSOC 0x00000200
|
|
#define CPUID_LEAF4_CACHE_SELF_INIT 0x00000100
|
|
#define CPUID_LEAF4_CACHE_FULLY_ASSOC 0x00000200
|
|
|
|
#define CPUID_INTEL_IDBECX_LEVEL_TYPE_INVALID 0
|
|
#define CPUID_INTEL_IDBECX_LEVEL_TYPE_SMT 1
|
|
#define CPUID_INTEL_IDBECX_LEVEL_TYPE_CORE 2
|
|
#define CPUID_TOPOLOGY_LEVEL_TYPE_INVALID 0
|
|
#define CPUID_TOPOLOGY_LEVEL_TYPE_SMT 1
|
|
#define CPUID_TOPOLOGY_LEVEL_TYPE_CORE 2
|
|
|
|
|
|
/*
|
|
* For certain AMD processors, an lfence instruction is necessary at various
|
|
* places to ensure ordering.
|
|
*/
|
|
|
|
static INLINE Bool
|
|
CPUID_VendorRequiresFence(CpuidVendor vendor)
|
|
{
|
|
return vendor == CPUID_VENDOR_AMD;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_VersionRequiresFence(uint32 version)
|
|
{
|
|
return CPUID_EFFECTIVE_FAMILY(version) == CPUID_FAMILY_K8 &&
|
|
CPUID_EFFECTIVE_MODEL(version) < 0x40;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_ID0RequiresFence(CPUIDRegs *id0)
|
|
{
|
|
if (id0->eax == 0) {
|
|
return FALSE;
|
|
}
|
|
return CPUID_IsVendorAMD(id0);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_ID1RequiresFence(CPUIDRegs *id1)
|
|
{
|
|
return CPUID_VersionRequiresFence(id1->eax);
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_RequiresFence(CpuidVendor vendor, // IN
|
|
uint32 version) // IN: %eax from CPUID with %eax=1.
|
|
{
|
|
return CPUID_VendorRequiresFence(vendor) &&
|
|
CPUID_VersionRequiresFence(version);
|
|
}
|
|
|
|
|
|
/*
|
|
* The following low-level functions compute the number of
|
|
* cores per cpu. They should be used cautiously because
|
|
* they do not necessarily work on all types of CPUs.
|
|
* High-level functions that are correct for all CPUs are
|
|
* available elsewhere: see lib/cpuidInfo/cpuidInfo.c.
|
|
*/
|
|
|
|
static INLINE uint32
|
|
CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. */
|
|
{
|
|
// Note: This is not guaranteed to work on older Intel CPUs.
|
|
return 1 + CPUID_GET(4, EAX, LEAF4_CORE_COUNT, v);
|
|
}
|
|
|
|
|
|
static INLINE uint32
|
|
CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */
|
|
{
|
|
// Note: This is not guaranteed to work on older AMD CPUs.
|
|
return 1 + CPUID_GET(0x80000008, ECX, LEAF88_CORE_COUNT, v);
|
|
}
|
|
|
|
|
|
/*
|
|
* Hypervisor CPUID space is 0x400000XX.
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_IsHypervisorLevel(uint32 level)
|
|
{
|
|
return (level & 0xffffff00) == 0x40000000;
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* CPUID_LevelUsesEcx --
|
|
*
|
|
* Returns TRUE for leaves that support input ECX != 0 (subleaves).
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
static INLINE Bool
|
|
CPUID_LevelUsesEcx(uint32 level) {
|
|
return level == 4 || level == 7 || level == 0xb || level == 0xd ||
|
|
level == 0x8000001d;
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* CPUID_IsValid*Subleaf --
|
|
*
|
|
* Functions to determine the last subleaf for the level specified
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
|
|
static INLINE Bool
|
|
CPUID_IsValidBSubleaf(uint32 ebx) // IN: %ebx = cpuid.b.sublevel.ebx
|
|
{
|
|
return ebx != 0;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_IsValid4Subleaf(uint32 eax) // IN: %eax = cpuid.4.sublevel.eax
|
|
{
|
|
return eax != 0;
|
|
}
|
|
|
|
static INLINE Bool
|
|
CPUID_IsValid7Subleaf(uint32 eax, uint32 subleaf) // IN: %eax = cpuid.7.0.eax
|
|
{
|
|
/*
|
|
* cpuid.7.0.eax is the max ecx (subleaf) index
|
|
*/
|
|
return subleaf <= eax;
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* CPUID_IsValidDSubleaf --
|
|
*
|
|
* It is the caller's repsonsibility to determine if the processor
|
|
* supports XSAVE and therefore has D sub-leaves.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_IsValidDSubleaf(uint32 subleaf) // IN: subleaf to check
|
|
{
|
|
return subleaf <= 63;
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------
|
|
*
|
|
* CPUID_SupportsMsrPlatformInfo --
|
|
*
|
|
* Uses vendor and cpuid.1.0.eax to determine if the processor
|
|
* supports MSR_PLATFORM_INFO.
|
|
*
|
|
*----------------------------------------------------------------------
|
|
*/
|
|
static INLINE Bool
|
|
CPUID_SupportsMsrPlatformInfo(CpuidVendor vendor, uint32 version)
|
|
{
|
|
return vendor == CPUID_VENDOR_INTEL &&
|
|
(CPUID_UARCH_IS_NEHALEM(version) ||
|
|
CPUID_UARCH_IS_HASWELL(version) ||
|
|
CPUID_UARCH_IS_SANDYBRIDGE(version));
|
|
}
|
|
|
|
#endif
|