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