blob: b12b214713a603c851615b984d625a3113d497de [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * __get_user functions.
3 *
4 * (C) Copyright 1998 Linus Torvalds
5 * (C) Copyright 2005 Andi Kleen
Glauber Costa6c2d4582008-06-24 12:05:11 -03006 * (C) Copyright 2008 Glauber Costa
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 *
8 * These functions have a non-standard call interface
9 * to make them more efficient, especially as they
10 * return an error value in addition to the "real"
11 * return value.
12 */
13
14/*
15 * __get_user_X
16 *
Glauber Costa6c2d4582008-06-24 12:05:11 -030017 * Inputs: %[r|e]ax contains the address.
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 *
Glauber Costa6c2d4582008-06-24 12:05:11 -030019 * Outputs: %[r|e]ax is error code (0 or -EFAULT)
20 * %[r|e]dx contains zero-extended value
Ville Syrjälä96477b42012-12-12 13:34:03 +020021 * %ecx contains the high half for 32-bit __get_user_8
Glauber Costa6c2d4582008-06-24 12:05:11 -030022 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 *
24 * These functions should not modify any other registers,
25 * as they get called from within inline assembly.
26 */
27
28#include <linux/linkage.h>
Jeremy Fitzhardinge0341c142009-02-13 11:14:01 -080029#include <asm/page_types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/errno.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020031#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <asm/thread_info.h>
Glauber Costa40faf462008-06-24 11:37:57 -030033#include <asm/asm.h>
H. Peter Anvin63bcff22012-09-21 12:43:12 -070034#include <asm/smap.h>
Al Viro784d5692016-01-11 11:04:34 -050035#include <asm/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37 .text
Jan Beulich8d379da2006-09-26 10:52:32 +020038ENTRY(__get_user_1)
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070039 mov PER_CPU_VAR(current_task), %_ASM_DX
40 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 jae bad_get_user
Dan Williams398a3932018-01-29 17:02:54 -080042 sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
43 and %_ASM_DX, %_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -070044 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800451: movzbl (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030046 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070047 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020049ENDPROC(__get_user_1)
Al Viro784d5692016-01-11 11:04:34 -050050EXPORT_SYMBOL(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Jan Beulich8d379da2006-09-26 10:52:32 +020052ENTRY(__get_user_2)
Glauber Costa40faf462008-06-24 11:37:57 -030053 add $1,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030054 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070055 mov PER_CPU_VAR(current_task), %_ASM_DX
56 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030057 jae bad_get_user
Dan Williams398a3932018-01-29 17:02:54 -080058 sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
59 and %_ASM_DX, %_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -070060 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300612: movzwl -1(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030062 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070063 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020065ENDPROC(__get_user_2)
Al Viro784d5692016-01-11 11:04:34 -050066EXPORT_SYMBOL(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Jan Beulich8d379da2006-09-26 10:52:32 +020068ENTRY(__get_user_4)
Glauber Costa40faf462008-06-24 11:37:57 -030069 add $3,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030070 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070071 mov PER_CPU_VAR(current_task), %_ASM_DX
72 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030073 jae bad_get_user
Dan Williams398a3932018-01-29 17:02:54 -080074 sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
75 and %_ASM_DX, %_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -070076 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800773: movl -3(%_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
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020081ENDPROC(__get_user_4)
Al Viro784d5692016-01-11 11:04:34 -050082EXPORT_SYMBOL(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Jan Beulich8d379da2006-09-26 10:52:32 +020084ENTRY(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +020085#ifdef CONFIG_X86_64
Glauber Costa40faf462008-06-24 11:37:57 -030086 add $7,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030087 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070088 mov PER_CPU_VAR(current_task), %_ASM_DX
89 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +020090 jae bad_get_user
Dan Williams398a3932018-01-29 17:02:54 -080091 sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
92 and %_ASM_DX, %_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -070093 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800944: movq -7(%_ASM_AX),%rdx
Glauber Costaef8c1a22008-06-24 11:21:53 -030095 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070096 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 ret
Ville Syrjälä96477b42012-12-12 13:34:03 +020098#else
99 add $7,%_ASM_AX
100 jc bad_get_user_8
Andy Lutomirski13d4ea02016-07-14 13:22:57 -0700101 mov PER_CPU_VAR(current_task), %_ASM_DX
102 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +0200103 jae bad_get_user_8
Dan Williams398a3932018-01-29 17:02:54 -0800104 sbb %_ASM_DX, %_ASM_DX /* array_index_mask_nospec() */
105 and %_ASM_DX, %_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +0200106 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -08001074: movl -7(%_ASM_AX),%edx
1085: movl -3(%_ASM_AX),%ecx
Ville Syrjälä96477b42012-12-12 13:34:03 +0200109 xor %eax,%eax
110 ASM_CLAC
111 ret
112#endif
Jan Beulich8d379da2006-09-26 10:52:32 +0200113ENDPROC(__get_user_8)
Al Viro784d5692016-01-11 11:04:34 -0500114EXPORT_SYMBOL(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117bad_get_user:
Glauber Costaef8c1a22008-06-24 11:21:53 -0300118 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -0300119 mov $(-EFAULT),%_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -0700120 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 ret
Jan Beulich8d379da2006-09-26 10:52:32 +0200122END(bad_get_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Ville Syrjälä96477b42012-12-12 13:34:03 +0200124#ifdef CONFIG_X86_32
125bad_get_user_8:
Ville Syrjälä96477b42012-12-12 13:34:03 +0200126 xor %edx,%edx
127 xor %ecx,%ecx
128 mov $(-EFAULT),%_ASM_AX
129 ASM_CLAC
130 ret
Ville Syrjälä96477b42012-12-12 13:34:03 +0200131END(bad_get_user_8)
132#endif
133
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700134 _ASM_EXTABLE(1b,bad_get_user)
135 _ASM_EXTABLE(2b,bad_get_user)
136 _ASM_EXTABLE(3b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300137#ifdef CONFIG_X86_64
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700138 _ASM_EXTABLE(4b,bad_get_user)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200139#else
140 _ASM_EXTABLE(4b,bad_get_user_8)
141 _ASM_EXTABLE(5b,bad_get_user_8)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300142#endif