xref: /OK3568_Linux_fs/kernel/arch/x86/lib/getuser.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * __get_user functions.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (C) Copyright 1998 Linus Torvalds
6*4882a593Smuzhiyun * (C) Copyright 2005 Andi Kleen
7*4882a593Smuzhiyun * (C) Copyright 2008 Glauber Costa
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * These functions have a non-standard call interface
10*4882a593Smuzhiyun * to make them more efficient, especially as they
11*4882a593Smuzhiyun * return an error value in addition to the "real"
12*4882a593Smuzhiyun * return value.
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun/*
16*4882a593Smuzhiyun * __get_user_X
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Inputs:	%[r|e]ax contains the address.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Outputs:	%[r|e]ax is error code (0 or -EFAULT)
21*4882a593Smuzhiyun *		%[r|e]dx contains zero-extended value
22*4882a593Smuzhiyun *		%ecx contains the high half for 32-bit __get_user_8
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * These functions should not modify any other registers,
26*4882a593Smuzhiyun * as they get called from within inline assembly.
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun#include <linux/linkage.h>
30*4882a593Smuzhiyun#include <asm/page_types.h>
31*4882a593Smuzhiyun#include <asm/errno.h>
32*4882a593Smuzhiyun#include <asm/asm-offsets.h>
33*4882a593Smuzhiyun#include <asm/thread_info.h>
34*4882a593Smuzhiyun#include <asm/asm.h>
35*4882a593Smuzhiyun#include <asm/smap.h>
36*4882a593Smuzhiyun#include <asm/export.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun#ifdef CONFIG_X86_5LEVEL
41*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \
42*4882a593Smuzhiyun	ALTERNATIVE __stringify(mov $((1 << 47) - 4096 - (n)),%rdx), \
43*4882a593Smuzhiyun		    __stringify(mov $((1 << 56) - 4096 - (n)),%rdx), X86_FEATURE_LA57
44*4882a593Smuzhiyun#else
45*4882a593Smuzhiyun#define LOAD_TASK_SIZE_MINUS_N(n) \
46*4882a593Smuzhiyun	mov $(TASK_SIZE_MAX - (n)),%_ASM_DX
47*4882a593Smuzhiyun#endif
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun	.text
50*4882a593SmuzhiyunSYM_FUNC_START(__get_user_1)
51*4882a593Smuzhiyun	LOAD_TASK_SIZE_MINUS_N(0)
52*4882a593Smuzhiyun	cmp %_ASM_DX,%_ASM_AX
53*4882a593Smuzhiyun	jae bad_get_user
54*4882a593Smuzhiyun	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
55*4882a593Smuzhiyun	and %_ASM_DX, %_ASM_AX
56*4882a593Smuzhiyun	ASM_STAC
57*4882a593Smuzhiyun1:	movzbl (%_ASM_AX),%edx
58*4882a593Smuzhiyun	xor %eax,%eax
59*4882a593Smuzhiyun	ASM_CLAC
60*4882a593Smuzhiyun	RET
61*4882a593SmuzhiyunSYM_FUNC_END(__get_user_1)
62*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_1)
63*4882a593Smuzhiyun
64*4882a593SmuzhiyunSYM_FUNC_START(__get_user_2)
65*4882a593Smuzhiyun	LOAD_TASK_SIZE_MINUS_N(1)
66*4882a593Smuzhiyun	cmp %_ASM_DX,%_ASM_AX
67*4882a593Smuzhiyun	jae bad_get_user
68*4882a593Smuzhiyun	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
69*4882a593Smuzhiyun	and %_ASM_DX, %_ASM_AX
70*4882a593Smuzhiyun	ASM_STAC
71*4882a593Smuzhiyun2:	movzwl (%_ASM_AX),%edx
72*4882a593Smuzhiyun	xor %eax,%eax
73*4882a593Smuzhiyun	ASM_CLAC
74*4882a593Smuzhiyun	RET
75*4882a593SmuzhiyunSYM_FUNC_END(__get_user_2)
76*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_2)
77*4882a593Smuzhiyun
78*4882a593SmuzhiyunSYM_FUNC_START(__get_user_4)
79*4882a593Smuzhiyun	LOAD_TASK_SIZE_MINUS_N(3)
80*4882a593Smuzhiyun	cmp %_ASM_DX,%_ASM_AX
81*4882a593Smuzhiyun	jae bad_get_user
82*4882a593Smuzhiyun	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
83*4882a593Smuzhiyun	and %_ASM_DX, %_ASM_AX
84*4882a593Smuzhiyun	ASM_STAC
85*4882a593Smuzhiyun3:	movl (%_ASM_AX),%edx
86*4882a593Smuzhiyun	xor %eax,%eax
87*4882a593Smuzhiyun	ASM_CLAC
88*4882a593Smuzhiyun	RET
89*4882a593SmuzhiyunSYM_FUNC_END(__get_user_4)
90*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_4)
91*4882a593Smuzhiyun
92*4882a593SmuzhiyunSYM_FUNC_START(__get_user_8)
93*4882a593Smuzhiyun#ifdef CONFIG_X86_64
94*4882a593Smuzhiyun	LOAD_TASK_SIZE_MINUS_N(7)
95*4882a593Smuzhiyun	cmp %_ASM_DX,%_ASM_AX
96*4882a593Smuzhiyun	jae bad_get_user
97*4882a593Smuzhiyun	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
98*4882a593Smuzhiyun	and %_ASM_DX, %_ASM_AX
99*4882a593Smuzhiyun	ASM_STAC
100*4882a593Smuzhiyun4:	movq (%_ASM_AX),%rdx
101*4882a593Smuzhiyun	xor %eax,%eax
102*4882a593Smuzhiyun	ASM_CLAC
103*4882a593Smuzhiyun	RET
104*4882a593Smuzhiyun#else
105*4882a593Smuzhiyun	LOAD_TASK_SIZE_MINUS_N(7)
106*4882a593Smuzhiyun	cmp %_ASM_DX,%_ASM_AX
107*4882a593Smuzhiyun	jae bad_get_user_8
108*4882a593Smuzhiyun	sbb %_ASM_DX, %_ASM_DX		/* array_index_mask_nospec() */
109*4882a593Smuzhiyun	and %_ASM_DX, %_ASM_AX
110*4882a593Smuzhiyun	ASM_STAC
111*4882a593Smuzhiyun4:	movl (%_ASM_AX),%edx
112*4882a593Smuzhiyun5:	movl 4(%_ASM_AX),%ecx
113*4882a593Smuzhiyun	xor %eax,%eax
114*4882a593Smuzhiyun	ASM_CLAC
115*4882a593Smuzhiyun	RET
116*4882a593Smuzhiyun#endif
117*4882a593SmuzhiyunSYM_FUNC_END(__get_user_8)
118*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_8)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun/* .. and the same for __get_user, just without the range checks */
121*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_1)
122*4882a593Smuzhiyun	ASM_STAC
123*4882a593Smuzhiyun	ASM_BARRIER_NOSPEC
124*4882a593Smuzhiyun6:	movzbl (%_ASM_AX),%edx
125*4882a593Smuzhiyun	xor %eax,%eax
126*4882a593Smuzhiyun	ASM_CLAC
127*4882a593Smuzhiyun	RET
128*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_1)
129*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_1)
130*4882a593Smuzhiyun
131*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_2)
132*4882a593Smuzhiyun	ASM_STAC
133*4882a593Smuzhiyun	ASM_BARRIER_NOSPEC
134*4882a593Smuzhiyun7:	movzwl (%_ASM_AX),%edx
135*4882a593Smuzhiyun	xor %eax,%eax
136*4882a593Smuzhiyun	ASM_CLAC
137*4882a593Smuzhiyun	RET
138*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_2)
139*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_2)
140*4882a593Smuzhiyun
141*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_4)
142*4882a593Smuzhiyun	ASM_STAC
143*4882a593Smuzhiyun	ASM_BARRIER_NOSPEC
144*4882a593Smuzhiyun8:	movl (%_ASM_AX),%edx
145*4882a593Smuzhiyun	xor %eax,%eax
146*4882a593Smuzhiyun	ASM_CLAC
147*4882a593Smuzhiyun	RET
148*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_4)
149*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_4)
150*4882a593Smuzhiyun
151*4882a593SmuzhiyunSYM_FUNC_START(__get_user_nocheck_8)
152*4882a593Smuzhiyun	ASM_STAC
153*4882a593Smuzhiyun	ASM_BARRIER_NOSPEC
154*4882a593Smuzhiyun#ifdef CONFIG_X86_64
155*4882a593Smuzhiyun9:	movq (%_ASM_AX),%rdx
156*4882a593Smuzhiyun#else
157*4882a593Smuzhiyun9:	movl (%_ASM_AX),%edx
158*4882a593Smuzhiyun10:	movl 4(%_ASM_AX),%ecx
159*4882a593Smuzhiyun#endif
160*4882a593Smuzhiyun	xor %eax,%eax
161*4882a593Smuzhiyun	ASM_CLAC
162*4882a593Smuzhiyun	RET
163*4882a593SmuzhiyunSYM_FUNC_END(__get_user_nocheck_8)
164*4882a593SmuzhiyunEXPORT_SYMBOL(__get_user_nocheck_8)
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun
167*4882a593SmuzhiyunSYM_CODE_START_LOCAL(.Lbad_get_user_clac)
168*4882a593Smuzhiyun	ASM_CLAC
169*4882a593Smuzhiyunbad_get_user:
170*4882a593Smuzhiyun	xor %edx,%edx
171*4882a593Smuzhiyun	mov $(-EFAULT),%_ASM_AX
172*4882a593Smuzhiyun	RET
173*4882a593SmuzhiyunSYM_CODE_END(.Lbad_get_user_clac)
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun#ifdef CONFIG_X86_32
176*4882a593SmuzhiyunSYM_CODE_START_LOCAL(.Lbad_get_user_8_clac)
177*4882a593Smuzhiyun	ASM_CLAC
178*4882a593Smuzhiyunbad_get_user_8:
179*4882a593Smuzhiyun	xor %edx,%edx
180*4882a593Smuzhiyun	xor %ecx,%ecx
181*4882a593Smuzhiyun	mov $(-EFAULT),%_ASM_AX
182*4882a593Smuzhiyun	RET
183*4882a593SmuzhiyunSYM_CODE_END(.Lbad_get_user_8_clac)
184*4882a593Smuzhiyun#endif
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun/* get_user */
187*4882a593Smuzhiyun	_ASM_EXTABLE_UA(1b, .Lbad_get_user_clac)
188*4882a593Smuzhiyun	_ASM_EXTABLE_UA(2b, .Lbad_get_user_clac)
189*4882a593Smuzhiyun	_ASM_EXTABLE_UA(3b, .Lbad_get_user_clac)
190*4882a593Smuzhiyun#ifdef CONFIG_X86_64
191*4882a593Smuzhiyun	_ASM_EXTABLE_UA(4b, .Lbad_get_user_clac)
192*4882a593Smuzhiyun#else
193*4882a593Smuzhiyun	_ASM_EXTABLE_UA(4b, .Lbad_get_user_8_clac)
194*4882a593Smuzhiyun	_ASM_EXTABLE_UA(5b, .Lbad_get_user_8_clac)
195*4882a593Smuzhiyun#endif
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun/* __get_user */
198*4882a593Smuzhiyun	_ASM_EXTABLE_UA(6b, .Lbad_get_user_clac)
199*4882a593Smuzhiyun	_ASM_EXTABLE_UA(7b, .Lbad_get_user_clac)
200*4882a593Smuzhiyun	_ASM_EXTABLE_UA(8b, .Lbad_get_user_clac)
201*4882a593Smuzhiyun#ifdef CONFIG_X86_64
202*4882a593Smuzhiyun	_ASM_EXTABLE_UA(9b, .Lbad_get_user_clac)
203*4882a593Smuzhiyun#else
204*4882a593Smuzhiyun	_ASM_EXTABLE_UA(9b, .Lbad_get_user_8_clac)
205*4882a593Smuzhiyun	_ASM_EXTABLE_UA(10b, .Lbad_get_user_8_clac)
206*4882a593Smuzhiyun#endif
207