xref: /linux/arch/x86/include/asm/smap.h (revision a936af8ea3580855adcc80daa8e01c0196afeb15)
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 <asm/nops.h>
17cd4d09ecSBorislav Petkov #include <asm/cpufeatures.h>
1851ae4a2dSH. Peter Anvin 
1951ae4a2dSH. Peter Anvin /* "Raw" instruction opcodes */
20*a936af8eSPeter Zijlstra #define __ASM_CLAC	".byte 0x0f,0x01,0xca"
21*a936af8eSPeter Zijlstra #define __ASM_STAC	".byte 0x0f,0x01,0xcb"
2251ae4a2dSH. Peter Anvin 
2351ae4a2dSH. Peter Anvin #ifdef __ASSEMBLY__
2451ae4a2dSH. Peter Anvin 
2551ae4a2dSH. Peter Anvin #include <asm/alternative-asm.h>
2651ae4a2dSH. Peter Anvin 
2751ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP
2851ae4a2dSH. Peter Anvin 
2951ae4a2dSH. Peter Anvin #define ASM_CLAC \
30*a936af8eSPeter Zijlstra 	ALTERNATIVE "", __ASM_CLAC, X86_FEATURE_SMAP
3151ae4a2dSH. Peter Anvin 
3251ae4a2dSH. Peter Anvin #define ASM_STAC \
33*a936af8eSPeter Zijlstra 	ALTERNATIVE "", __ASM_STAC, X86_FEATURE_SMAP
3451ae4a2dSH. Peter Anvin 
3551ae4a2dSH. Peter Anvin #else /* CONFIG_X86_SMAP */
3651ae4a2dSH. Peter Anvin 
3751ae4a2dSH. Peter Anvin #define ASM_CLAC
3851ae4a2dSH. Peter Anvin #define ASM_STAC
3951ae4a2dSH. Peter Anvin 
4051ae4a2dSH. Peter Anvin #endif /* CONFIG_X86_SMAP */
4151ae4a2dSH. Peter Anvin 
4251ae4a2dSH. Peter Anvin #else /* __ASSEMBLY__ */
4351ae4a2dSH. Peter Anvin 
4451ae4a2dSH. Peter Anvin #include <asm/alternative.h>
4551ae4a2dSH. Peter Anvin 
4651ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP
4751ae4a2dSH. Peter Anvin 
4863bcff2aSH. Peter Anvin static __always_inline void clac(void)
4951ae4a2dSH. Peter Anvin {
5051ae4a2dSH. Peter Anvin 	/* Note: a barrier is implicit in alternative() */
51*a936af8eSPeter Zijlstra 	alternative("", __ASM_CLAC, X86_FEATURE_SMAP);
5251ae4a2dSH. Peter Anvin }
5351ae4a2dSH. Peter Anvin 
5463bcff2aSH. Peter Anvin static __always_inline void stac(void)
5551ae4a2dSH. Peter Anvin {
5651ae4a2dSH. Peter Anvin 	/* Note: a barrier is implicit in alternative() */
57*a936af8eSPeter Zijlstra 	alternative("", __ASM_STAC, X86_FEATURE_SMAP);
5851ae4a2dSH. Peter Anvin }
5951ae4a2dSH. Peter Anvin 
60e74deb11SPeter Zijlstra static __always_inline unsigned long smap_save(void)
61e74deb11SPeter Zijlstra {
62e74deb11SPeter Zijlstra 	unsigned long flags;
63e74deb11SPeter Zijlstra 
64*a936af8eSPeter Zijlstra 	asm volatile (ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC,
65e74deb11SPeter Zijlstra 				  X86_FEATURE_SMAP)
66e74deb11SPeter Zijlstra 		      : "=rm" (flags) : : "memory", "cc");
67e74deb11SPeter Zijlstra 
68e74deb11SPeter Zijlstra 	return flags;
69e74deb11SPeter Zijlstra }
70e74deb11SPeter Zijlstra 
71e74deb11SPeter Zijlstra static __always_inline void smap_restore(unsigned long flags)
72e74deb11SPeter Zijlstra {
73e74deb11SPeter Zijlstra 	asm volatile (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP)
74e74deb11SPeter Zijlstra 		      : : "g" (flags) : "memory", "cc");
75e74deb11SPeter Zijlstra }
76e74deb11SPeter Zijlstra 
7751ae4a2dSH. Peter Anvin /* These macros can be used in asm() statements */
7851ae4a2dSH. Peter Anvin #define ASM_CLAC \
79*a936af8eSPeter Zijlstra 	ALTERNATIVE("", __ASM_CLAC, X86_FEATURE_SMAP)
8051ae4a2dSH. Peter Anvin #define ASM_STAC \
81*a936af8eSPeter Zijlstra 	ALTERNATIVE("", __ASM_STAC, X86_FEATURE_SMAP)
8251ae4a2dSH. Peter Anvin 
8351ae4a2dSH. Peter Anvin #else /* CONFIG_X86_SMAP */
8451ae4a2dSH. Peter Anvin 
8551ae4a2dSH. Peter Anvin static inline void clac(void) { }
8651ae4a2dSH. Peter Anvin static inline void stac(void) { }
8751ae4a2dSH. Peter Anvin 
88e74deb11SPeter Zijlstra static inline unsigned long smap_save(void) { return 0; }
89e74deb11SPeter Zijlstra static inline void smap_restore(unsigned long flags) { }
90e74deb11SPeter Zijlstra 
9151ae4a2dSH. Peter Anvin #define ASM_CLAC
9251ae4a2dSH. Peter Anvin #define ASM_STAC
9351ae4a2dSH. Peter Anvin 
9451ae4a2dSH. Peter Anvin #endif /* CONFIG_X86_SMAP */
9551ae4a2dSH. Peter Anvin 
9651ae4a2dSH. Peter Anvin #endif /* __ASSEMBLY__ */
9751ae4a2dSH. Peter Anvin 
9851ae4a2dSH. Peter Anvin #endif /* _ASM_X86_SMAP_H */
99