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#ifdef CONFIG_X86_5LEVEL 37#define LOAD_TASK_SIZE_MINUS_N(n) \ 38 ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rbx), \ 39 __stringify(mov $((1 << 56) - 4096 - (n)),%rbx), X86_FEATURE_LA57 40#else 41#define LOAD_TASK_SIZE_MINUS_N(n) \ 42 mov $(TASK_SIZE_MAX - (n)),%_ASM_BX 43#endif 44 45.text 46SYM_FUNC_START(__put_user_1) 47 LOAD_TASK_SIZE_MINUS_N(0) 48 cmp %_ASM_BX,%_ASM_CX 49 jae .Lbad_put_user 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 LOAD_TASK_SIZE_MINUS_N(1) 70 cmp %_ASM_BX,%_ASM_CX 71 jae .Lbad_put_user 72 ASM_STAC 733: movw %ax,(%_ASM_CX) 74 xor %ecx,%ecx 75 ASM_CLAC 76 RET 77SYM_FUNC_END(__put_user_2) 78EXPORT_SYMBOL(__put_user_2) 79 80SYM_FUNC_START(__put_user_nocheck_2) 81 ENDBR 82 ASM_STAC 834: movw %ax,(%_ASM_CX) 84 xor %ecx,%ecx 85 ASM_CLAC 86 RET 87SYM_FUNC_END(__put_user_nocheck_2) 88EXPORT_SYMBOL(__put_user_nocheck_2) 89 90SYM_FUNC_START(__put_user_4) 91 LOAD_TASK_SIZE_MINUS_N(3) 92 cmp %_ASM_BX,%_ASM_CX 93 jae .Lbad_put_user 94 ASM_STAC 955: movl %eax,(%_ASM_CX) 96 xor %ecx,%ecx 97 ASM_CLAC 98 RET 99SYM_FUNC_END(__put_user_4) 100EXPORT_SYMBOL(__put_user_4) 101 102SYM_FUNC_START(__put_user_nocheck_4) 103 ENDBR 104 ASM_STAC 1056: movl %eax,(%_ASM_CX) 106 xor %ecx,%ecx 107 ASM_CLAC 108 RET 109SYM_FUNC_END(__put_user_nocheck_4) 110EXPORT_SYMBOL(__put_user_nocheck_4) 111 112SYM_FUNC_START(__put_user_8) 113 LOAD_TASK_SIZE_MINUS_N(7) 114 cmp %_ASM_BX,%_ASM_CX 115 jae .Lbad_put_user 116 ASM_STAC 1177: mov %_ASM_AX,(%_ASM_CX) 118#ifdef CONFIG_X86_32 1198: movl %edx,4(%_ASM_CX) 120#endif 121 xor %ecx,%ecx 122 ASM_CLAC 123 RET 124SYM_FUNC_END(__put_user_8) 125EXPORT_SYMBOL(__put_user_8) 126 127SYM_FUNC_START(__put_user_nocheck_8) 128 ENDBR 129 ASM_STAC 1309: mov %_ASM_AX,(%_ASM_CX) 131#ifdef CONFIG_X86_32 13210: movl %edx,4(%_ASM_CX) 133#endif 134 xor %ecx,%ecx 135 ASM_CLAC 136 RET 137SYM_FUNC_END(__put_user_nocheck_8) 138EXPORT_SYMBOL(__put_user_nocheck_8) 139 140SYM_CODE_START_LOCAL(.Lbad_put_user_clac) 141 ASM_CLAC 142.Lbad_put_user: 143 movl $-EFAULT,%ecx 144 RET 145SYM_CODE_END(.Lbad_put_user_clac) 146 147 _ASM_EXTABLE_UA(1b, .Lbad_put_user_clac) 148 _ASM_EXTABLE_UA(2b, .Lbad_put_user_clac) 149 _ASM_EXTABLE_UA(3b, .Lbad_put_user_clac) 150 _ASM_EXTABLE_UA(4b, .Lbad_put_user_clac) 151 _ASM_EXTABLE_UA(5b, .Lbad_put_user_clac) 152 _ASM_EXTABLE_UA(6b, .Lbad_put_user_clac) 153 _ASM_EXTABLE_UA(7b, .Lbad_put_user_clac) 154 _ASM_EXTABLE_UA(9b, .Lbad_put_user_clac) 155#ifdef CONFIG_X86_32 156 _ASM_EXTABLE_UA(8b, .Lbad_put_user_clac) 157 _ASM_EXTABLE_UA(10b, .Lbad_put_user_clac) 158#endif 159