cpufeature.h 7.9 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
H
H. Peter Anvin 已提交
2 3
#ifndef _ASM_X86_CPUFEATURE_H
#define _ASM_X86_CPUFEATURE_H
H
H. Peter Anvin 已提交
4

5
#include <asm/processor.h>
6 7 8

#if defined(__KERNEL__) && !defined(__ASSEMBLY__)

9
#include <asm/asm.h>
10 11
#include <linux/bitops.h>

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
enum cpuid_leafs
{
	CPUID_1_EDX		= 0,
	CPUID_8000_0001_EDX,
	CPUID_8086_0001_EDX,
	CPUID_LNX_1,
	CPUID_1_ECX,
	CPUID_C000_0001_EDX,
	CPUID_8000_0001_ECX,
	CPUID_LNX_2,
	CPUID_LNX_3,
	CPUID_7_0_EBX,
	CPUID_D_1_EAX,
	CPUID_F_0_EDX,
	CPUID_F_1_EDX,
	CPUID_8000_0008_EBX,
	CPUID_6_EAX,
	CPUID_8000_000A_EDX,
30
	CPUID_7_ECX,
31
	CPUID_8000_0007_EBX,
32
	CPUID_7_EDX,
33 34
};

35
#ifdef CONFIG_X86_FEATURE_NAMES
36 37
extern const char * const x86_cap_flags[NCAPINTS*32];
extern const char * const x86_power_flags[32];
38 39 40 41 42 43
#define X86_CAP_FMT "%s"
#define x86_cap_flag(flag) x86_cap_flags[flag]
#else
#define X86_CAP_FMT "%d:%d"
#define x86_cap_flag(flag) ((flag) >> 5), ((flag) & 31)
#endif
44

45 46 47 48 49 50
/*
 * In order to save room, we index into this array by doing
 * X86_BUG_<name> - NCAPINTS*32.
 */
extern const char * const x86_bug_flags[NBUGINTS*32];

51 52 53
#define test_cpu_cap(c, bit)						\
	 test_bit(bit, (unsigned long *)((c)->x86_capability))

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
/*
 * There are 32 bits/features in each mask word.  The high bits
 * (selected with (bit>>5) give us the word number and the low 5
 * bits give us the bit/feature number inside the word.
 * (1UL<<((bit)&31) gives us a mask for the feature_bit so we can
 * see if it is set in the mask word.
 */
#define CHECK_BIT_IN_MASK_WORD(maskname, word, bit)	\
	(((bit)>>5)==(word) && (1UL<<((bit)&31) & maskname##word ))

#define REQUIRED_MASK_BIT_SET(feature_bit)		\
	 ( CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  0, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  1, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  2, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  3, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  4, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  5, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  6, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  7, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  8, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK,  9, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 10, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 11, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 12, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 13, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 14, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 15, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 16, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 17, feature_bit) ||	\
83
	   CHECK_BIT_IN_MASK_WORD(REQUIRED_MASK, 18, feature_bit) ||	\
84
	   REQUIRED_MASK_CHECK					  ||	\
85
	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
86

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
#define DISABLED_MASK_BIT_SET(feature_bit)				\
	 ( CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  0, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  1, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  2, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  3, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  4, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  5, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  6, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  7, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  8, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK,  9, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 10, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 11, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 12, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 13, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 14, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 15, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 16, feature_bit) ||	\
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 17, feature_bit) ||	\
106
	   CHECK_BIT_IN_MASK_WORD(DISABLED_MASK, 18, feature_bit) ||	\
107
	   DISABLED_MASK_CHECK					  ||	\
108
	   BUILD_BUG_ON_ZERO(NCAPINTS != 19))
D
Dave Hansen 已提交
109

110 111
#define cpu_has(c, bit)							\
	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :	\
112 113
	 test_cpu_cap(c, bit))

114 115 116 117
#define this_cpu_has(bit)						\
	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : 	\
	 x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability))

D
Dave Hansen 已提交
118 119 120 121 122 123 124 125 126
/*
 * This macro is for detection of features which need kernel
 * infrastructure to be used.  It may *not* directly test the CPU
 * itself.  Use the cpu_has() family if you want true runtime
 * testing of CPU features, like in hypervisor code where you are
 * supporting a possible guest feature where host support for it
 * is not relevant.
 */
#define cpu_feature_enabled(bit)	\
127
	(__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit))
D
Dave Hansen 已提交
128

H
H. Peter Anvin 已提交
129 130
#define boot_cpu_has(bit)	cpu_has(&boot_cpu_data, bit)

