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 48 SYM_FUNC_START(__put_user_1) 49 check_range size=1 50 ASM_STAC 51 1: movb %al,(%_ASM_CX) 52 xor %ecx,%ecx 53 ASM_CLAC 54 RET 55 SYM_FUNC_END(__put_user_1) 56 EXPORT_SYMBOL(__put_user_1) 57 58 SYM_FUNC_START(__put_user_nocheck_1) 59 ASM_STAC 60 2: movb %al,(%_ASM_CX) 61 xor %ecx,%ecx 62 ASM_CLAC 63 RET 64 SYM_FUNC_END(__put_user_nocheck_1) 65 EXPORT_SYMBOL(__put_user_nocheck_1) 66 67 SYM_FUNC_START(__put_user_2) 68 check_range size=2 69 ASM_STAC 70 3: movw %ax,(%_ASM_CX) 71 xor %ecx,%ecx 72 ASM_CLAC 73 RET 74 SYM_FUNC_END(__put_user_2) 75 EXPORT_SYMBOL(__put_user_2) 76 77 SYM_FUNC_START(__put_user_nocheck_2) 78 ASM_STAC 79 4: movw %ax,(%_ASM_CX) 80 xor %ecx,%ecx 81 ASM_CLAC 82 RET 83 SYM_FUNC_END(__put_user_nocheck_2) 84 EXPORT_SYMBOL(__put_user_nocheck_2) 85 86 SYM_FUNC_START(__put_user_4) 87 check_range size=4 88 ASM_STAC 89 5: movl %eax,(%_ASM_CX) 90 xor %ecx,%ecx 91 ASM_CLAC 92 RET 93 SYM_FUNC_END(__put_user_4) 94 EXPORT_SYMBOL(__put_user_4) 95 96 SYM_FUNC_START(__put_user_nocheck_4) 97 ASM_STAC 98 6: movl %eax,(%_ASM_CX) 99 xor %ecx,%ecx 100 ASM_CLAC 101 RET 102 SYM_FUNC_END(__put_user_nocheck_4) 103 EXPORT_SYMBOL(__put_user_nocheck_4) 104 105 SYM_FUNC_START(__put_user_8) 106 check_range size=8 107 ASM_STAC 108 7: mov %_ASM_AX,(%_ASM_CX) 109 #ifdef CONFIG_X86_32 110 8: movl %edx,4(%_ASM_CX) 111 #endif 112 xor %ecx,%ecx 113 ASM_CLAC 114 RET 115 SYM_FUNC_END(__put_user_8) 116 EXPORT_SYMBOL(__put_user_8) 117 118 SYM_FUNC_START(__put_user_nocheck_8) 119 ASM_STAC 120 9: mov %_ASM_AX,(%_ASM_CX) 121 #ifdef CONFIG_X86_32 122 10: movl %edx,4(%_ASM_CX) 123 #endif 124 xor %ecx,%ecx 125 ASM_CLAC 126 RET 127 SYM_FUNC_END(__put_user_nocheck_8) 128 EXPORT_SYMBOL(__put_user_nocheck_8) 129 130 SYM_CODE_START_LOCAL(__put_user_handle_exception) 131 ASM_CLAC 132 .Lbad_put_user: 133 movl $-EFAULT,%ecx 134 RET 135 SYM_CODE_END(__put_user_handle_exception) 136 137 _ASM_EXTABLE_UA(1b, __put_user_handle_exception) 138 _ASM_EXTABLE_UA(2b, __put_user_handle_exception) 139 _ASM_EXTABLE_UA(3b, __put_user_handle_exception) 140 _ASM_EXTABLE_UA(4b, __put_user_handle_exception) 141 _ASM_EXTABLE_UA(5b, __put_user_handle_exception) 142 _ASM_EXTABLE_UA(6b, __put_user_handle_exception) 143 _ASM_EXTABLE_UA(7b, __put_user_handle_exception) 144 _ASM_EXTABLE_UA(9b, __put_user_handle_exception) 145 #ifdef CONFIG_X86_32 146 _ASM_EXTABLE_UA(8b, __put_user_handle_exception) 147 _ASM_EXTABLE_UA(10b, __put_user_handle_exception) 148 #endif 149