cpufeature.h 7.9 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
2 3
#ifndef _ASM_X86_CPUFEATURE_H
#define _ASM_X86_CPUFEATURE_H
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))
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
#define this_cpu_has(bit)						\
115 116 117
	(__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 :	\
	 x86_this_cpu_test_bit(bit,					\
		(unsigned long __percpu *)&cpu_info.x86_capability))
118

119 120 121 122 123 124 125 126 127
/*
 * 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)	\
128
	(__builtin_constant_p(bit) && DISABLED_MASK_BIT_SET(bit) ? 0 : static_cpu_has(bit))
129

130 131
#define boot_cpu_has(bit)	cpu_has(&boot_cpu_data, bit)

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

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

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

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

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

/*
 * 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

158 159
/*
 * Static testing of CPU features.  Used the same as boot_cpu_has().
160 161
 * These will statically patch the target code for additional
 * performance.
162
 */
163
static __always_inline __pure bool _static_cpu_has(u16 bit)
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 195
	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"
196 197 198
		 : : [feature]  "i" (bit),
		     [always]   "i" (X86_FEATURE_ALWAYS),
		     [bitnum]   "i" (1 << (bit & 7)),
199 200 201 202 203 204
		     [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3])
		 : : t_yes, t_no);
t_yes:
	return true;
t_no:
	return false;
205 206
}

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

215 216 217
#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))
218

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

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

226 227 228
#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
229

230
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
231
#endif /* _ASM_X86_CPUFEATURE_H */
反馈
建议
客服 返回
顶部