blob: 20ef350a60fbb59a4b183bc3e54b1d517e6bba9b [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * __get_user functions.
4 *
5 * (C) Copyright 1998 Linus Torvalds
6 * (C) Copyright 2005 Andi Kleen
Glauber Costa6c2d4582008-06-24 12:05:11 -03007 * (C) Copyright 2008 Glauber Costa
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
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 *
Glauber Costa6c2d4582008-06-24 12:05:11 -030018 * Inputs: %[r|e]ax contains the address.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Glauber Costa6c2d4582008-06-24 12:05:11 -030020 * Outputs: %[r|e]ax is error code (0 or -EFAULT)
21 * %[r|e]dx contains zero-extended value
Ville Syrjälä96477b42012-12-12 13:34:03 +020022 * %ecx contains the high half for 32-bit __get_user_8
Glauber Costa6c2d4582008-06-24 12:05:11 -030023 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 *
25 * These functions should not modify any other registers,
26 * as they get called from within inline assembly.
27 */
28
Masahiro Yamada94ea9c02023-08-06 23:59:56 +090029#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/linkage.h>
Jeremy Fitzhardinge0341c142009-02-13 11:14:01 -080031#include <asm/page_types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/errno.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020033#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <asm/thread_info.h>
Glauber Costa40faf462008-06-24 11:37:57 -030035#include <asm/asm.h>
H. Peter Anvin63bcff22012-09-21 12:43:12 -070036#include <asm/smap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Linus Torvaldsea6f0432020-04-08 12:50:01 -070038#define ASM_BARRIER_NOSPEC ALTERNATIVE "", "lfence", X86_FEATURE_LFENCE_RDTSC
39
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030040.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
Christoph Hellwig47058bb2020-09-03 16:22:40 +020052
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 .text
Jiri Slaby6dcc5622019-10-11 13:51:04 +020054SYM_FUNC_START(__get_user_1)
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030055 check_range size=1
H. Peter Anvin63bcff22012-09-21 12:43:12 -070056 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800571: movzbl (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030058 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070059 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +010060 RET
Jiri Slaby6dcc5622019-10-11 13:51:04 +020061SYM_FUNC_END(__get_user_1)
Al Viro784d5692016-01-11 11:04:34 -050062EXPORT_SYMBOL(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Jiri Slaby6dcc5622019-10-11 13:51:04 +020064SYM_FUNC_START(__get_user_2)
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030065 check_range size=2
H. Peter Anvin63bcff22012-09-21 12:43:12 -070066 ASM_STAC
Christoph Hellwig47058bb2020-09-03 16:22:40 +0200672: movzwl (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030068 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070069 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +010070 RET
Jiri Slaby6dcc5622019-10-11 13:51:04 +020071SYM_FUNC_END(__get_user_2)
Al Viro784d5692016-01-11 11:04:34 -050072EXPORT_SYMBOL(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Jiri Slaby6dcc5622019-10-11 13:51:04 +020074SYM_FUNC_START(__get_user_4)
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030075 check_range size=4
H. Peter Anvin63bcff22012-09-21 12:43:12 -070076 ASM_STAC
Christoph Hellwig47058bb2020-09-03 16:22:40 +0200773: movl (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030078 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070079 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +010080 RET
Jiri Slaby6dcc5622019-10-11 13:51:04 +020081SYM_FUNC_END(__get_user_4)
Al Viro784d5692016-01-11 11:04:34 -050082EXPORT_SYMBOL(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Jiri Slaby6dcc5622019-10-11 13:51:04 +020084SYM_FUNC_START(__get_user_8)
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030085 check_range size=8
86 ASM_STAC
Ville Syrjälä96477b42012-12-12 13:34:03 +020087#ifdef CONFIG_X86_64
Christoph Hellwig47058bb2020-09-03 16:22:40 +0200884: movq (%_ASM_AX),%rdx
Ville Syrjälä96477b42012-12-12 13:34:03 +020089#else
Christoph Hellwig47058bb2020-09-03 16:22:40 +0200904: movl (%_ASM_AX),%edx
915: movl 4(%_ASM_AX),%ecx
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +030092#endif
Ville Syrjälä96477b42012-12-12 13:34:03 +020093 xor %eax,%eax
94 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +010095 RET
Jiri Slaby6dcc5622019-10-11 13:51:04 +020096SYM_FUNC_END(__get_user_8)
Al Viro784d5692016-01-11 11:04:34 -050097EXPORT_SYMBOL(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +020098
Linus Torvaldsea6f0432020-04-08 12:50:01 -070099/* .. and the same for __get_user, just without the range checks */
100SYM_FUNC_START(__get_user_nocheck_1)
101 ASM_STAC
102 ASM_BARRIER_NOSPEC
1036: movzbl (%_ASM_AX),%edx
104 xor %eax,%eax
105 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100106 RET
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700107SYM_FUNC_END(__get_user_nocheck_1)
108EXPORT_SYMBOL(__get_user_nocheck_1)
109
110SYM_FUNC_START(__get_user_nocheck_2)
111 ASM_STAC
112 ASM_BARRIER_NOSPEC
1137: movzwl (%_ASM_AX),%edx
114 xor %eax,%eax
115 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100116 RET
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700117SYM_FUNC_END(__get_user_nocheck_2)
118EXPORT_SYMBOL(__get_user_nocheck_2)
119
120SYM_FUNC_START(__get_user_nocheck_4)
121 ASM_STAC
122 ASM_BARRIER_NOSPEC
1238: movl (%_ASM_AX),%edx
124 xor %eax,%eax
125 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100126 RET
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700127SYM_FUNC_END(__get_user_nocheck_4)
128EXPORT_SYMBOL(__get_user_nocheck_4)
129
130SYM_FUNC_START(__get_user_nocheck_8)
131 ASM_STAC
132 ASM_BARRIER_NOSPEC
133#ifdef CONFIG_X86_64
1349: movq (%_ASM_AX),%rdx
135#else
1369: movl (%_ASM_AX),%edx
13710: movl 4(%_ASM_AX),%ecx
138#endif
139 xor %eax,%eax
140 ASM_CLAC
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100141 RET
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700142SYM_FUNC_END(__get_user_nocheck_8)
143EXPORT_SYMBOL(__get_user_nocheck_8)
144
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Nadav Amit5516c892023-05-25 11:42:44 -0700146SYM_CODE_START_LOCAL(__get_user_handle_exception)
Josh Poimboeuf82e844a2019-07-17 20:36:44 -0500147 ASM_CLAC
Kirill A. Shutemovb19b74b2023-03-12 14:25:56 +0300148.Lbad_get_user:
Glauber Costaef8c1a22008-06-24 11:21:53 -0300149 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -0300150 mov $(-EFAULT),%_ASM_AX
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100151 RET
Nadav Amit5516c892023-05-25 11:42:44 -0700152SYM_CODE_END(__get_user_handle_exception)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Ville Syrjälä96477b42012-12-12 13:34:03 +0200154#ifdef CONFIG_X86_32
Nadav Amit5516c892023-05-25 11:42:44 -0700155SYM_CODE_START_LOCAL(__get_user_8_handle_exception)
Josh Poimboeuf82e844a2019-07-17 20:36:44 -0500156 ASM_CLAC
Ville Syrjälä96477b42012-12-12 13:34:03 +0200157bad_get_user_8:
Ville Syrjälä96477b42012-12-12 13:34:03 +0200158 xor %edx,%edx
159 xor %ecx,%ecx
160 mov $(-EFAULT),%_ASM_AX
Peter Zijlstraf94909c2021-12-04 14:43:40 +0100161 RET
Nadav Amit5516c892023-05-25 11:42:44 -0700162SYM_CODE_END(__get_user_8_handle_exception)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200163#endif
164
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700165/* get_user */
Nadav Amit5516c892023-05-25 11:42:44 -0700166 _ASM_EXTABLE(1b, __get_user_handle_exception)
167 _ASM_EXTABLE(2b, __get_user_handle_exception)
168 _ASM_EXTABLE(3b, __get_user_handle_exception)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300169#ifdef CONFIG_X86_64
Nadav Amit5516c892023-05-25 11:42:44 -0700170 _ASM_EXTABLE(4b, __get_user_handle_exception)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200171#else
Nadav Amit5516c892023-05-25 11:42:44 -0700172 _ASM_EXTABLE(4b, __get_user_8_handle_exception)
173 _ASM_EXTABLE(5b, __get_user_8_handle_exception)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300174#endif
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700175
176/* __get_user */
Nadav Amit5516c892023-05-25 11:42:44 -0700177 _ASM_EXTABLE(6b, __get_user_handle_exception)
178 _ASM_EXTABLE(7b, __get_user_handle_exception)
179 _ASM_EXTABLE(8b, __get_user_handle_exception)
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700180#ifdef CONFIG_X86_64
Nadav Amit5516c892023-05-25 11:42:44 -0700181 _ASM_EXTABLE(9b, __get_user_handle_exception)
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700182#else
Nadav Amit5516c892023-05-25 11:42:44 -0700183 _ASM_EXTABLE(9b, __get_user_8_handle_exception)
184 _ASM_EXTABLE(10b, __get_user_8_handle_exception)
Linus Torvaldsea6f0432020-04-08 12:50:01 -0700185#endif