1b886d83cSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */ 251ae4a2dSH. Peter Anvin /* 351ae4a2dSH. Peter Anvin * Supervisor Mode Access Prevention support 451ae4a2dSH. Peter Anvin * 551ae4a2dSH. Peter Anvin * Copyright (C) 2012 Intel Corporation 651ae4a2dSH. Peter Anvin * Author: H. Peter Anvin <hpa@linux.intel.com> 751ae4a2dSH. Peter Anvin */ 851ae4a2dSH. Peter Anvin 951ae4a2dSH. Peter Anvin #ifndef _ASM_X86_SMAP_H 1051ae4a2dSH. Peter Anvin #define _ASM_X86_SMAP_H 1151ae4a2dSH. Peter Anvin 1251ae4a2dSH. Peter Anvin #include <asm/nops.h> 13cd4d09ecSBorislav Petkov #include <asm/cpufeatures.h> 1451ae4a2dSH. Peter Anvin 1551ae4a2dSH. Peter Anvin /* "Raw" instruction opcodes */ 16a936af8eSPeter Zijlstra #define __ASM_CLAC ".byte 0x0f,0x01,0xca" 17a936af8eSPeter Zijlstra #define __ASM_STAC ".byte 0x0f,0x01,0xcb" 1851ae4a2dSH. Peter Anvin 1951ae4a2dSH. Peter Anvin #ifdef __ASSEMBLY__ 2051ae4a2dSH. Peter Anvin 2151ae4a2dSH. Peter Anvin #include <asm/alternative-asm.h> 2251ae4a2dSH. Peter Anvin 2351ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP 2451ae4a2dSH. Peter Anvin 2551ae4a2dSH. Peter Anvin #define ASM_CLAC \ 26a936af8eSPeter Zijlstra ALTERNATIVE "", __ASM_CLAC, X86_FEATURE_SMAP 2751ae4a2dSH. Peter Anvin 2851ae4a2dSH. Peter Anvin #define ASM_STAC \ 29a936af8eSPeter Zijlstra ALTERNATIVE "", __ASM_STAC, X86_FEATURE_SMAP 3051ae4a2dSH. Peter Anvin 3151ae4a2dSH. Peter Anvin #else /* CONFIG_X86_SMAP */ 3251ae4a2dSH. Peter Anvin 3351ae4a2dSH. Peter Anvin #define ASM_CLAC 3451ae4a2dSH. Peter Anvin #define ASM_STAC 3551ae4a2dSH. Peter Anvin 3651ae4a2dSH. Peter Anvin #endif /* CONFIG_X86_SMAP */ 3751ae4a2dSH. Peter Anvin 3851ae4a2dSH. Peter Anvin #else /* __ASSEMBLY__ */ 3951ae4a2dSH. Peter Anvin 4051ae4a2dSH. Peter Anvin #include <asm/alternative.h> 4151ae4a2dSH. Peter Anvin 4251ae4a2dSH. Peter Anvin #ifdef CONFIG_X86_SMAP 4351ae4a2dSH. Peter Anvin 4463bcff2aSH. Peter Anvin static __always_inline void clac(void) 4551ae4a2dSH. Peter Anvin { 4651ae4a2dSH. Peter Anvin /* Note: a barrier is implicit in alternative() */ 47a936af8eSPeter Zijlstra alternative("", __ASM_CLAC, X86_FEATURE_SMAP); 4851ae4a2dSH. Peter Anvin } 4951ae4a2dSH. Peter Anvin 5063bcff2aSH. Peter Anvin static __always_inline void stac(void) 5151ae4a2dSH. Peter Anvin { 5251ae4a2dSH. Peter Anvin /* Note: a barrier is implicit in alternative() */ 53a936af8eSPeter Zijlstra alternative("", __ASM_STAC, X86_FEATURE_SMAP); 5451ae4a2dSH. Peter Anvin } 5551ae4a2dSH. Peter Anvin 56e74deb11SPeter Zijlstra static __always_inline unsigned long smap_save(void) 57e74deb11SPeter Zijlstra { 58e74deb11SPeter Zijlstra unsigned long flags; 59e74deb11SPeter Zijlstra 60*1ff865e3SPeter Zijlstra asm volatile ("# smap_save\n\t" 61*1ff865e3SPeter Zijlstra ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP) 62*1ff865e3SPeter Zijlstra "pushf; pop %0; " __ASM_CLAC "\n\t" 63*1ff865e3SPeter Zijlstra "1:" 64e74deb11SPeter Zijlstra : "=rm" (flags) : : "memory", "cc"); 65e74deb11SPeter Zijlstra 66e74deb11SPeter Zijlstra return flags; 67e74deb11SPeter Zijlstra } 68e74deb11SPeter Zijlstra 69e74deb11SPeter Zijlstra static __always_inline void smap_restore(unsigned long flags) 70e74deb11SPeter Zijlstra { 71*1ff865e3SPeter Zijlstra asm volatile ("# smap_restore\n\t" 72*1ff865e3SPeter Zijlstra ALTERNATIVE("jmp 1f", "", X86_FEATURE_SMAP) 73*1ff865e3SPeter Zijlstra "push %0; popf\n\t" 74*1ff865e3SPeter Zijlstra "1:" 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 \ 80a936af8eSPeter Zijlstra ALTERNATIVE("", __ASM_CLAC, X86_FEATURE_SMAP) 8151ae4a2dSH. Peter Anvin #define ASM_STAC \ 82a936af8eSPeter Zijlstra ALTERNATIVE("", __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