xref: /openbmc/linux/arch/x86/include/asm/smap.h (revision e74deb11)
151ae4a2dSH. Peter Anvin /*
251ae4a2dSH. Peter Anvin  * Supervisor Mode Access Prevention support
351ae4a2dSH. Peter Anvin  *
451ae4a2dSH. Peter Anvin  * Copyright (C) 2012 Intel Corporation
551ae4a2dSH. Peter Anvin  * Author: H. Peter Anvin <hpa@linux.intel.com>
651ae4a2dSH. Peter Anvin  *
751ae4a2dSH. Peter Anvin  * This program is free software; you can redistribute it and/or
851ae4a2dSH. Peter Anvin  * modify it under the terms of the GNU General Public License
951ae4a2dSH. Peter Anvin  * as published by the Free Software Foundation; version 2
1051ae4a2dSH. Peter Anvin  * of the License.
1151ae4a2dSH. Peter Anvin  */
1251ae4a2dSH. Peter Anvin 
1351ae4a2dSH. Peter Anvin #ifndef _ASM_X86_SMAP_H
1451ae4a2dSH. Peter Anvin #define _ASM_X86_SMAP_H
1551ae4a2dSH. Peter Anvin 
1651ae4a2dSH. Peter Anvin #include <linux/stringify.h>
1751ae4a2dSH. Peter Anvin #include <asm/nops.h>
18cd4d09ecSBorislav Petkov #include <asm/cpufeatures.h>
1951ae4a2dSH. Peter Anvin 
2051ae4a2dSH. Peter Anvin /* "Raw" instruction opcodes */
2151ae4a2dSH. Peter Anvin #define __ASM_CLAC	.byte 0x0f,0x01,0xca
2251ae4a2dSH. Peter Anvin #define __ASM_STAC	.byte 0x0f,0x01,0xcb
2351ae4a2dSH. Peter Anvin 
2451ae4a2dSH. Peter Anvin #ifdef __ASSEMBLY__
2551ae4a2dSH. Peter Anvin 
2651ae4a2dSH. Peter Anvin #include <asm/alternative-asm.h>
2751ae4a2dSH. Peter Anvin 
2851ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP
2951ae4a2dSH. Peter Anvin 
3051ae4a2dSH. Peter Anvin #define ASM_CLAC \
31669f8a90SBorislav Petkov 	ALTERNATIVE "", __stringify(__ASM_CLAC), X86_FEATURE_SMAP
3251ae4a2dSH. Peter Anvin 
3351ae4a2dSH. Peter Anvin #define ASM_STAC \
34669f8a90SBorislav Petkov 	ALTERNATIVE "", __stringify(__ASM_STAC), X86_FEATURE_SMAP
3551ae4a2dSH. Peter Anvin 
3651ae4a2dSH. Peter Anvin #else /* CONFIG_X86_SMAP */
3751ae4a2dSH. Peter Anvin 
3851ae4a2dSH. Peter Anvin #define ASM_CLAC
3951ae4a2dSH. Peter Anvin #define ASM_STAC
4051ae4a2dSH. Peter Anvin 
4151ae4a2dSH. Peter Anvin #endif /* CONFIG_X86_SMAP */
4251ae4a2dSH. Peter Anvin 
4351ae4a2dSH. Peter Anvin #else /* __ASSEMBLY__ */
4451ae4a2dSH. Peter Anvin 
4551ae4a2dSH. Peter Anvin #include <asm/alternative.h>
4651ae4a2dSH. Peter Anvin 
4751ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP
4851ae4a2dSH. Peter Anvin 
4963bcff2aSH. Peter Anvin static __always_inline void clac(void)
5051ae4a2dSH. Peter Anvin {
5151ae4a2dSH. Peter Anvin 	/* Note: a barrier is implicit in alternative() */
52669f8a90SBorislav Petkov 	alternative("", __stringify(__ASM_CLAC), X86_FEATURE_SMAP);
5351ae4a2dSH. Peter Anvin }
5451ae4a2dSH. Peter Anvin 
5563bcff2aSH. Peter Anvin static __always_inline void stac(void)
5651ae4a2dSH. Peter Anvin {
5751ae4a2dSH. Peter Anvin 	/* Note: a barrier is implicit in alternative() */
58669f8a90SBorislav Petkov 	alternative("", __stringify(__ASM_STAC), X86_FEATURE_SMAP);
5951ae4a2dSH. Peter Anvin }
6051ae4a2dSH. Peter Anvin 
61e74deb11SPeter Zijlstra static __always_inline unsigned long smap_save(void)
62e74deb11SPeter Zijlstra {
63e74deb11SPeter Zijlstra 	unsigned long flags;
64e74deb11SPeter Zijlstra 
65e74deb11SPeter Zijlstra 	asm volatile (ALTERNATIVE("", "pushf; pop %0; " __stringify(__ASM_CLAC),
66e74deb11SPeter Zijlstra 				  X86_FEATURE_SMAP)
67e74deb11SPeter Zijlstra 		      : "=rm" (flags) : : "memory", "cc");
68e74deb11SPeter Zijlstra 
69e74deb11SPeter Zijlstra 	return flags;
70e74deb11SPeter Zijlstra }
71e74deb11SPeter Zijlstra 
72e74deb11SPeter Zijlstra static __always_inline void smap_restore(unsigned long flags)
73e74deb11SPeter Zijlstra {
74e74deb11SPeter Zijlstra 	asm volatile (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP)
75e74deb11SPeter Zijlstra 		      : : "g" (flags) : "memory", "cc");
76e74deb11SPeter Zijlstra }
77e74deb11SPeter Zijlstra 
7851ae4a2dSH. Peter Anvin /* These macros can be used in asm() statements */
7951ae4a2dSH. Peter Anvin #define ASM_CLAC \
80669f8a90SBorislav Petkov 	ALTERNATIVE("", __stringify(__ASM_CLAC), X86_FEATURE_SMAP)
8151ae4a2dSH. Peter Anvin #define ASM_STAC \
82669f8a90SBorislav Petkov 	ALTERNATIVE("", __stringify(__ASM_STAC), X86_FEATURE_SMAP)
8351ae4a2dSH. Peter Anvin 
8451ae4a2dSH. Peter Anvin #else /* CONFIG_X86_SMAP */
8551ae4a2dSH. Peter Anvin 
8651ae4a2dSH. Peter Anvin static inline void clac(void) { }
8751ae4a2dSH. Peter Anvin static inline void stac(void) { }
8851ae4a2dSH. Peter Anvin 
89e74deb11SPeter Zijlstra static inline unsigned long smap_save(void) { return 0; }
90e74deb11SPeter Zijlstra static inline void smap_restore(unsigned long flags) { }
91e74deb11SPeter Zijlstra 
9251ae4a2dSH. Peter Anvin #define ASM_CLAC
9351ae4a2dSH. Peter Anvin #define ASM_STAC
9451ae4a2dSH. Peter Anvin 
9551ae4a2dSH. Peter Anvin #endif /* CONFIG_X86_SMAP */
9651ae4a2dSH. Peter Anvin 
9751ae4a2dSH. Peter Anvin #endif /* __ASSEMBLY__ */
9851ae4a2dSH. Peter Anvin 
9951ae4a2dSH. Peter Anvin #endif /* _ASM_X86_SMAP_H */
100