2021-04-21 17:56:22 -07:00
/* SPDX-License-Identifier: GPL-2.0 */
# ifndef ARCH_X86_KVM_REVERSE_CPUID_H
# define ARCH_X86_KVM_REVERSE_CPUID_H
# include <uapi/asm/kvm.h>
# include <asm/cpufeature.h>
# include <asm/cpufeatures.h>
/*
* Hardware - defined CPUID leafs that are scattered in the kernel , but need to
* be directly used by KVM . Note , these word values conflict with the kernel ' s
* " bug " caps , but KVM doesn ' t use those .
*/
enum kvm_only_cpuid_leafs {
CPUID_12_EAX = NCAPINTS ,
NR_KVM_CPU_CAPS ,
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS ,
} ;
# define KVM_X86_FEATURE(w, f) ((w)*32 + (f))
/* Intel-defined SGX sub-features, CPUID level 0x12 (EAX). */
# define KVM_X86_FEATURE_SGX1 KVM_X86_FEATURE(CPUID_12_EAX, 0)
# define KVM_X86_FEATURE_SGX2 KVM_X86_FEATURE(CPUID_12_EAX, 1)
struct cpuid_reg {
u32 function ;
u32 index ;
int reg ;
} ;
static const struct cpuid_reg reverse_cpuid [ ] = {
[ CPUID_1_EDX ] = { 1 , 0 , CPUID_EDX } ,
[ CPUID_8000_0001_EDX ] = { 0x80000001 , 0 , CPUID_EDX } ,
[ CPUID_8086_0001_EDX ] = { 0x80860001 , 0 , CPUID_EDX } ,
[ CPUID_1_ECX ] = { 1 , 0 , CPUID_ECX } ,
[ CPUID_C000_0001_EDX ] = { 0xc0000001 , 0 , CPUID_EDX } ,
[ CPUID_8000_0001_ECX ] = { 0x80000001 , 0 , CPUID_ECX } ,
[ CPUID_7_0_EBX ] = { 7 , 0 , CPUID_EBX } ,
[ CPUID_D_1_EAX ] = { 0xd , 1 , CPUID_EAX } ,
[ CPUID_8000_0008_EBX ] = { 0x80000008 , 0 , CPUID_EBX } ,
[ CPUID_6_EAX ] = { 6 , 0 , CPUID_EAX } ,
[ CPUID_8000_000A_EDX ] = { 0x8000000a , 0 , CPUID_EDX } ,
[ CPUID_7_ECX ] = { 7 , 0 , CPUID_ECX } ,
[ CPUID_8000_0007_EBX ] = { 0x80000007 , 0 , CPUID_EBX } ,
[ CPUID_7_EDX ] = { 7 , 0 , CPUID_EDX } ,
[ CPUID_7_1_EAX ] = { 7 , 1 , CPUID_EAX } ,
[ CPUID_12_EAX ] = { 0x00000012 , 0 , CPUID_EAX } ,
2021-04-21 19:11:15 -07:00
[ CPUID_8000_001F_EAX ] = { 0x8000001f , 0 , CPUID_EAX } ,
2021-04-21 17:56:22 -07:00
} ;
/*
* Reverse CPUID and its derivatives can only be used for hardware - defined
* feature words , i . e . words whose bits directly correspond to a CPUID leaf .
* Retrieving a feature bit or masking guest CPUID from a Linux - defined word
* is nonsensical as the bit number / mask is an arbitrary software - defined value
* and can ' t be used by KVM to query / control guest capabilities . And obviously
* the leaf being queried must have an entry in the lookup table .
*/
static __always_inline void reverse_cpuid_check ( unsigned int x86_leaf )
{
BUILD_BUG_ON ( x86_leaf = = CPUID_LNX_1 ) ;
BUILD_BUG_ON ( x86_leaf = = CPUID_LNX_2 ) ;
BUILD_BUG_ON ( x86_leaf = = CPUID_LNX_3 ) ;
BUILD_BUG_ON ( x86_leaf = = CPUID_LNX_4 ) ;
BUILD_BUG_ON ( x86_leaf > = ARRAY_SIZE ( reverse_cpuid ) ) ;
BUILD_BUG_ON ( reverse_cpuid [ x86_leaf ] . function = = 0 ) ;
}
/*
* Translate feature bits that are scattered in the kernel ' s cpufeatures word
* into KVM feature words that align with hardware ' s definitions .
*/
static __always_inline u32 __feature_translate ( int x86_feature )
{
if ( x86_feature = = X86_FEATURE_SGX1 )
return KVM_X86_FEATURE_SGX1 ;
else if ( x86_feature = = X86_FEATURE_SGX2 )
return KVM_X86_FEATURE_SGX2 ;
return x86_feature ;
}
static __always_inline u32 __feature_leaf ( int x86_feature )
{
return __feature_translate ( x86_feature ) / 32 ;
}
/*
* Retrieve the bit mask from an X86_FEATURE_ * definition . Features contain
* the hardware defined bit number ( stored in bits 4 : 0 ) and a software defined
* " word " ( stored in bits 31 : 5 ) . The word is used to index into arrays of
* bit masks that hold the per - cpu feature capabilities , e . g . this_cpu_has ( ) .
*/
static __always_inline u32 __feature_bit ( int x86_feature )
{
x86_feature = __feature_translate ( x86_feature ) ;
reverse_cpuid_check ( x86_feature / 32 ) ;
return 1 < < ( x86_feature & 31 ) ;
}
# define feature_bit(name) __feature_bit(X86_FEATURE_##name)
static __always_inline struct cpuid_reg x86_feature_cpuid ( unsigned int x86_feature )
{
unsigned int x86_leaf = __feature_leaf ( x86_feature ) ;
reverse_cpuid_check ( x86_leaf ) ;
return reverse_cpuid [ x86_leaf ] ;
}
static __always_inline u32 * __cpuid_entry_get_reg ( struct kvm_cpuid_entry2 * entry ,
u32 reg )
{
switch ( reg ) {
case CPUID_EAX :
return & entry - > eax ;
case CPUID_EBX :
return & entry - > ebx ;
case CPUID_ECX :
return & entry - > ecx ;
case CPUID_EDX :
return & entry - > edx ;
default :
BUILD_BUG ( ) ;
return NULL ;
}
}
static __always_inline u32 * cpuid_entry_get_reg ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature )
{
const struct cpuid_reg cpuid = x86_feature_cpuid ( x86_feature ) ;
return __cpuid_entry_get_reg ( entry , cpuid . reg ) ;
}
static __always_inline u32 cpuid_entry_get ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature )
{
u32 * reg = cpuid_entry_get_reg ( entry , x86_feature ) ;
return * reg & __feature_bit ( x86_feature ) ;
}
static __always_inline bool cpuid_entry_has ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature )
{
return cpuid_entry_get ( entry , x86_feature ) ;
}
static __always_inline void cpuid_entry_clear ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature )
{
u32 * reg = cpuid_entry_get_reg ( entry , x86_feature ) ;
* reg & = ~ __feature_bit ( x86_feature ) ;
}
static __always_inline void cpuid_entry_set ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature )
{
u32 * reg = cpuid_entry_get_reg ( entry , x86_feature ) ;
* reg | = __feature_bit ( x86_feature ) ;
}
static __always_inline void cpuid_entry_change ( struct kvm_cpuid_entry2 * entry ,
unsigned int x86_feature ,
bool set )
{
u32 * reg = cpuid_entry_get_reg ( entry , x86_feature ) ;
/*
* Open coded instead of using cpuid_entry_ { clear , set } ( ) to coerce the
* compiler into using CMOV instead of Jcc when possible .
*/
if ( set )
* reg | = __feature_bit ( x86_feature ) ;
else
* reg & = ~ __feature_bit ( x86_feature ) ;
}
# endif /* ARCH_X86_KVM_REVERSE_CPUID_H */