/* 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 /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_subleaf(leaf, subleaf, regs) { \
static_assert(sizeof (*(regs)) == 16 ); \
__cpuid_read(leaf, subleaf, (u32 *)(regs)); \
}
#define cpuid_leaf(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 0 xb:
case 0 xd:
case 0 xf:
case 0 x10:
case 0 x12:
case 0 x14:
case 0 x17:
case 0 x18:
case 0 x1d:
case 0 x1e:
case 0 x1f:
case 0 x24:
case 0 x8000001d:
return true ;
}
return false ;
}
#define for_each_possible_cpuid_base_hypervisor(function) \
for (function = 0 x40000000; function < 0 x40010000; function += 0 x100)
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[tyle='color: green'>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 ( 0 x2 ) parsing :
*/
/**
* cpuid_leaf_0x2 ( ) - Return sanitized CPUID ( 0 x2 ) register output
* @ regs : Output parameter
*
* Query CPUID ( 0 x2 ) 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_leaf(0 x2, 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 ] != 0 x01) {
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 ( 0 x2 ) descriptors
* @ _ regs : CPUID ( 0 x2 ) register output , as returned by cpuid_leaf_0x2 ( )
* @ _ ptr : u8 pointer , for macro internal use only
* @ _ desc : Pointer to the parsed CPUID ( 0 x2 ) descriptor at each iteration
*
* Loop over the 1 - byte descriptors in the passed CPUID ( 0 x2 ) 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 ( & regs ) ;
* 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 ( 0 x80000006 ) parsing :
*/
static inline bool cpuid_amd_hygon_has_l3_cache(void )
{
return cpuid_edx(0 x80000006);
}
#endif /* _ASM_X86_CPUID_API_H */
Messung V0.5 in Prozent C=95 H=84 G=89
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland