1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * __put_user functions. 4 * 5 * (C) Copyright 2005 Linus Torvalds 6 * (C) Copyright 2005 Andi Kleen 7 * (C) Copyright 2008 Glauber Costa 8 * 9 * These functions have a non-standard call interface 10 * to make them more efficient, especially as they 11 * return an error value in addition to the "real" 12 * return value. 13 */ 14#include <linux/linkage.h> 15#include <asm/thread_info.h> 16#include <asm/errno.h> 17#include <asm/asm.h> 18#include <asm/smap.h> 19#include <asm/export.h> 20 21 22/* 23 * __put_user_X 24 * 25 * Inputs: %eax[:%edx] contains the data 26 * %ecx contains the address 27 * 28 * Outputs: %ecx is error code (0 or -EFAULT) 29 * 30 * Clobbers: %ebx needed for task pointer 31 * 32 * These functions should not modify any other registers, 33 * as they get called from within inline assembly. 34 */ 35 36.macro check_range size:req 37.if IS_ENABLED(CONFIG_X86_64) 38 mov %rcx, %rbx 39 sar $63, %rbx 40 or %rbx, %rcx 41.else 42 cmp $TASK_SIZE_MAX-\size+1, %ecx 43 jae .Lbad_put_user 44.endif 45.endm 46 47.text 48SYM_FUNC_START(__put_user_1) 49 check_range size=1 50 ASM_STAC 511: movb %al,(%_ASM_CX) 52 xor %ecx,%ecx 53 ASM_CLAC 54 RET 55SYM_FUNC_END(__put_user_1) 56EXPORT_SYMBOL(__put_user_1) 57 58SYM_FUNC_START(__put_user_nocheck_1) 59 ENDBR 60 ASM_STAC 612: movb %al,(%_ASM_CX) 62 xor %ecx,%ecx 63 ASM_CLAC 64 RET 65SYM_FUNC_END(__put_user_nocheck_1) 66EXPORT_SYMBOL(__put_user_nocheck_1) 67 68SYM_FUNC_START(__put_user_2) 69 check_range size=2 70 ASM_STAC 713: movw %ax,(%_ASM_CX) 72 xor %ecx,%ecx 73 ASM_CLAC 74 RET 75SYM_FUNC_END(__put_user_2) 76EXPORT_SYMBOL(__put_user_2) 77 78SYM_FUNC_START(__put_user_nocheck_2) 79 ENDBR 80 ASM_STAC 814: movw %ax,(%_ASM_CX) 82 xor %ecx,%ecx 83 ASM_CLAC 84 RET 85SYM_FUNC_END(__put_user_nocheck_2) 86EXPORT_SYMBOL(__put_user_nocheck_2) 87 88SYM_FUNC_START(__put_user_4) 89 check_range size=4 90 ASM_STAC 915: movl %eax,(%_ASM_CX) 92 xor %ecx,%ecx 93 ASM_CLAC 94 RET 95SYM_FUNC_END(__put_user_4) 96EXPORT_SYMBOL(__put_user_4) 97 98SYM_FUNC_START(__put_user_nocheck_4) 99 ENDBR 100 ASM_STAC 1016: movl %eax,(%_ASM_CX) 102 xor %ecx,%ecx 103 ASM_CLAC 104 RET 105SYM_FUNC_END(__put_user_nocheck_4) 106EXPORT_SYMBOL(__put_user_nocheck_4) 107 108SYM_FUNC_START(__put_user_8) 109 check_range size=8 110 ASM_STAC 1117: mov %_ASM_AX,(%_ASM_CX) 112#ifdef CONFIG_X86_32 1138: movl %edx,4(%_ASM_CX) 114#endif 115 xor %ecx,%ecx 116 ASM_CLAC 117 RET 118SYM_FUNC_END(__put_user_8) 119EXPORT_SYMBOL(__put_user_8) 120 121SYM_FUNC_START(__put_user_nocheck_8) 122 ENDBR 123 ASM_STAC 1249: mov %_ASM_AX,(%_ASM_CX) 125#ifdef CONFIG_X86_32 12610: movl %edx,4(%_ASM_CX) 127#endif 128 xor %ecx,%ecx 129 ASM_CLAC 130 RET 131SYM_FUNC_END(__put_user_nocheck_8) 132EXPORT_SYMBOL(__put_user_nocheck_8) 133 134SYM_CODE_START_LOCAL(.Lbad_put_user_clac) 135 ASM_CLAC 136.Lbad_put_user: 137 movl $-EFAULT,%ecx 138 RET 139SYM_CODE_END(.Lbad_put_user_clac) 140 141 _ASM_EXTABLE(1b, .Lbad_put_user_clac) 142 _ASM_EXTABLE(2b, .Lbad_put_user_clac) 143 _ASM_EXTABLE(3b, .Lbad_put_user_clac) 144 _ASM_EXTABLE(4b, .Lbad_put_user_clac) 145 _ASM_EXTABLE(5b, .Lbad_put_user_clac) 146 _ASM_EXTABLE(6b, .Lbad_put_user_clac) 147 _ASM_EXTABLE(7b, .Lbad_put_user_clac) 148 _ASM_EXTABLE(9b, .Lbad_put_user_clac) 149#ifdef CONFIG_X86_32 150 _ASM_EXTABLE(8b, .Lbad_put_user_clac) 151 _ASM_EXTABLE(10b, .Lbad_put_user_clac) 152#endif 153