xref: /openbmc/linux/arch/x86/lib/getuser.S (revision 6c71a0574249f5e5a45fe055ab5f837023d5eeca)
1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */
26c2d4586SGlauber Costa/*
36c2d4586SGlauber Costa * __get_user functions.
46c2d4586SGlauber Costa *
56c2d4586SGlauber Costa * (C) Copyright 1998 Linus Torvalds
66c2d4586SGlauber Costa * (C) Copyright 2005 Andi Kleen
76c2d4586SGlauber Costa * (C) Copyright 2008 Glauber Costa
86c2d4586SGlauber Costa *
96c2d4586SGlauber Costa * These functions have a non-standard call interface
106c2d4586SGlauber Costa * to make them more efficient, especially as they
116c2d4586SGlauber Costa * return an error value in addition to the "real"
126c2d4586SGlauber Costa * return value.
136c2d4586SGlauber Costa */
146c2d4586SGlauber Costa
156c2d4586SGlauber Costa/*
166c2d4586SGlauber Costa * __get_user_X
176c2d4586SGlauber Costa *
186c2d4586SGlauber Costa * Inputs:	%[r|e]ax contains the address.
196c2d4586SGlauber Costa *
206c2d4586SGlauber Costa * Outputs:	%[r|e]ax is error code (0 or -EFAULT)
216c2d4586SGlauber Costa *		%[r|e]dx contains zero-extended value
2296477b4cSVille Syrjälä *		%ecx contains the high half for 32-bit __get_user_8
236c2d4586SGlauber Costa *
246c2d4586SGlauber Costa *
256c2d4586SGlauber Costa * These functions should not modify any other registers,
266c2d4586SGlauber Costa * as they get called from within inline assembly.
276c2d4586SGlauber Costa */
286c2d4586SGlauber Costa
296c2d4586SGlauber Costa#include <linux/linkage.h>
300341c14dSJeremy Fitzhardinge#include <asm/page_types.h>
316c2d4586SGlauber Costa#include <asm/errno.h>
326c2d4586SGlauber Costa#include <asm/asm-offsets.h>
336c2d4586SGlauber Costa#include <asm/thread_info.h>
346c2d4586SGlauber Costa#include <asm/asm.h>
3563bcff2aSH. Peter Anvin#include <asm/smap.h>
36784d5699SAl Viro#include <asm/export.h>
376c2d4586SGlauber Costa
38ea6f043fSLinus Torvalds#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
39ea6f043fSLinus Torvalds
40b19b74bcSKirill A. Shutemov.macro check_range size:req
41b19b74bcSKirill A. Shutemov.if IS_ENABLED(CONFIG_X86_64)
42b19b74bcSKirill A. Shutemov	mov %rax, %rdx
43b19b74bcSKirill A. Shutemov	sar $63, %rdx
44b19b74bcSKirill A. Shutemov	or %rdx, %rax
45b19b74bcSKirill A. Shutemov.else
46b19b74bcSKirill A. Shutemov	cmp $TASK_SIZE_MAX-\size+1, %eax
47*567cfc59SKees Cook.if \size != 8
48b19b74bcSKirill A. Shutemov	jae .Lbad_get_user
49*567cfc59SKees Cook.else
50*567cfc59SKees Cook	jae .Lbad_get_user_8
51*567cfc59SKees Cook.endif
52b19b74bcSKirill A. Shutemov	sbb %edx, %edx		/* array_index_mask_nospec() */
53b19b74bcSKirill A. Shutemov	and %edx, %eax
54b19b74bcSKirill A. Shutemov.endif
55b19b74bcSKirill A. Shutemov.endm
5647058bb5SChristoph Hellwig
576c2d4586SGlauber Costa	.text
586dcc5627SJiri SlabySYM_FUNC_START(__get_user_1)
59b19b74bcSKirill A. Shutemov	check_range size=1
6063bcff2aSH. Peter Anvin	ASM_STAC
6116640165SH. Peter Anvin1:	movzbl (%_ASM_AX),%edx
626c2d4586SGlauber Costa	xor %eax,%eax
6363bcff2aSH. Peter Anvin	ASM_CLAC
64f94909ceSPeter Zijlstra	RET
656dcc5627SJiri SlabySYM_FUNC_END(__get_user_1)
66784d5699SAl ViroEXPORT_SYMBOL(__get_user_1)
676c2d4586SGlauber Costa
686dcc5627SJiri SlabySYM_FUNC_START(__get_user_2)
69b19b74bcSKirill A. Shutemov	check_range size=2
7063bcff2aSH. Peter Anvin	ASM_STAC
7147058bb5SChristoph Hellwig2:	movzwl (%_ASM_AX),%edx
726c2d4586SGlauber Costa	xor %eax,%eax
7363bcff2aSH. Peter Anvin	ASM_CLAC
74f94909ceSPeter Zijlstra	RET
756dcc5627SJiri SlabySYM_FUNC_END(__get_user_2)
76784d5699SAl ViroEXPORT_SYMBOL(__get_user_2)
776c2d4586SGlauber Costa
786dcc5627SJiri SlabySYM_FUNC_START(__get_user_4)
79b19b74bcSKirill A. Shutemov	check_range size=4
8063bcff2aSH. Peter Anvin	ASM_STAC
8147058bb5SChristoph Hellwig3:	movl (%_ASM_AX),%edx
826c2d4586SGlauber Costa	xor %eax,%eax
8363bcff2aSH. Peter Anvin	ASM_CLAC
84f94909ceSPeter Zijlstra	RET
856dcc5627SJiri SlabySYM_FUNC_END(__get_user_4)
86784d5699SAl ViroEXPORT_SYMBOL(__get_user_4)
876c2d4586SGlauber Costa
886dcc5627SJiri SlabySYM_FUNC_START(__get_user_8)
89b19b74bcSKirill A. Shutemov	check_range size=8
90b19b74bcSKirill A. Shutemov	ASM_STAC
9196477b4cSVille Syrjälä#ifdef CONFIG_X86_64
9247058bb5SChristoph Hellwig4:	movq (%_ASM_AX),%rdx
9396477b4cSVille Syrjälä#else
9447058bb5SChristoph Hellwig4:	movl (%_ASM_AX),%edx
9547058bb5SChristoph Hellwig5:	movl 4(%_ASM_AX),%ecx
96b19b74bcSKirill A. Shutemov#endif
9796477b4cSVille Syrjälä	xor %eax,%eax
9896477b4cSVille Syrjälä	ASM_CLAC
99f94909ceSPeter Zijlstra	RET
1006dcc5627SJiri SlabySYM_FUNC_END(__get_user_8)
101784d5699SAl ViroEXPORT_SYMBOL(__get_user_8)
10296477b4cSVille Syrjälä
103ea6f043fSLinus Torvalds/* .. and the same for __get_user, just without the range checks */
104ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_1)
105ea6f043fSLinus Torvalds	ASM_STAC
106ea6f043fSLinus Torvalds	ASM_BARRIER_NOSPEC
107ea6f043fSLinus Torvalds6:	movzbl (%_ASM_AX),%edx
108ea6f043fSLinus Torvalds	xor %eax,%eax
109ea6f043fSLinus Torvalds	ASM_CLAC
110f94909ceSPeter Zijlstra	RET
111ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_1)
112ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_1)
113ea6f043fSLinus Torvalds
114ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_2)
115ea6f043fSLinus Torvalds	ASM_STAC
116ea6f043fSLinus Torvalds	ASM_BARRIER_NOSPEC
117ea6f043fSLinus Torvalds7:	movzwl (%_ASM_AX),%edx
118ea6f043fSLinus Torvalds	xor %eax,%eax
119ea6f043fSLinus Torvalds	ASM_CLAC
120f94909ceSPeter Zijlstra	RET
121ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_2)
122ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_2)
123ea6f043fSLinus Torvalds
124ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_4)
125ea6f043fSLinus Torvalds	ASM_STAC
126ea6f043fSLinus Torvalds	ASM_BARRIER_NOSPEC
127ea6f043fSLinus Torvalds8:	movl (%_ASM_AX),%edx
128ea6f043fSLinus Torvalds	xor %eax,%eax
129ea6f043fSLinus Torvalds	ASM_CLAC
130f94909ceSPeter Zijlstra	RET
131ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_4)
132ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_4)
133ea6f043fSLinus Torvalds
134ea6f043fSLinus TorvaldsSYM_FUNC_START(__get_user_nocheck_8)
135ea6f043fSLinus Torvalds	ASM_STAC
136ea6f043fSLinus Torvalds	ASM_BARRIER_NOSPEC
137ea6f043fSLinus Torvalds#ifdef CONFIG_X86_64
138ea6f043fSLinus Torvalds9:	movq (%_ASM_AX),%rdx
139ea6f043fSLinus Torvalds#else
140ea6f043fSLinus Torvalds9:	movl (%_ASM_AX),%edx
141ea6f043fSLinus Torvalds10:	movl 4(%_ASM_AX),%ecx
142ea6f043fSLinus Torvalds#endif
143ea6f043fSLinus Torvalds	xor %eax,%eax
144ea6f043fSLinus Torvalds	ASM_CLAC
145f94909ceSPeter Zijlstra	RET
146ea6f043fSLinus TorvaldsSYM_FUNC_END(__get_user_nocheck_8)
147ea6f043fSLinus TorvaldsEXPORT_SYMBOL(__get_user_nocheck_8)
148ea6f043fSLinus Torvalds
1496c2d4586SGlauber Costa
1505516c89dSNadav AmitSYM_CODE_START_LOCAL(__get_user_handle_exception)
15182e844a6SJosh Poimboeuf	ASM_CLAC
152b19b74bcSKirill A. Shutemov.Lbad_get_user:
1536c2d4586SGlauber Costa	xor %edx,%edx
1546c2d4586SGlauber Costa	mov $(-EFAULT),%_ASM_AX
155f94909ceSPeter Zijlstra	RET
1565516c89dSNadav AmitSYM_CODE_END(__get_user_handle_exception)
1576c2d4586SGlauber Costa
15896477b4cSVille Syrjälä#ifdef CONFIG_X86_32
1595516c89dSNadav AmitSYM_CODE_START_LOCAL(__get_user_8_handle_exception)
16082e844a6SJosh Poimboeuf	ASM_CLAC
161*567cfc59SKees Cook.Lbad_get_user_8:
16296477b4cSVille Syrjälä	xor %edx,%edx
16396477b4cSVille Syrjälä	xor %ecx,%ecx
16496477b4cSVille Syrjälä	mov $(-EFAULT),%_ASM_AX
165f94909ceSPeter Zijlstra	RET
1665516c89dSNadav AmitSYM_CODE_END(__get_user_8_handle_exception)
16796477b4cSVille Syrjälä#endif
16896477b4cSVille Syrjälä
169ea6f043fSLinus Torvalds/* get_user */
1702aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(1b, __get_user_handle_exception)
1712aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(2b, __get_user_handle_exception)
1722aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(3b, __get_user_handle_exception)
1736c2d4586SGlauber Costa#ifdef CONFIG_X86_64
1742aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(4b, __get_user_handle_exception)
17596477b4cSVille Syrjälä#else
1762aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(4b, __get_user_8_handle_exception)
1772aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(5b, __get_user_8_handle_exception)
1786c2d4586SGlauber Costa#endif
179ea6f043fSLinus Torvalds
180ea6f043fSLinus Torvalds/* __get_user */
1812aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(6b, __get_user_handle_exception)
1822aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(7b, __get_user_handle_exception)
1832aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(8b, __get_user_handle_exception)
184ea6f043fSLinus Torvalds#ifdef CONFIG_X86_64
1852aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(9b, __get_user_handle_exception)
186ea6f043fSLinus Torvalds#else
1872aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(9b, __get_user_8_handle_exception)
1882aed1b6cSQiuxu Zhuo	_ASM_EXTABLE_UA(10b, __get_user_8_handle_exception)
189ea6f043fSLinus Torvalds#endif
190