x86/lib: Revert to _ASM_EXTABLE_UA() for {get,put}_user() fixups
[platform/kernel/linux-rpi.git] / arch / x86 / lib / getuser.S
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  */
14
15 /*
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  */
28
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>
37
38 #define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
39
40 .macro check_range size:req
41 .if IS_ENABLED(CONFIG_X86_64)
42         mov %rax, %rdx
43         sar $63, %rdx
44         or %rdx, %rax
45 .else
46         cmp $TASK_SIZE_MAX-\size+1, %eax
47         jae .Lbad_get_user
48         sbb %edx, %edx          /* array_index_mask_nospec() */
49         and %edx, %eax
50 .endif
51 .endm
52
53         .text
54 SYM_FUNC_START(__get_user_1)
55         check_range size=1
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)
63
64 SYM_FUNC_START(__get_user_2)
65         check_range size=2
66         ASM_STAC
67 2:      movzwl (%_ASM_AX),%edx
68         xor %eax,%eax
69         ASM_CLAC
70         RET
71 SYM_FUNC_END(__get_user_2)
72 EXPORT_SYMBOL(__get_user_2)
73
74 SYM_FUNC_START(__get_user_4)
75         check_range size=4
76         ASM_STAC
77 3:      movl (%_ASM_AX),%edx
78         xor %eax,%eax
79         ASM_CLAC
80         RET
81 SYM_FUNC_END(__get_user_4)
82 EXPORT_SYMBOL(__get_user_4)
83
84 SYM_FUNC_START(__get_user_8)
85         check_range size=8
86         ASM_STAC
87 #ifdef CONFIG_X86_64
88 4:      movq (%_ASM_AX),%rdx
89 #else
90 4:      movl (%_ASM_AX),%edx
91 5:      movl 4(%_ASM_AX),%ecx
92 #endif
93         xor %eax,%eax
94         ASM_CLAC
95         RET
96 SYM_FUNC_END(__get_user_8)
97 EXPORT_SYMBOL(__get_user_8)
98
99 /* .. and the same for __get_user, just without the range checks */
100 SYM_FUNC_START(__get_user_nocheck_1)
101         ASM_STAC
102         ASM_BARRIER_NOSPEC
103 6:      movzbl (%_ASM_AX),%edx
104         xor %eax,%eax
105         ASM_CLAC
106         RET
107 SYM_FUNC_END(__get_user_nocheck_1)
108 EXPORT_SYMBOL(__get_user_nocheck_1)
109
110 SYM_FUNC_START(__get_user_nocheck_2)
111         ASM_STAC
112         ASM_BARRIER_NOSPEC
113 7:      movzwl (%_ASM_AX),%edx
114         xor %eax,%eax
115         ASM_CLAC
116         RET
117 SYM_FUNC_END(__get_user_nocheck_2)
118 EXPORT_SYMBOL(__get_user_nocheck_2)
119
120 SYM_FUNC_START(__get_user_nocheck_4)
121         ASM_STAC
122         ASM_BARRIER_NOSPEC
123 8:      movl (%_ASM_AX),%edx
124         xor %eax,%eax
125         ASM_CLAC
126         RET
127 SYM_FUNC_END(__get_user_nocheck_4)
128 EXPORT_SYMBOL(__get_user_nocheck_4)
129
130 SYM_FUNC_START(__get_user_nocheck_8)
131         ASM_STAC
132         ASM_BARRIER_NOSPEC
133 #ifdef CONFIG_X86_64
134 9:      movq (%_ASM_AX),%rdx
135 #else
136 9:      movl (%_ASM_AX),%edx
137 10:     movl 4(%_ASM_AX),%ecx
138 #endif
139         xor %eax,%eax
140         ASM_CLAC
141         RET
142 SYM_FUNC_END(__get_user_nocheck_8)
143 EXPORT_SYMBOL(__get_user_nocheck_8)
144
145
146 SYM_CODE_START_LOCAL(__get_user_handle_exception)
147         ASM_CLAC
148 .Lbad_get_user:
149         xor %edx,%edx
150         mov $(-EFAULT),%_ASM_AX
151         RET
152 SYM_CODE_END(__get_user_handle_exception)
153
154 #ifdef CONFIG_X86_32
155 SYM_CODE_START_LOCAL(__get_user_8_handle_exception)
156         ASM_CLAC
157 bad_get_user_8:
158         xor %edx,%edx
159         xor %ecx,%ecx
160         mov $(-EFAULT),%_ASM_AX
161         RET
162 SYM_CODE_END(__get_user_8_handle_exception)
163 #endif
164
165 /* get_user */
166         _ASM_EXTABLE_UA(1b, __get_user_handle_exception)
167         _ASM_EXTABLE_UA(2b, __get_user_handle_exception)
168         _ASM_EXTABLE_UA(3b, __get_user_handle_exception)
169 #ifdef CONFIG_X86_64
170         _ASM_EXTABLE_UA(4b, __get_user_handle_exception)
171 #else
172         _ASM_EXTABLE_UA(4b, __get_user_8_handle_exception)
173         _ASM_EXTABLE_UA(5b, __get_user_8_handle_exception)
174 #endif
175
176 /* __get_user */
177         _ASM_EXTABLE_UA(6b, __get_user_handle_exception)
178         _ASM_EXTABLE_UA(7b, __get_user_handle_exception)
179         _ASM_EXTABLE_UA(8b, __get_user_handle_exception)
180 #ifdef CONFIG_X86_64
181         _ASM_EXTABLE_UA(9b, __get_user_handle_exception)
182 #else
183         _ASM_EXTABLE_UA(9b, __get_user_8_handle_exception)
184         _ASM_EXTABLE_UA(10b, __get_user_8_handle_exception)
185 #endif