1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */ 26c2d4586SGlauber Costa/* 36c2d4586SGlauber Costa * __get_user functions. 46c2d4586SGlauber Costa * 56c2d4586SGlauber Costa * (C) Copyright 1998 Linus Torvalds 66c2d4586SGlauber Costa * (C) Copyright 2005 Andi Kleen 76c2d4586SGlauber Costa * (C) Copyright 2008 Glauber Costa 86c2d4586SGlauber Costa * 96c2d4586SGlauber Costa * These functions have a non-standard call interface 106c2d4586SGlauber Costa * to make them more efficient, especially as they 116c2d4586SGlauber Costa * return an error value in addition to the "real" 126c2d4586SGlauber Costa * return value. 136c2d4586SGlauber Costa */ 146c2d4586SGlauber Costa 156c2d4586SGlauber Costa/* 166c2d4586SGlauber Costa * __get_user_X 176c2d4586SGlauber Costa * 186c2d4586SGlauber Costa * Inputs: %[r|e]ax contains the address. 196c2d4586SGlauber Costa * 206c2d4586SGlauber Costa * Outputs: %[r|e]ax is error code (0 or -EFAULT) 216c2d4586SGlauber Costa * %[r|e]dx contains zero-extended value 2296477b4cSVille Syrjälä * %ecx contains the high half for 32-bit __get_user_8 236c2d4586SGlauber Costa * 246c2d4586SGlauber Costa * 256c2d4586SGlauber Costa * These functions should not modify any other registers, 266c2d4586SGlauber Costa * as they get called from within inline assembly. 276c2d4586SGlauber Costa */ 286c2d4586SGlauber Costa 296c2d4586SGlauber Costa#include <linux/linkage.h> 300341c14dSJeremy Fitzhardinge#include <asm/page_types.h> 316c2d4586SGlauber Costa#include <asm/errno.h> 326c2d4586SGlauber Costa#include <asm/asm-offsets.h> 336c2d4586SGlauber Costa#include <asm/thread_info.h> 346c2d4586SGlauber Costa#include <asm/asm.h> 3563bcff2aSH. Peter Anvin#include <asm/smap.h> 36784d5699SAl Viro#include <asm/export.h> 376c2d4586SGlauber Costa 38ea6f043fSLinus Torvalds#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC 39ea6f043fSLinus Torvalds 40b19b74bcSKirill A. Shutemov.macro check_range size:req 41b19b74bcSKirill A. Shutemov.if IS_ENABLED(CONFIG_X86_64) 42b19b74bcSKirill A. Shutemov mov %rax, %rdx 43b19b74bcSKirill A. Shutemov sar $63, %rdx 44b19b74bcSKirill A. Shutemov or %rdx, %rax 45b19b74bcSKirill A. Shutemov.else 46b19b74bcSKirill A. Shutemov cmp $TASK_SIZE_MAX-\size+1, %eax 47*567cfc59SKees Cook.if \size != 8 48b19b74bcSKirill A. Shutemov jae .Lbad_get_user 49*567cfc59SKees Cook.else 50*567cfc59SKees Cook jae .Lbad_get_user_8 51*567cfc59SKees Cook.endif 52b19b74bcSKirill A. Shutemov sbb %edx, %edx /* array_index_mask_nospec() */ 53b19b74bcSKirill A. Shutemov and %edx, %eax 54b19b74bcSKirill A. Shutemov.endif 55b19b74bcSKirill A. Shutemov.endm 5647058bb5SChristoph Hellwig 576c2d4586SGlauber Costa .text 586dcc5627SJiri SlabySYM_FUNC_START(__get_user_1) 59b19b74bcSKirill A. Shutemov check_range size=1 6063bcff2aSH. Peter Anvin ASM_STAC 6116640165SH. Peter Anvin1: movzbl (%_ASM_AX),%edx 626c2d4586SGlauber Costa xor %eax,%eax 6363bcff2aSH. Peter Anvin ASM_CLAC 64f94909ceSPeter Zijlstra RET 656dcc5627SJiri SlabySYM_FUNC_END(__get_user_1) 66784d5699SAl ViroEXPORT_SYMBOL(__get_user_1) 676c2d4586SGlauber Costa 686dcc5627SJiri SlabySYM_FUNC_START(__get_user_2) 69b19b74bcSKirill A. Shutemov check_range size=2 7063bcff2aSH. Peter Anvin ASM_STAC 7147058bb5SChristoph Hellwig2: movzwl (%_ASM_AX),%edx 726c2d4586SGlauber Costa xor %eax,%eax 7363bcff2aSH. Peter Anvin ASM_CLAC 74f94909ceSPeter Zijlstra RET 756dcc5627SJiri SlabySYM_FUNC_END(__get_user_2) 76784d5699SAl ViroEXPORT_SYMBOL(__get_user_2) 776c2d4586SGlauber Costa 786dcc5627SJiri SlabySYM_FUNC_START(__get_user_4) 79b19b74bcSKirill A. Shutemov check_range size=4 8063bcff2aSH. Peter Anvin ASM_STAC 8147058bb5SChristoph Hellwig3: movl (%_ASM_AX),%edx 826c2d4586SGlauber Costa xor %eax,%eax 8363bcff2aSH. Peter Anvin ASM_CLAC 84f94909ceSPeter Zijlstra RET 856dcc5627SJiri SlabySYM_FUNC_END(__get_user_4) 86784d5699SAl ViroEXPORT_SYMBOL(__get_user_4) 876c2d4586SGlauber Costa 886dcc5627SJiri SlabySYM_FUNC_START(__get_user_8) 89b19b74bcSKirill A. Shutemov check_range size=8 90b19b74bcSKirill A. Shutemov ASM_STAC 9196477b4cSVille Syrjälä#ifdef CONFIG_X86_64 9247058bb5SChristoph Hellwig4: movq (%_ASM_AX),%rdx 9396477b4cSVille Syrjälä#else 9447058bb5SChristoph Hellwig4: movl (%_ASM_AX),%edx 9547058bb5SChristoph Hellwig5: movl 4(%_ASM_AX),%ecx 96b19b74bcSKirill A. Shutemov#endif 9796477b4cSVille Syrjälä xor %eax,%eax 9896477b4cSVille Syrjälä ASM_CLAC 99f94909ceSPeter Zijlstra RET 1006dcc5627SJiri SlabySYM_FUNC_END(__get_user_8) 101784d5699SAl ViroEXPORT_SYMBOL(__get_user_8) 10296477b4cSVille Syrjälä 103ea6f043fSLinus Torvalds/* .. and the same for __get_user, just without the range checks */ 104ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_1) 105ea6f043fSLinus Torvalds ASM_STAC 106ea6f043fSLinus Torvalds ASM_BARRIER_NOSPEC 107ea6f043fSLinus Torvalds6: movzbl (%_ASM_AX),%edx 108ea6f043fSLinus Torvalds xor %eax,%eax 109ea6f043fSLinus Torvalds ASM_CLAC 110f94909ceSPeter Zijlstra RET 111ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_1) 112ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_1) 113ea6f043fSLinus Torvalds 114ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_2) 115ea6f043fSLinus Torvalds ASM_STAC 116ea6f043fSLinus Torvalds ASM_BARRIER_NOSPEC 117ea6f043fSLinus Torvalds7: movzwl (%_ASM_AX),%edx 118ea6f043fSLinus Torvalds xor %eax,%eax 119ea6f043fSLinus Torvalds ASM_CLAC 120f94909ceSPeter Zijlstra RET 121ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_2) 122ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_2) 123ea6f043fSLinus Torvalds 124ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_4) 125ea6f043fSLinus Torvalds ASM_STAC 126ea6f043fSLinus Torvalds ASM_BARRIER_NOSPEC 127ea6f043fSLinus Torvalds8: movl (%_ASM_AX),%edx 128ea6f043fSLinus Torvalds xor %eax,%eax 129ea6f043fSLinus Torvalds ASM_CLAC 130f94909ceSPeter Zijlstra RET 131ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_4) 132ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_4) 133ea6f043fSLinus Torvalds 134ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_8) 135ea6f043fSLinus Torvalds ASM_STAC 136ea6f043fSLinus Torvalds ASM_BARRIER_NOSPEC 137ea6f043fSLinus Torvalds#ifdef CONFIG_X86_64 138ea6f043fSLinus Torvalds9: movq (%_ASM_AX),%rdx 139ea6f043fSLinus Torvalds#else 140ea6f043fSLinus Torvalds9: movl (%_ASM_AX),%edx 141ea6f043fSLinus Torvalds10: movl 4(%_ASM_AX),%ecx 142ea6f043fSLinus Torvalds#endif 143ea6f043fSLinus Torvalds xor %eax,%eax 144ea6f043fSLinus Torvalds ASM_CLAC 145f94909ceSPeter Zijlstra RET 146ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_8) 147ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_8) 148ea6f043fSLinus Torvalds 1496c2d4586SGlauber Costa 1505516c89dSNadav AmitSYM_CODE_START_LOCAL(__get_user_handle_exception) 15182e844a6SJosh Poimboeuf ASM_CLAC 152b19b74bcSKirill A. Shutemov.Lbad_get_user: 1536c2d4586SGlauber Costa xor %edx,%edx 1546c2d4586SGlauber Costa mov $(-EFAULT),%_ASM_AX 155f94909ceSPeter Zijlstra RET 1565516c89dSNadav AmitSYM_CODE_END(__get_user_handle_exception) 1576c2d4586SGlauber Costa 15896477b4cSVille Syrjälä#ifdef CONFIG_X86_32 1595516c89dSNadav AmitSYM_CODE_START_LOCAL(__get_user_8_handle_exception) 16082e844a6SJosh Poimboeuf ASM_CLAC 161*567cfc59SKees Cook.Lbad_get_user_8: 16296477b4cSVille Syrjälä xor %edx,%edx 16396477b4cSVille Syrjälä xor %ecx,%ecx 16496477b4cSVille Syrjälä mov $(-EFAULT),%_ASM_AX 165f94909ceSPeter Zijlstra RET 1665516c89dSNadav AmitSYM_CODE_END(__get_user_8_handle_exception) 16796477b4cSVille Syrjälä#endif 16896477b4cSVille Syrjälä 169ea6f043fSLinus Torvalds/* get_user */ 1702aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(1b, __get_user_handle_exception) 1712aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(2b, __get_user_handle_exception) 1722aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(3b, __get_user_handle_exception) 1736c2d4586SGlauber Costa#ifdef CONFIG_X86_64 1742aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(4b, __get_user_handle_exception) 17596477b4cSVille Syrjälä#else 1762aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(4b, __get_user_8_handle_exception) 1772aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(5b, __get_user_8_handle_exception) 1786c2d4586SGlauber Costa#endif 179ea6f043fSLinus Torvalds 180ea6f043fSLinus Torvalds/* __get_user */ 1812aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(6b, __get_user_handle_exception) 1822aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(7b, __get_user_handle_exception) 1832aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(8b, __get_user_handle_exception) 184ea6f043fSLinus Torvalds#ifdef CONFIG_X86_64 1852aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(9b, __get_user_handle_exception) 186ea6f043fSLinus Torvalds#else 1872aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(9b, __get_user_8_handle_exception) 1882aed1b6cSQiuxu Zhuo _ASM_EXTABLE_UA(10b, __get_user_8_handle_exception) 189ea6f043fSLinus Torvalds#endif 190