540 lines
15 KiB
C
540 lines
15 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_X86_CPUID_API_H
|
|
#define _ASM_X86_CPUID_API_H
|
|
|
|
#include <asm/cpuid/types.h>
|
|
|
|
#include <linux/build_bug.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <asm/processor.h>
|
|
#include <asm/string.h>
|
|
|
|
/*
|
|
* Raw CPUID accessors:
|
|
*/
|
|
|
|
#ifdef CONFIG_X86_32
|
|
bool cpuid_feature(void);
|
|
#else
|
|
static inline bool cpuid_feature(void)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static inline void native_cpuid(u32 *eax, u32 *ebx,
|
|
u32 *ecx, u32 *edx)
|
|
{
|
|
/* ecx is often an input as well as an output. */
|
|
asm volatile("cpuid"
|
|
: "=a" (*eax),
|
|
"=b" (*ebx),
|
|
"=c" (*ecx),
|
|
"=d" (*edx)
|
|
: "0" (*eax), "2" (*ecx)
|
|
: "memory");
|
|
}
|
|
|
|
#define NATIVE_CPUID_REG(reg) \
|
|
static inline u32 native_cpuid_##reg(u32 op) \
|
|
{ \
|
|
u32 eax = op, ebx, ecx = 0, edx; \
|
|
\
|
|
native_cpuid(&eax, &ebx, &ecx, &edx); \
|
|
\
|
|
return reg; \
|
|
}
|
|
|
|
/*
|
|
* Native CPUID functions returning a single datum:
|
|
*/
|
|
NATIVE_CPUID_REG(eax)
|
|
NATIVE_CPUID_REG(ebx)
|
|
NATIVE_CPUID_REG(ecx)
|
|
NATIVE_CPUID_REG(edx)
|
|
|
|
#ifdef CONFIG_PARAVIRT_XXL
|
|
# include <asm/paravirt.h>
|
|
#else
|
|
# define __cpuid native_cpuid
|
|
#endif
|
|
|
|
/*
|
|
* Generic CPUID function
|
|
*
|
|
* Clear ECX since some CPUs (Cyrix MII) do not set or clear ECX
|
|
* resulting in stale register contents being returned.
|
|
*/
|
|
static inline void cpuid(u32 op,
|
|
u32 *eax, u32 *ebx,
|
|
u32 *ecx, u32 *edx)
|
|
{
|
|
*eax = op;
|
|
*ecx = 0;
|
|
__cpuid(eax, ebx, ecx, edx);
|
|
}
|
|
|
|
/* Some CPUID calls want 'count' to be placed in ECX */
|
|
static inline void cpuid_count(u32 op, int count,
|
|
u32 *eax, u32 *ebx,
|
|
u32 *ecx, u32 *edx)
|
|
{
|
|
*eax = op;
|
|
*ecx = count;
|
|
__cpuid(eax, ebx, ecx, edx);
|
|
}
|
|
|
|
/*
|
|
* CPUID functions returning a single datum:
|
|
*/
|
|
|
|
static inline u32 cpuid_eax(u32 op)
|
|
{
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
cpuid(op, &eax, &ebx, &ecx, &edx);
|
|
|
|
return eax;
|
|
}
|
|
|
|
static inline u32 cpuid_ebx(u32 op)
|
|
{
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
cpuid(op, &eax, &ebx, &ecx, &edx);
|
|
|
|
return ebx;
|
|
}
|
|
|
|
static inline u32 cpuid_ecx(u32 op)
|
|
{
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
cpuid(op, &eax, &ebx, &ecx, &edx);
|
|
|
|
return ecx;
|
|
}
|
|
|
|
static inline u32 cpuid_edx(u32 op)
|
|
{
|
|
u32 eax, ebx, ecx, edx;
|
|
|
|
cpuid(op, &eax, &ebx, &ecx, &edx);
|
|
|
|
return edx;
|
|
}
|
|
|
|
static inline void __cpuid_read(u32 leaf, u32 subleaf, u32 *regs)
|
|
{
|
|
regs[CPUID_EAX] = leaf;
|
|
regs[CPUID_ECX] = subleaf;
|
|
__cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX);
|
|
}
|
|
|
|
#define cpuid_read_subleaf(leaf, subleaf, regs) { \
|
|
static_assert(sizeof(*(regs)) == 16); \
|
|
__cpuid_read(leaf, subleaf, (u32 *)(regs)); \
|
|
}
|
|
|
|
#define cpuid_read(leaf, regs) { \
|
|
static_assert(sizeof(*(regs)) == 16); \
|
|
__cpuid_read(leaf, 0, (u32 *)(regs)); \
|
|
}
|
|
|
|
static inline void __cpuid_read_reg(u32 leaf, u32 subleaf,
|
|
enum cpuid_regs_idx regidx, u32 *reg)
|
|
{
|
|
u32 regs[4];
|
|
|
|
__cpuid_read(leaf, subleaf, regs);
|
|
*reg = regs[regidx];
|
|
}
|
|
|
|
#define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) { \
|
|
static_assert(sizeof(*(reg)) == 4); \
|
|
__cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg)); \
|
|
}
|
|
|
|
#define cpuid_leaf_reg(leaf, regidx, reg) { \
|
|
static_assert(sizeof(*(reg)) == 4); \
|
|
__cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg)); \
|
|
}
|
|
|
|
/*
|
|
* Hypervisor-related APIs:
|
|
*/
|
|
|
|
static __always_inline bool cpuid_function_is_indexed(u32 function)
|
|
{
|
|
switch (function) {
|
|
case 4:
|
|
case 7:
|
|
case 0xb:
|
|
case 0xd:
|
|
case 0xf:
|
|
case 0x10:
|
|
case 0x12:
|
|
case 0x14:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
case 0x24:
|
|
case 0x8000001d:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#define for_each_possible_cpuid_base_hypervisor(function) \
|
|
for (function = 0x40000000; function < 0x40010000; function += 0x100)
|
|
|
|
static inline u32 cpuid_base_hypervisor(const char *sig, u32 leaves)
|
|
{
|
|
u32 base, eax, signature[3];
|
|
|
|
for_each_possible_cpuid_base_hypervisor(base) {
|
|
cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
|
|
|
|
/*
|
|
* This must not compile to "call memcmp" because it's called
|
|
* from PVH early boot code before instrumentation is set up
|
|
* and memcmp() itself may be instrumented.
|
|
*/
|
|
if (!__builtin_memcmp(sig, signature, 12) &&
|
|
(leaves == 0 || ((eax - base) >= leaves)))
|
|
return base;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CPUID(0x2) parsing:
|
|
*/
|
|
|
|
/**
|
|
* cpuid_leaf_0x2() - Return sanitized CPUID(0x2) register output
|
|
* @regs: Output parameter
|
|
*
|
|
* Query CPUID(0x2) and store its output in @regs. Force set any
|
|
* invalid 1-byte descriptor returned by the hardware to zero (the NULL
|
|
* cache/TLB descriptor) before returning it to the caller.
|
|
*
|
|
* Use for_each_cpuid_0x2_desc() to iterate over the register output in
|
|
* parsed form.
|
|
*/
|
|
static inline void cpuid_leaf_0x2(union leaf_0x2_regs *regs)
|
|
{
|
|
cpuid_read(0x2, regs);
|
|
|
|
/*
|
|
* All Intel CPUs must report an iteration count of 1. In case
|
|
* of bogus hardware, treat all returned descriptors as NULL.
|
|
*/
|
|
if (regs->desc[0] != 0x01) {
|
|
for (int i = 0; i < 4; i++)
|
|
regs->regv[i] = 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The most significant bit (MSB) of each register must be clear.
|
|
* If a register is invalid, replace its descriptors with NULL.
|
|
*/
|
|
for (int i = 0; i < 4; i++) {
|
|
if (regs->reg[i].invalid)
|
|
regs->regv[i] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* for_each_cpuid_0x2_desc() - Iterator for parsed CPUID(0x2) descriptors
|
|
* @_regs: CPUID(0x2) register output, as returned by cpuid_leaf_0x2()
|
|
* @_ptr: u8 pointer, for macro internal use only
|
|
* @_desc: Pointer to the parsed CPUID(0x2) descriptor at each iteration
|
|
*
|
|
* Loop over the 1-byte descriptors in the passed CPUID(0x2) output registers
|
|
* @_regs. Provide the parsed information for each descriptor through @_desc.
|
|
*
|
|
* To handle cache-specific descriptors, switch on @_desc->c_type. For TLB
|
|
* descriptors, switch on @_desc->t_type.
|
|
*
|
|
* Example usage for cache descriptors::
|
|
*
|
|
* const struct leaf_0x2_table *desc;
|
|
* union leaf_0x2_regs regs;
|
|
* u8 *ptr;
|
|
*
|
|
* cpuid_leaf_0x2(®s);
|
|
* for_each_cpuid_0x2_desc(regs, ptr, desc) {
|
|
* switch (desc->c_type) {
|
|
* ...
|
|
* }
|
|
* }
|
|
*/
|
|
#define for_each_cpuid_0x2_desc(_regs, _ptr, _desc) \
|
|
for (_ptr = &(_regs).desc[1]; \
|
|
_ptr < &(_regs).desc[16] && (_desc = &cpuid_0x2_table[*_ptr]); \
|
|
_ptr++)
|
|
|
|
/*
|
|
* CPUID(0x80000006) parsing:
|
|
*/
|
|
|
|
static inline bool cpuid_amd_hygon_has_l3_cache(void)
|
|
{
|
|
return cpuid_edx(0x80000006);
|
|
}
|
|
|
|
/*
|
|
* 'struct cpuid_leaves' accessors (without sanity checks):
|
|
*
|
|
* For internal use by the CPUID parser.
|
|
*/
|
|
|
|
/* Return constified pointers for all call-site APIs */
|
|
#define __const_ptr(_ptr) \
|
|
((const __typeof__(*(_ptr)) *)(_ptr))
|
|
|
|
#define __cpuid_leaves_subleaf(_leaves, _leaf, _subleaf) \
|
|
__const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## _subleaf)[0])
|
|
|
|
#define __cpuid_leaves_subleaf_n(_leaves, _leaf, _index) \
|
|
__const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## n)[_index])
|
|
|
|
#define __cpuid_leaves_subleaf_info(_leaves, _leaf, _subleaf) \
|
|
__const_ptr(&((_leaves)->leaf_ ## _leaf ## _ ## _subleaf ## _ ## info))
|
|
|
|
/*
|
|
* 'struct cpuid_table' accessors (with sanity checks):
|
|
*
|
|
* For internal use by the CPUID parser.
|
|
*/
|
|
|
|
#define __cpuid_table_nr_filled_subleaves(_table, _leaf, _subleaf) \
|
|
__cpuid_leaves_subleaf_info(&((_table)->leaves), _leaf, _subleaf)->nr_entries
|
|
|
|
#define __cpuid_table_subleaf_range_size(_table, _leaf) \
|
|
ARRAY_SIZE((_table)->leaves.leaf_ ## _leaf ## _n)
|
|
|
|
#define __cpuid_table_invalid_subleaf(_table, _leaf, _subleaf) \
|
|
(((_subleaf) < (__cpuid_leaf_first_subleaf(_leaf))) || \
|
|
((_subleaf) > (__cpuid_leaf_first_subleaf(_leaf) + \
|
|
__cpuid_table_subleaf_range_size(_table, _leaf) - 1)))
|
|
|
|
/* Return NULL if the parser did not fill that leaf. Check cpuid_subleaf(). */
|
|
#define __cpuid_table_subleaf(_table, _leaf, _subleaf) \
|
|
({ \
|
|
unsigned int ____f = __cpuid_table_nr_filled_subleaves(_table, _leaf, _subleaf); \
|
|
\
|
|
(____f != 1) ? NULL : __cpuid_leaves_subleaf(&((_table)->leaves), _leaf, _subleaf); \
|
|
})
|
|
|
|
/*
|
|
* Return NULL if the CPUID parser did not fill this leaf, or if the given
|
|
* dynamic subleaf value is out of range. Check cpuid_subleaf_n().
|
|
*/
|
|
#define __cpuid_table_subleaf_n(_table, _leaf, _subleaf) \
|
|
({ \
|
|
unsigned int ____i = (_subleaf) - __cpuid_leaf_first_subleaf(_leaf); \
|
|
unsigned int ____f = __cpuid_table_nr_filled_subleaves(_table, _leaf, n); \
|
|
\
|
|
/* CPUID parser might not have filled the entire subleaf range */ \
|
|
((____i >= ____f) || __cpuid_table_invalid_subleaf(_table, _leaf, _subleaf)) ? \
|
|
NULL : __cpuid_leaves_subleaf_n(&((_table)->leaves), _leaf, ____i); \
|
|
})
|
|
|
|
/*
|
|
* Compile-time checks for leaves with a subleaf range:
|
|
*/
|
|
|
|
#define __cpuid_assert_subleaf_range(_cpuinfo, _leaf) \
|
|
static_assert(__cpuid_table_subleaf_range_size(&(_cpuinfo)->cpuid, _leaf) > 1)
|
|
|
|
#define __cpuid_assert_subleaf_within_range(_cpuinfo, _leaf, _subleaf) \
|
|
BUILD_BUG_ON(__builtin_constant_p(_subleaf) && \
|
|
__cpuid_table_invalid_subleaf(&(_cpuinfo)->cpuid, _leaf, _subleaf))
|
|
|
|
/*
|
|
* CPUID Parser Call-site APIs
|
|
*
|
|
* Call sites should use below APIs instead of invoking direct CPUID queries.
|
|
*
|
|
* Benefits include:
|
|
*
|
|
* - Return CPUID output as typed C structures that are auto-generated from a
|
|
* centralized database (see <asm/cpuid/leaf_types.h). Such data types have a
|
|
* full C99 bitfield layout per CPUID leaf/subleaf combination. Call sites
|
|
* can thus avoid doing ugly and cryptic bitwise operations on raw CPUID data.
|
|
*
|
|
* - Return cached, per-CPU, CPUID output. Below APIs do not invoke any CPUID
|
|
* queries, thus avoiding their side effects like serialization and VM exits.
|
|
* Call-site-specific hard coded constants and macros for caching CPUID query
|
|
* outputs can also be avoided.
|
|
*
|
|
* - Return sanitized CPUID data. Below APIs return NULL if the given CPUID
|
|
* leaf/subleaf input is not supported by hardware, or if the hardware CPUID
|
|
* output was deemed invalid by the CPUID parser. This centralizes all CPUID
|
|
* data sanitization in one place (the kernel's CPUID parser.)
|
|
*
|
|
* - A centralized global view of system CPUID data. Below APIs will reflect
|
|
* any kernel-enforced feature masking or overrides, unlike ad hoc parsing of
|
|
* raw CPUID output by drivers and individual call sites.
|
|
*/
|
|
|
|
/*
|
|
* Call-site APIs for CPUID leaves with a single subleaf:
|
|
*/
|
|
|
|
/**
|
|
* cpuid_subleaf() - Access parsed CPUID
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x7, 0xf
|
|
* @_subleaf: CPUID subleaf, in compile-time decimal format; e.g. 0, 1, 3
|
|
*
|
|
* Returns a pointer to parsed CPUID output, from the CPUID table inside
|
|
* @_cpuinfo, as a <cpuid/leaf_types.h> data type: 'struct leaf_0xM_N', where
|
|
* 0xM is the token provided at @_leaf, and N is the token provided at
|
|
* @_subleaf; e.g. struct leaf_0x7_0.
|
|
*
|
|
* Returns NULL if the requested CPUID @_leaf/@_subleaf query output is not
|
|
* present at the parsed CPUID table inside @_cpuinfo. This can happen if:
|
|
*
|
|
* - The CPUID table inside @_cpuinfo has not yet been populated.
|
|
* - The CPUID table inside @_cpuinfo was populated, but the CPU does not
|
|
* implement the requested CPUID @_leaf/@_subleaf combination.
|
|
* - The CPUID table inside @_cpuinfo was populated, but the kernel's CPUID
|
|
* parser has predetermined that the requested CPUID @_leaf/@_subleaf
|
|
* hardware output is invalid or unsupported.
|
|
*
|
|
* Example usage::
|
|
*
|
|
* const struct leaf_0x7_0 *l7_0 = cpuid_subleaf(c, 0x7, 0);
|
|
* if (!l7_0) {
|
|
* // Handle error
|
|
* }
|
|
*
|
|
* const struct leaf_0x7_1 *l7_1 = cpuid_subleaf(c, 0x7, 1);
|
|
* if (!l7_1) {
|
|
* // Handle error
|
|
* }
|
|
*/
|
|
#define cpuid_subleaf(_cpuinfo, _leaf, _subleaf) \
|
|
__cpuid_table_subleaf(&(_cpuinfo)->cpuid, _leaf, _subleaf) \
|
|
|
|
/**
|
|
* cpuid_leaf() - Access parsed CPUID data
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x0, 0x2, 0x80000000
|
|
*
|
|
* Similar to cpuid_subleaf(), but with a CPUID subleaf = 0.
|
|
*
|
|
* Example usage::
|
|
*
|
|
* const struct leaf_0x0_0 *l0 = cpuid_leaf(c, 0x0);
|
|
* if (!l0) {
|
|
* // Handle error
|
|
* }
|
|
*
|
|
* const struct leaf_0x80000000_0 *el0 = cpuid_leaf(c, 0x80000000);
|
|
* if (!el0) {
|
|
* // Handle error
|
|
* }
|
|
*/
|
|
#define cpuid_leaf(_cpuinfo, _leaf) \
|
|
cpuid_subleaf(_cpuinfo, _leaf, 0)
|
|
|
|
/**
|
|
* cpuid_leaf_raw() - Access parsed CPUID data in raw format
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format
|
|
*
|
|
* Similar to cpuid_leaf(), but returns a raw 'struct cpuid_regs' pointer to
|
|
* the parsed CPUID data instead of a "typed" <asm/cpuid/leaf_types.h> pointer.
|
|
*/
|
|
#define cpuid_leaf_raw(_cpuinfo, _leaf) \
|
|
((const struct cpuid_regs *)(cpuid_leaf(_cpuinfo, _leaf)))
|
|
|
|
/*
|
|
* Call-site APIs for CPUID leaves with a subleaf range:
|
|
*/
|
|
|
|
/**
|
|
* cpuid_subleaf_n() - Access parsed CPUID data for leaf with a subleaf range
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d
|
|
* @_subleaf: Subleaf number, which can be passed dynamically. It must be smaller
|
|
* than cpuid_subleaf_count(@_cpuinfo, @_leaf).
|
|
*
|
|
* Build-time errors will be emitted in the following cases:
|
|
*
|
|
* - @_leaf has no subleaf range. Leaves with a subleaf range have an '_n' type
|
|
* suffix and are listed at <asm/cpuid/types.h> using the CPUID_LEAF_N() macro.
|
|
*
|
|
* - @_subleaf is known at compile-time but is out of range.
|
|
*
|
|
* Example usage::
|
|
*
|
|
* const struct leaf_0x4_n *l4;
|
|
*
|
|
* for (int i = 0; i < cpuid_subleaf_count(c, 0x4); i++) {
|
|
* l4 = cpuid_subleaf_n(c, 0x4, i);
|
|
* if (!l4) {
|
|
* // Handle error
|
|
* }
|
|
* ...
|
|
* }
|
|
*
|
|
* Beside the standard error situations detailed at cpuid_subleaf(), this
|
|
* macro will also return NULL if @_subleaf is out of the leaf's subleaf range.
|
|
*/
|
|
#define cpuid_subleaf_n(_cpuinfo, _leaf, _subleaf) \
|
|
({ \
|
|
__cpuid_assert_subleaf_range(_cpuinfo, _leaf); \
|
|
__cpuid_assert_subleaf_within_range(_cpuinfo, _leaf, _subleaf); \
|
|
__cpuid_table_subleaf_n(&(_cpuinfo)->cpuid, _leaf, _subleaf); \
|
|
})
|
|
|
|
/**
|
|
* cpuid_subleaf_n_raw() - Access parsed CPUID data for leaf with subleaf range
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d
|
|
* @_subleaf: Subleaf number, which can be passed dynamically. It must be smaller
|
|
* than cpuid_subleaf_count(@_cpuinfo, @_leaf).
|
|
*
|
|
* Similar to cpuid_subleaf_n(), but returns a raw 'struct cpuid_regs' pointer to
|
|
* the parsed CPUID data instead of a "typed" <asm/cpuid/leaf_types.h> pointer.
|
|
*/
|
|
#define cpuid_subleaf_n_raw(_cpuinfo, _leaf, _subleaf) \
|
|
((const struct cpuid_regs *)cpuid_subleaf_n(_cpuinfo, _leaf, _subleaf))
|
|
|
|
/**
|
|
* cpuid_subleaf_count() - Number of filled subleaves for @_leaf
|
|
* @_cpuinfo: CPU capability structure reference ('struct cpuinfo_x86')
|
|
* @_leaf: CPUID leaf, in compile-time 0xN format; e.g. 0x4, 0x8000001d
|
|
*
|
|
* Return the number of subleaves filled by the CPUID parser for @_leaf.
|
|
*
|
|
* @_leaf must have subleaf range. Leaves with a subleaf range have an '_n' type
|
|
* suffix and are listed at <asm/cpuid/types.h> using the CPUID_LEAF_N() macro.
|
|
*/
|
|
#define cpuid_subleaf_count(_cpuinfo, _leaf) \
|
|
({ \
|
|
__cpuid_assert_subleaf_range(_cpuinfo, _leaf); \
|
|
__cpuid_table_nr_filled_subleaves(&(_cpuinfo)->cpuid, _leaf, n); \
|
|
})
|
|
|
|
/*
|
|
* CPUID parser exported APIs:
|
|
*/
|
|
|
|
void cpuid_scan_cpu(struct cpuinfo_x86 *c);
|
|
void cpuid_refresh_leaf(struct cpuinfo_x86 *c, u32 leaf);
|
|
void cpuid_refresh_range(struct cpuinfo_x86 *c, u32 start, u32 end);
|
|
|
|
#endif /* _ASM_X86_CPUID_API_H */
|