xref: /openbmc/linux/arch/x86/include/asm/ibt.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1156ff4a5SPeter Zijlstra /* SPDX-License-Identifier: GPL-2.0 */
2156ff4a5SPeter Zijlstra #ifndef _ASM_X86_IBT_H
3156ff4a5SPeter Zijlstra #define _ASM_X86_IBT_H
4156ff4a5SPeter Zijlstra 
5156ff4a5SPeter Zijlstra #include <linux/types.h>
6156ff4a5SPeter Zijlstra 
7156ff4a5SPeter Zijlstra /*
8156ff4a5SPeter Zijlstra  * The rules for enabling IBT are:
9156ff4a5SPeter Zijlstra  *
10156ff4a5SPeter Zijlstra  *  - CC_HAS_IBT:         the toolchain supports it
11156ff4a5SPeter Zijlstra  *  - X86_KERNEL_IBT:     it is selected in Kconfig
12156ff4a5SPeter Zijlstra  *  - !__DISABLE_EXPORTS: this is regular kernel code
13156ff4a5SPeter Zijlstra  *
14156ff4a5SPeter Zijlstra  * Esp. that latter one is a bit non-obvious, but some code like compressed,
15156ff4a5SPeter Zijlstra  * purgatory, realmode etc.. is built with custom CFLAGS that do not include
16156ff4a5SPeter Zijlstra  * -fcf-protection=branch and things will go *bang*.
17156ff4a5SPeter Zijlstra  *
18156ff4a5SPeter Zijlstra  * When all the above are satisfied, HAS_KERNEL_IBT will be 1, otherwise 0.
19156ff4a5SPeter Zijlstra  */
20156ff4a5SPeter Zijlstra #if defined(CONFIG_X86_KERNEL_IBT) && !defined(__DISABLE_EXPORTS)
21156ff4a5SPeter Zijlstra 
22156ff4a5SPeter Zijlstra #define HAS_KERNEL_IBT	1
23156ff4a5SPeter Zijlstra 
24156ff4a5SPeter Zijlstra #ifndef __ASSEMBLY__
25156ff4a5SPeter Zijlstra 
26156ff4a5SPeter Zijlstra #ifdef CONFIG_X86_64
27156ff4a5SPeter Zijlstra #define ASM_ENDBR	"endbr64\n\t"
28156ff4a5SPeter Zijlstra #else
29156ff4a5SPeter Zijlstra #define ASM_ENDBR	"endbr32\n\t"
30156ff4a5SPeter Zijlstra #endif
31156ff4a5SPeter Zijlstra 
32156ff4a5SPeter Zijlstra #define __noendbr	__attribute__((nocf_check))
33156ff4a5SPeter Zijlstra 
34e27e5beaSJosh Poimboeuf /*
35e27e5beaSJosh Poimboeuf  * Create a dummy function pointer reference to prevent objtool from marking
36e27e5beaSJosh Poimboeuf  * the function as needing to be "sealed" (i.e. ENDBR converted to NOP by
37*be0fffa5SPeter Zijlstra  * apply_seal_endbr()).
38e27e5beaSJosh Poimboeuf  */
39e27e5beaSJosh Poimboeuf #define IBT_NOSEAL(fname)				\
40e27e5beaSJosh Poimboeuf 	".pushsection .discard.ibt_endbr_noseal\n\t"	\
41e27e5beaSJosh Poimboeuf 	_ASM_PTR fname "\n\t"				\
42e27e5beaSJosh Poimboeuf 	".popsection\n\t"
43e27e5beaSJosh Poimboeuf 
gen_endbr(void)44156ff4a5SPeter Zijlstra static inline __attribute_const__ u32 gen_endbr(void)
45156ff4a5SPeter Zijlstra {
46156ff4a5SPeter Zijlstra 	u32 endbr;
47156ff4a5SPeter Zijlstra 
48156ff4a5SPeter Zijlstra 	/*
49156ff4a5SPeter Zijlstra 	 * Generate ENDBR64 in a way that is sure to not result in
50156ff4a5SPeter Zijlstra 	 * an ENDBR64 instruction as immediate.
51156ff4a5SPeter Zijlstra 	 */
52156ff4a5SPeter Zijlstra 	asm ( "mov $~0xfa1e0ff3, %[endbr]\n\t"
53156ff4a5SPeter Zijlstra 	      "not %[endbr]\n\t"
54156ff4a5SPeter Zijlstra 	       : [endbr] "=&r" (endbr) );
55156ff4a5SPeter Zijlstra 
56156ff4a5SPeter Zijlstra 	return endbr;
57156ff4a5SPeter Zijlstra }
58156ff4a5SPeter Zijlstra 
gen_endbr_poison(void)59ed53a0d9SPeter Zijlstra static inline __attribute_const__ u32 gen_endbr_poison(void)
60ed53a0d9SPeter Zijlstra {
61ed53a0d9SPeter Zijlstra 	/*
62ed53a0d9SPeter Zijlstra 	 * 4 byte NOP that isn't NOP4 (in fact it is OSP NOP3), such that it
63ed53a0d9SPeter Zijlstra 	 * will be unique to (former) ENDBR sites.
64ed53a0d9SPeter Zijlstra 	 */
65ed53a0d9SPeter Zijlstra 	return 0x001f0f66; /* osp nopl (%rax) */
66ed53a0d9SPeter Zijlstra }
67ed53a0d9SPeter Zijlstra 
is_endbr(u32 val)68156ff4a5SPeter Zijlstra static inline bool is_endbr(u32 val)
69156ff4a5SPeter Zijlstra {
70ed53a0d9SPeter Zijlstra 	if (val == gen_endbr_poison())
71ed53a0d9SPeter Zijlstra 		return true;
72ed53a0d9SPeter Zijlstra 
73156ff4a5SPeter Zijlstra 	val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
74156ff4a5SPeter Zijlstra 	return val == gen_endbr();
75156ff4a5SPeter Zijlstra }
76156ff4a5SPeter Zijlstra 
7793be2859SArd Biesheuvel extern __noendbr u64 ibt_save(bool disable);
78fe379fa4SPeter Zijlstra extern __noendbr void ibt_restore(u64 save);
79fe379fa4SPeter Zijlstra 
80156ff4a5SPeter Zijlstra #else /* __ASSEMBLY__ */
81156ff4a5SPeter Zijlstra 
82156ff4a5SPeter Zijlstra #ifdef CONFIG_X86_64
83156ff4a5SPeter Zijlstra #define ENDBR	endbr64
84156ff4a5SPeter Zijlstra #else
85156ff4a5SPeter Zijlstra #define ENDBR	endbr32
86156ff4a5SPeter Zijlstra #endif
87156ff4a5SPeter Zijlstra 
88156ff4a5SPeter Zijlstra #endif /* __ASSEMBLY__ */
89156ff4a5SPeter Zijlstra 
90156ff4a5SPeter Zijlstra #else /* !IBT */
91156ff4a5SPeter Zijlstra 
92156ff4a5SPeter Zijlstra #define HAS_KERNEL_IBT	0
93156ff4a5SPeter Zijlstra 
94156ff4a5SPeter Zijlstra #ifndef __ASSEMBLY__
95156ff4a5SPeter Zijlstra 
96156ff4a5SPeter Zijlstra #define ASM_ENDBR
97e27e5beaSJosh Poimboeuf #define IBT_NOSEAL(name)
98156ff4a5SPeter Zijlstra 
99156ff4a5SPeter Zijlstra #define __noendbr
100156ff4a5SPeter Zijlstra 
is_endbr(u32 val)101156ff4a5SPeter Zijlstra static inline bool is_endbr(u32 val) { return false; }
102156ff4a5SPeter Zijlstra 
ibt_save(bool disable)10393be2859SArd Biesheuvel static inline u64 ibt_save(bool disable) { return 0; }
ibt_restore(u64 save)104fe379fa4SPeter Zijlstra static inline void ibt_restore(u64 save) { }
105fe379fa4SPeter Zijlstra 
106156ff4a5SPeter Zijlstra #else /* __ASSEMBLY__ */
107156ff4a5SPeter Zijlstra 
108156ff4a5SPeter Zijlstra #define ENDBR
109156ff4a5SPeter Zijlstra 
110156ff4a5SPeter Zijlstra #endif /* __ASSEMBLY__ */
111156ff4a5SPeter Zijlstra 
112156ff4a5SPeter Zijlstra #endif /* CONFIG_X86_KERNEL_IBT */
113156ff4a5SPeter Zijlstra 
114156ff4a5SPeter Zijlstra #define ENDBR_INSN_SIZE		(4*HAS_KERNEL_IBT)
115156ff4a5SPeter Zijlstra 
116156ff4a5SPeter Zijlstra #endif /* _ASM_X86_IBT_H */
117