WIP FPC-III support
[linux/fpc-iii.git] / arch / x86 / lib / getuser.S
blobfa1bc2104b326ee36e41e9a89a74c2b8c5f511dc
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * __get_user functions.
4  *
5  * (C) Copyright 1998 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  */
16  * __get_user_X
17  *
18  * Inputs:      %[r|e]ax contains the address.
19  *
20  * Outputs:     %[r|e]ax is error code (0 or -EFAULT)
21  *              %[r|e]dx contains zero-extended value
22  *              %ecx contains the high half for 32-bit __get_user_8
23  *
24  *
25  * These functions should not modify any other registers,
26  * as they get called from within inline assembly.
27  */
29 #include <linux/linkage.h>
30 #include <asm/page_types.h>
31 #include <asm/errno.h>
32 #include <asm/asm-offsets.h>
33 #include <asm/thread_info.h>
34 #include <asm/asm.h>
35 #include <asm/smap.h>
36 #include <asm/export.h>
38 #define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
40 #ifdef CONFIG_X86_5LEVEL
41 #define LOAD_TASK_SIZE_MINUS_N(n) \
42         ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rdx), \
43                     __stringify(mov $((1 << 56) - 4096 - (n)),%rdx), X86_FEATURE_LA57
44 #else
45 #define LOAD_TASK_SIZE_MINUS_N(n) \
46         mov $(TASK_SIZE_MAX - (n)),%_ASM_DX
47 #endif
49         .text
50 SYM_FUNC_START(__get_user_1)
51         LOAD_TASK_SIZE_MINUS_N(0)
52         cmp %_ASM_DX,%_ASM_AX
53         jae bad_get_user
54         sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
55         and %_ASM_DX, %_ASM_AX
56         ASM_STAC
57 1:      movzbl (%_ASM_AX),%edx
58         xor %eax,%eax
59         ASM_CLAC
60         ret
61 SYM_FUNC_END(__get_user_1)
62 EXPORT_SYMBOL(__get_user_1)
64 SYM_FUNC_START(__get_user_2)
65         LOAD_TASK_SIZE_MINUS_N(1)
66         cmp %_ASM_DX,%_ASM_AX
67         jae bad_get_user
68         sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
69         and %_ASM_DX, %_ASM_AX
70         ASM_STAC
71 2:      movzwl (%_ASM_AX),%edx
72         xor %eax,%eax
73         ASM_CLAC
74         ret
75 SYM_FUNC_END(__get_user_2)
76 EXPORT_SYMBOL(__get_user_2)
78 SYM_FUNC_START(__get_user_4)
79         LOAD_TASK_SIZE_MINUS_N(3)
80         cmp %_ASM_DX,%_ASM_AX
81         jae bad_get_user
82         sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
83         and %_ASM_DX, %_ASM_AX
84         ASM_STAC
85 3:      movl (%_ASM_AX),%edx
86         xor %eax,%eax
87         ASM_CLAC
88         ret
89 SYM_FUNC_END(__get_user_4)
90 EXPORT_SYMBOL(__get_user_4)
92 SYM_FUNC_START(__get_user_8)
93 #ifdef CONFIG_X86_64
94         LOAD_TASK_SIZE_MINUS_N(7)
95         cmp %_ASM_DX,%_ASM_AX
96         jae bad_get_user
97         sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
98         and %_ASM_DX, %_ASM_AX
99         ASM_STAC
100 4:      movq (%_ASM_AX),%rdx
101         xor %eax,%eax
102         ASM_CLAC
103         ret
104 #else
105         LOAD_TASK_SIZE_MINUS_N(7)
106         cmp %_ASM_DX,%_ASM_AX
107         jae bad_get_user_8
108         sbb %_ASM_DX, %_ASM_DX          /* array_index_mask_nospec() */
109         and %_ASM_DX, %_ASM_AX
110         ASM_STAC
111 4:      movl (%_ASM_AX),%edx
112 5:      movl 4(%_ASM_AX),%ecx
113         xor %eax,%eax
114         ASM_CLAC
115         ret
116 #endif
117 SYM_FUNC_END(__get_user_8)
118 EXPORT_SYMBOL(__get_user_8)
120 /* .. and the same for __get_user, just without the range checks */
121 SYM_FUNC_START(__get_user_nocheck_1)
122         ASM_STAC
123         ASM_BARRIER_NOSPEC
124 6:      movzbl (%_ASM_AX),%edx
125         xor %eax,%eax
126         ASM_CLAC
127         ret
128 SYM_FUNC_END(__get_user_nocheck_1)
129 EXPORT_SYMBOL(__get_user_nocheck_1)
131 SYM_FUNC_START(__get_user_nocheck_2)
132         ASM_STAC
133         ASM_BARRIER_NOSPEC
134 7:      movzwl (%_ASM_AX),%edx
135         xor %eax,%eax
136         ASM_CLAC
137         ret
138 SYM_FUNC_END(__get_user_nocheck_2)
139 EXPORT_SYMBOL(__get_user_nocheck_2)
141 SYM_FUNC_START(__get_user_nocheck_4)
142         ASM_STAC
143         ASM_BARRIER_NOSPEC
144 8:      movl (%_ASM_AX),%edx
145         xor %eax,%eax
146         ASM_CLAC
147         ret
148 SYM_FUNC_END(__get_user_nocheck_4)
149 EXPORT_SYMBOL(__get_user_nocheck_4)
151 SYM_FUNC_START(__get_user_nocheck_8)
152         ASM_STAC
153         ASM_BARRIER_NOSPEC
154 #ifdef CONFIG_X86_64
155 9:      movq (%_ASM_AX),%rdx
156 #else
157 9:      movl (%_ASM_AX),%edx
158 10:     movl 4(%_ASM_AX),%ecx
159 #endif
160         xor %eax,%eax
161         ASM_CLAC
162         ret
163 SYM_FUNC_END(__get_user_nocheck_8)
164 EXPORT_SYMBOL(__get_user_nocheck_8)
167 SYM_CODE_START_LOCAL(.Lbad_get_user_clac)
168         ASM_CLAC
169 bad_get_user:
170         xor %edx,%edx
171         mov $(-EFAULT),%_ASM_AX
172         ret
173 SYM_CODE_END(.Lbad_get_user_clac)
175 #ifdef CONFIG_X86_32
176 SYM_CODE_START_LOCAL(.Lbad_get_user_8_clac)
177         ASM_CLAC
178 bad_get_user_8:
179         xor %edx,%edx
180         xor %ecx,%ecx
181         mov $(-EFAULT),%_ASM_AX
182         ret
183 SYM_CODE_END(.Lbad_get_user_8_clac)
184 #endif
186 /* get_user */
187         _ASM_EXTABLE_UA(1b, .Lbad_get_user_clac)
188         _ASM_EXTABLE_UA(2b, .Lbad_get_user_clac)
189         _ASM_EXTABLE_UA(3b, .Lbad_get_user_clac)
190 #ifdef CONFIG_X86_64
191         _ASM_EXTABLE_UA(4b, .Lbad_get_user_clac)
192 #else
193         _ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac)
194         _ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac)
195 #endif
197 /* __get_user */
198         _ASM_EXTABLE_UA(6b, .Lbad_get_user_clac)
199         _ASM_EXTABLE_UA(7b, .Lbad_get_user_clac)
200         _ASM_EXTABLE_UA(8b, .Lbad_get_user_clac)
201 #ifdef CONFIG_X86_64
202         _ASM_EXTABLE_UA(9b, .Lbad_get_user_clac)
203 #else
204         _ASM_EXTABLE_UA(9b, .Lbad_get_user_8_clac)
205         _ASM_EXTABLE_UA(10b, .Lbad_get_user_8_clac)
206 #endif