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