1 /* 2 * Supervisor Mode Access Prevention support 3 * 4 * Copyright (C) 2012 Intel Corporation 5 * Author: H. Peter Anvin <hpa@linux.intel.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; version 2 10 * of the License. 11 */ 12 13 #ifndef _ASM_X86_SMAP_H 14 #define _ASM_X86_SMAP_H 15 16 #include <asm/nops.h> 17 #include <asm/cpufeatures.h> 18 19 /* "Raw" instruction opcodes */ 20 #define __ASM_CLAC ".byte 0x0f,0x01,0xca" 21 #define __ASM_STAC ".byte 0x0f,0x01,0xcb" 22 23 #ifdef __ASSEMBLY__ 24 25 #include <asm/alternative-asm.h> 26 27 #ifdef CONFIG_X86_SMAP 28 29 #define ASM_CLAC \ 30 ALTERNATIVE "", __ASM_CLAC, X86_FEATURE_SMAP 31 32 #define ASM_STAC \ 33 ALTERNATIVE "", __ASM_STAC, X86_FEATURE_SMAP 34 35 #else /* CONFIG_X86_SMAP */ 36 37 #define ASM_CLAC 38 #define ASM_STAC 39 40 #endif /* CONFIG_X86_SMAP */ 41 42 #else /* __ASSEMBLY__ */ 43 44 #include <asm/alternative.h> 45 46 #ifdef CONFIG_X86_SMAP 47 48 static __always_inline void clac(void) 49 { 50 /* Note: a barrier is implicit in alternative() */ 51 alternative("", __ASM_CLAC, X86_FEATURE_SMAP); 52 } 53 54 static __always_inline void stac(void) 55 { 56 /* Note: a barrier is implicit in alternative() */ 57 alternative("", __ASM_STAC, X86_FEATURE_SMAP); 58 } 59 60 static __always_inline unsigned long smap_save(void) 61 { 62 unsigned long flags; 63 64 asm volatile (ALTERNATIVE("", "pushf; pop %0; " __ASM_CLAC, 65 X86_FEATURE_SMAP) 66 : "=rm" (flags) : : "memory", "cc"); 67 68 return flags; 69 } 70 71 static __always_inline void smap_restore(unsigned long flags) 72 { 73 asm volatile (ALTERNATIVE("", "push %0; popf", X86_FEATURE_SMAP) 74 : : "g" (flags) : "memory", "cc"); 75 } 76 77 /* These macros can be used in asm() statements */ 78 #define ASM_CLAC \ 79 ALTERNATIVE("", __ASM_CLAC, X86_FEATURE_SMAP) 80 #define ASM_STAC \ 81 ALTERNATIVE("", __ASM_STAC, X86_FEATURE_SMAP) 82 83 #else /* CONFIG_X86_SMAP */ 84 85 static inline void clac(void) { } 86 static inline void stac(void) { } 87 88 static inline unsigned long smap_save(void) { return 0; } 89 static inline void smap_restore(unsigned long flags) { } 90 91 #define ASM_CLAC 92 #define ASM_STAC 93 94 #endif /* CONFIG_X86_SMAP */ 95 96 #endif /* __ASSEMBLY__ */ 97 98 #endif /* _ASM_X86_SMAP_H */ 99