blob: 3d1e3b7a9217e999cddd5e374454430ba348f93a [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <assert.h>
#include <zircon/compiler.h>
#include <stdint.h>
#include <arch/x86.h>
__BEGIN_CDECLS
#define MAX_SUPPORTED_CPUID (0x17)
#define MAX_SUPPORTED_CPUID_EXT (0x8000001e)
struct cpuid_leaf {
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
};
enum x86_cpuid_leaf_num {
X86_CPUID_BASE = 0,
X86_CPUID_MODEL_FEATURES = 0x1,
X86_CPUID_CACHE_V1 = 0x2,
X86_CPUID_CACHE_V2 = 0x4,
X86_CPUID_THERMAL_AND_POWER = 0x6,
X86_CPUID_EXTENDED_FEATURE_FLAGS = 0x7,
X86_CPUID_PERFORMANCE_MONITORING = 0xa,
X86_CPUID_TOPOLOGY = 0xb,
X86_CPUID_XSAVE = 0xd,
X86_CPUID_PT = 0x14,
X86_CPUID_TSC = 0x15,
X86_CPUID_EXT_BASE = 0x80000000,
X86_CPUID_ADDR_WIDTH = 0x80000008,
X86_CPUID_AMD_TOPOLOGY = 0x8000001e,
};
struct x86_cpuid_bit {
enum x86_cpuid_leaf_num leaf_num;
uint8_t word;
uint8_t bit;
};
#define X86_CPUID_BIT(leaf, word, bit) \
(struct x86_cpuid_bit){(enum x86_cpuid_leaf_num)(leaf), (word), (bit)}
void x86_feature_init(void);
static inline const struct cpuid_leaf *x86_get_cpuid_leaf(enum x86_cpuid_leaf_num leaf)
{
extern struct cpuid_leaf _cpuid[MAX_SUPPORTED_CPUID + 1];
extern struct cpuid_leaf _cpuid_ext[MAX_SUPPORTED_CPUID_EXT - X86_CPUID_EXT_BASE + 1];
extern uint32_t max_cpuid;
extern uint32_t max_ext_cpuid;
if (leaf < X86_CPUID_EXT_BASE) {
if (leaf > max_cpuid)
return NULL;
return &_cpuid[leaf];
} else {
if (leaf > max_ext_cpuid)
return NULL;
return &_cpuid_ext[(uint32_t)leaf - (uint32_t)X86_CPUID_EXT_BASE];
}
}
/* Retrieve the specified subleaf. This function is not cached.
* Returns false if leaf num is invalid */
bool x86_get_cpuid_subleaf(
enum x86_cpuid_leaf_num, uint32_t, struct cpuid_leaf *);
static inline bool x86_feature_test(struct x86_cpuid_bit bit)
{
DEBUG_ASSERT (bit.word <= 3 && bit.bit <= 31);
if (bit.word > 3 || bit.bit > 31)
return false;
const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(bit.leaf_num);
if (!leaf)
return false;
switch (bit.word) {
case 0: return !!((1u << bit.bit) & leaf->a);
case 1: return !!((1u << bit.bit) & leaf->b);
case 2: return !!((1u << bit.bit) & leaf->c);
case 3: return !!((1u << bit.bit) & leaf->d);
default: return false;
}
}
void x86_feature_debug(void);
/* add feature bits to test here */
#define X86_FEATURE_SSE3 X86_CPUID_BIT(0x1, 2, 0)
#define X86_FEATURE_VMX X86_CPUID_BIT(0x1, 2, 5)
#define X86_FEATURE_SSSE3 X86_CPUID_BIT(0x1, 2, 9)
#define X86_FEATURE_PDCM X86_CPUID_BIT(0x1, 2, 15)
#define X86_FEATURE_SSE4_1 X86_CPUID_BIT(0x1, 2, 19)
#define X86_FEATURE_SSE4_2 X86_CPUID_BIT(0x1, 2, 20)
#define X86_FEATURE_X2APIC X86_CPUID_BIT(0x1, 2, 21)
#define X86_FEATURE_TSC_DEADLINE X86_CPUID_BIT(0x1, 2, 24)
#define X86_FEATURE_AESNI X86_CPUID_BIT(0x1, 2, 25)
#define X86_FEATURE_XSAVE X86_CPUID_BIT(0x1, 2, 26)
#define X86_FEATURE_AVX X86_CPUID_BIT(0x1, 2, 28)
#define X86_FEATURE_RDRAND X86_CPUID_BIT(0x1, 2, 30)
#define X86_FEATURE_HYPERVISOR X86_CPUID_BIT(0x1, 2, 31)
#define X86_FEATURE_FPU X86_CPUID_BIT(0x1, 3, 0)
#define X86_FEATURE_MMX X86_CPUID_BIT(0x1, 3, 23)
#define X86_FEATURE_FXSR X86_CPUID_BIT(0x1, 3, 24)
#define X86_FEATURE_SSE X86_CPUID_BIT(0x1, 3, 25)
#define X86_FEATURE_SSE2 X86_CPUID_BIT(0x1, 3, 26)
#define X86_FEATURE_TM X86_CPUID_BIT(0x1, 3, 29)
#define X86_FEATURE_HWP X86_CPUID_BIT(0x6, 0, 7)
#define X86_FEATURE_HWP_PREF X86_CPUID_BIT(0x6, 0, 10)
#define X86_FEATURE_HW_FEEDBACK X86_CPUID_BIT(0x6, 2, 0)
#define X86_FEATURE_PERF_BIAS X86_CPUID_BIT(0x6, 2, 3)
#define X86_FEATURE_FSGSBASE X86_CPUID_BIT(0x7, 1, 0)
#define X86_FEATURE_TSC_ADJUST X86_CPUID_BIT(0x7, 1, 1)
#define X86_FEATURE_AVX2 X86_CPUID_BIT(0x7, 1, 5)
#define X86_FEATURE_SMEP X86_CPUID_BIT(0x7, 1, 7)
#define X86_FEATURE_RDSEED X86_CPUID_BIT(0x7, 1, 18)
#define X86_FEATURE_SMAP X86_CPUID_BIT(0x7, 1, 20)
#define X86_FEATURE_PT X86_CPUID_BIT(0x7, 1, 25)
#define X86_FEATURE_PKU X86_CPUID_BIT(0x7, 2, 3)
#define X86_FEATURE_AMD_TOPO X86_CPUID_BIT(0x80000001, 2, 22)
#define X86_FEATURE_SYSCALL X86_CPUID_BIT(0x80000001, 3, 11)
#define X86_FEATURE_NX X86_CPUID_BIT(0x80000001, 3, 20)
#define X86_FEATURE_HUGE_PAGE X86_CPUID_BIT(0x80000001, 3, 26)
#define X86_FEATURE_RDTSCP X86_CPUID_BIT(0x80000001, 3, 27)
#define X86_FEATURE_INVAR_TSC X86_CPUID_BIT(0x80000007, 3, 8)
/* legacy accessors */
static inline uint8_t x86_linear_address_width(void)
{
const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH);
if (!leaf)
return 0;
/*
Extracting bit 15:8 from eax register
Bits 15-08: #Linear Address Bits
*/
return (leaf->a >> 8) & 0xff;
}
static inline uint8_t x86_physical_address_width(void)
{
const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH);
if (!leaf)
return 0;
/*
Extracting bit 7:0 from eax register
Bits 07-00: #Physical Address Bits
*/
return leaf->a & 0xff;
}
/* cpu vendors */
enum x86_vendor_list {
X86_VENDOR_UNKNOWN,
X86_VENDOR_INTEL,
X86_VENDOR_AMD
};
extern enum x86_vendor_list x86_vendor;
/* topology */
#define X86_TOPOLOGY_INVALID 0
#define X86_TOPOLOGY_SMT 1
#define X86_TOPOLOGY_CORE 2
struct x86_topology_level {
/* The number of bits to right shift to identify the next-higher topological
* level */
uint8_t right_shift;
/* The type of relationship this level describes (hyperthread/core/etc) */
uint8_t type;
};
/**
* @brief Fetch the topology information for the given level.
*
* This interface is uncached.
*
* @param level The level to retrieve info for. Should initially be 0 and
* incremented with each call.
* @param info The structure to populate with the discovered information
*
* @return true if the requested level existed (and there may be higher levels).
* @return false if the requested level does not exist (and no higher ones do).
*/
bool x86_topology_enumerate(uint8_t level, struct x86_topology_level *info);
struct x86_model_info {
uint8_t processor_type;
uint8_t family;
uint8_t model;
uint8_t stepping;
uint32_t display_family;
uint32_t display_model;
};
const struct x86_model_info * x86_get_model(void);
enum x86_microarch_list {
X86_MICROARCH_UNKNOWN,
X86_MICROARCH_INTEL_SANDY_BRIDGE,
X86_MICROARCH_INTEL_IVY_BRIDGE,
X86_MICROARCH_INTEL_BROADWELL,
X86_MICROARCH_INTEL_HASWELL,
X86_MICROARCH_INTEL_SKYLAKE,
X86_MICROARCH_INTEL_KABYLAKE,
X86_MICROARCH_AMD_BULLDOZER,
X86_MICROARCH_AMD_JAGUAR,
X86_MICROARCH_AMD_ZEN,
};
extern enum x86_microarch_list x86_microarch;
__END_CDECLS