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/export.h>
15#include <linux/linkage.h>
16#include <linux/objtool.h>
17#include <asm/thread_info.h>
18#include <asm/errno.h>
19#include <asm/asm.h>
20#include <asm/smap.h>
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 ANNOTATE_NOENDBR
50 check_range size=1
51 ASM_STAC
521: movb %al,(%_ASM_CX)
53 xor %ecx,%ecx
54 ASM_CLAC
55 RET
56SYM_FUNC_END(__put_user_1)
57EXPORT_SYMBOL(__put_user_1)
58
59SYM_FUNC_START(__put_user_nocheck_1)
60 ANNOTATE_NOENDBR
61 ASM_STAC
622: movb %al,(%_ASM_CX)
63 xor %ecx,%ecx
64 ASM_CLAC
65 RET
66SYM_FUNC_END(__put_user_nocheck_1)
67EXPORT_SYMBOL(__put_user_nocheck_1)
68
69SYM_FUNC_START(__put_user_2)
70 ANNOTATE_NOENDBR
71 check_range size=2
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 ANNOTATE_NOENDBR
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 ANNOTATE_NOENDBR
92 check_range size=4
93 ASM_STAC
945: movl %eax,(%_ASM_CX)
95 xor %ecx,%ecx
96 ASM_CLAC
97 RET
98SYM_FUNC_END(__put_user_4)
99EXPORT_SYMBOL(__put_user_4)
100
101SYM_FUNC_START(__put_user_nocheck_4)
102 ANNOTATE_NOENDBR
103 ASM_STAC
1046: movl %eax,(%_ASM_CX)
105 xor %ecx,%ecx
106 ASM_CLAC
107 RET
108SYM_FUNC_END(__put_user_nocheck_4)
109EXPORT_SYMBOL(__put_user_nocheck_4)
110
111SYM_FUNC_START(__put_user_8)
112 ANNOTATE_NOENDBR
113 check_range size=8
114 ASM_STAC
1157: mov %_ASM_AX,(%_ASM_CX)
116#ifdef CONFIG_X86_32
1178: movl %edx,4(%_ASM_CX)
118#endif
119 xor %ecx,%ecx
120 ASM_CLAC
121 RET
122SYM_FUNC_END(__put_user_8)
123EXPORT_SYMBOL(__put_user_8)
124
125SYM_FUNC_START(__put_user_nocheck_8)
126 ANNOTATE_NOENDBR
127 ASM_STAC
1289: mov %_ASM_AX,(%_ASM_CX)
129#ifdef CONFIG_X86_32
13010: movl %edx,4(%_ASM_CX)
131#endif
132 xor %ecx,%ecx
133 ASM_CLAC
134 RET
135SYM_FUNC_END(__put_user_nocheck_8)
136EXPORT_SYMBOL(__put_user_nocheck_8)
137
138SYM_CODE_START_LOCAL(__put_user_handle_exception)
139 ASM_CLAC
140.Lbad_put_user:
141 movl $-EFAULT,%ecx
142 RET
143SYM_CODE_END(__put_user_handle_exception)
144
145 _ASM_EXTABLE_UA(1b, __put_user_handle_exception)
146 _ASM_EXTABLE_UA(2b, __put_user_handle_exception)
147 _ASM_EXTABLE_UA(3b, __put_user_handle_exception)
148 _ASM_EXTABLE_UA(4b, __put_user_handle_exception)
149 _ASM_EXTABLE_UA(5b, __put_user_handle_exception)
150 _ASM_EXTABLE_UA(6b, __put_user_handle_exception)
151 _ASM_EXTABLE_UA(7b, __put_user_handle_exception)
152 _ASM_EXTABLE_UA(9b, __put_user_handle_exception)
153#ifdef CONFIG_X86_32
154 _ASM_EXTABLE_UA(8b, __put_user_handle_exception)
155 _ASM_EXTABLE_UA(10b, __put_user_handle_exception)
156#endif
157