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 46 SYM_FUNC_START(__put_user_1) 47 LOAD_TASK_SIZE_MINUS_N(0) 48 cmp %_ASM_BX,%_ASM_CX 49 jae .Lbad_put_user 50 SYM_INNER_LABEL(__put_user_nocheck_1, SYM_L_GLOBAL) 51 ASM_STAC 52 1: movb %al,(%_ASM_CX) 53 xor %ecx,%ecx 54 ASM_CLAC 55 RET 56 SYM_FUNC_END(__put_user_1) 57 EXPORT_SYMBOL(__put_user_1) 58 EXPORT_SYMBOL(__put_user_nocheck_1) 59 60 SYM_FUNC_START(__put_user_2) 61 LOAD_TASK_SIZE_MINUS_N(1) 62 cmp %_ASM_BX,%_ASM_CX 63 jae .Lbad_put_user 64 SYM_INNER_LABEL(__put_user_nocheck_2, SYM_L_GLOBAL) 65 ASM_STAC 66 2: movw %ax,(%_ASM_CX) 67 xor %ecx,%ecx 68 ASM_CLAC 69 RET 70 SYM_FUNC_END(__put_user_2) 71 EXPORT_SYMBOL(__put_user_2) 72 EXPORT_SYMBOL(__put_user_nocheck_2) 73 74 SYM_FUNC_START(__put_user_4) 75 LOAD_TASK_SIZE_MINUS_N(3) 76 cmp %_ASM_BX,%_ASM_CX 77 jae .Lbad_put_user 78 SYM_INNER_LABEL(__put_user_nocheck_4, SYM_L_GLOBAL) 79 ASM_STAC 80 3: movl %eax,(%_ASM_CX) 81 xor %ecx,%ecx 82 ASM_CLAC 83 RET 84 SYM_FUNC_END(__put_user_4) 85 EXPORT_SYMBOL(__put_user_4) 86 EXPORT_SYMBOL(__put_user_nocheck_4) 87 88 SYM_FUNC_START(__put_user_8) 89 LOAD_TASK_SIZE_MINUS_N(7) 90 cmp %_ASM_BX,%_ASM_CX 91 jae .Lbad_put_user 92 SYM_INNER_LABEL(__put_user_nocheck_8, SYM_L_GLOBAL) 93 ASM_STAC 94 4: mov %_ASM_AX,(%_ASM_CX) 95 #ifdef CONFIG_X86_32 96 5: movl %edx,4(%_ASM_CX) 97 #endif 98 xor %ecx,%ecx 99 ASM_CLAC 100 RET 101 SYM_FUNC_END(__put_user_8) 102 EXPORT_SYMBOL(__put_user_8) 103 EXPORT_SYMBOL(__put_user_nocheck_8) 104 105 SYM_CODE_START_LOCAL(.Lbad_put_user_clac) 106 ASM_CLAC 107 .Lbad_put_user: 108 movl $-EFAULT,%ecx 109 RET 110 SYM_CODE_END(.Lbad_put_user_clac) 111 112 _ASM_EXTABLE_UA(1b, .Lbad_put_user_clac) 113 _ASM_EXTABLE_UA(2b, .Lbad_put_user_clac) 114 _ASM_EXTABLE_UA(3b, .Lbad_put_user_clac) 115 _ASM_EXTABLE_UA(4b, .Lbad_put_user_clac) 116 #ifdef CONFIG_X86_32 117 _ASM_EXTABLE_UA(5b, .Lbad_put_user_clac) 118 #endif 119