131
#define set_cpu_cap(c, bit)	set_bit(bit, (unsigned long *)((c)->x86_capability))
132 133 134 135

extern void setup_clear_cpu_cap(unsigned int bit);
extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);

136 137
#define setup_force_cpu_cap(bit) do { \
	set_cpu_cap(&boot_cpu_data, bit);	\
138
	set_bit(bit, (unsigned long *)cpu_caps_set);	\
139
} while (0)
140

141 142
#define setup_force_cpu_bug(bit) setup_force_cpu_cap(bit)

143 144 145 146 147 148 149 150 151 152 153 154 155 156
#if defined(__clang__) && !defined(CC_HAVE_ASM_GOTO)

/*
 * Workaround for the sake of BPF compilation which utilizes kernel
 * headers, but clang does not support ASM GOTO and fails the build.
 */
#ifndef __BPF_TRACING__
#warning "Compiler lacks ASM_GOTO support. Add -D __BPF_TRACING__ to your compiler arguments"
#endif

#define static_cpu_has(bit)            boot_cpu_has(bit)

#else

157 158
/*
 * Static testing of CPU features.  Used the same as boot_cpu_has().
159 160
 * These will statically patch the target code for additional
 * performance.
161
 */
162
static __always_inline __pure bool _static_cpu_has(u16 bit)
163
{
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
	asm_volatile_goto("1: jmp 6f\n"
		 "2:\n"
		 ".skip -(((5f-4f) - (2b-1b)) > 0) * "
			 "((5f-4f) - (2b-1b)),0x90\n"
		 "3:\n"
		 ".section .altinstructions,\"a\"\n"
		 " .long 1b - .\n"		/* src offset */
		 " .long 4f - .\n"		/* repl offset */
		 " .word %P[always]\n"		/* always replace */
		 " .byte 3b - 1b\n"		/* src len */
		 " .byte 5f - 4f\n"		/* repl len */
		 " .byte 3b - 2b\n"		/* pad len */
		 ".previous\n"
		 ".section .altinstr_replacement,\"ax\"\n"
		 "4: jmp %l[t_no]\n"
		 "5:\n"
		 ".previous\n"
		 ".section .altinstructions,\"a\"\n"
		 " .long 1b - .\n"		/* src offset */
		 " .long 0\n"			/* no replacement */
		 " .word %P[feature]\n"		/* feature bit */
		 " .byte 3b - 1b\n"		/* src len */
		 " .byte 0\n"			/* repl len */
		 " .byte 0\n"			/* pad len */
		 ".previous\n"
		 ".section .altinstr_aux,\"ax\"\n"
		 "6:\n"
		 " testb %[bitnum],%[cap_byte]\n"
		 " jnz %l[t_yes]\n"
		 " jmp %l[t_no]\n"
		 ".previous\n"
195 196 197
		 : : [feature]  "i" (bit),
		     [always]   "i" (X86_FEATURE_ALWAYS),
		     [bitnum]   "i" (1 << (bit & 7)),
198 199 200 201 202 203
		     [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3])
		 : : t_yes, t_no);
t_yes:
	return true;
t_no:
	return false;
204 205
}

206
#define static_cpu_has(bit)					\
207 208 209
(								\
	__builtin_constant_p(boot_cpu_has(bit)) ?		\
		boot_cpu_has(bit) :				\
210
		_static_cpu_has(bit)				\
211
)
212
#endif
213

214 215 216
#define cpu_has_bug(c, bit)		cpu_has(c, (bit))
#define set_cpu_bug(c, bit)		set_cpu_cap(c, (bit))
#define clear_cpu_bug(c, bit)		clear_cpu_cap(c, (bit))
217

218 219
#define static_cpu_has_bug(bit)		static_cpu_has((bit))
#define boot_cpu_has_bug(bit)		cpu_has_bug(&boot_cpu_data, (bit))
220
#define boot_cpu_set_bug(bit)		set_cpu_cap(&boot_cpu_data, (bit))
221

222 223
#define MAX_CPU_FEATURES		(NCAPINTS * 32)
#define cpu_have_feature		boot_cpu_has
224

225 226 227
#define CPU_FEATURE_TYPEFMT		"x86,ven%04Xfam%04Xmod%04X"
#define CPU_FEATURE_TYPEVAL		boot_cpu_data.x86_vendor, boot_cpu_data.x86, \
					boot_cpu_data.x86_model
228

229
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
H
H. Peter Anvin 已提交
230
#endif /* _ASM_X86_CPUFEATURE_H */