blob: 37b62d4121481df990741fac20ee48c2e68492e7 [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
H. Peter Anvin63bcff22012-09-21 12:43:12 -070042 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800431: movzbl (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030044 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070045 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020047ENDPROC(__get_user_1)
Al Viro784d5692016-01-11 11:04:34 -050048EXPORT_SYMBOL(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Jan Beulich8d379da2006-09-26 10:52:32 +020050ENTRY(__get_user_2)
Glauber Costa40faf462008-06-24 11:37:57 -030051 add $1,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030052 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070053 mov PER_CPU_VAR(current_task), %_ASM_DX
54 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030055 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070056 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300572: movzwl -1(%_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
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020061ENDPROC(__get_user_2)
Al Viro784d5692016-01-11 11:04:34 -050062EXPORT_SYMBOL(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Jan Beulich8d379da2006-09-26 10:52:32 +020064ENTRY(__get_user_4)
Glauber Costa40faf462008-06-24 11:37:57 -030065 add $3,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030066 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070067 mov PER_CPU_VAR(current_task), %_ASM_DX
68 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030069 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070070 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800713: movl -3(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030072 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070073 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020075ENDPROC(__get_user_4)
Al Viro784d5692016-01-11 11:04:34 -050076EXPORT_SYMBOL(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Jan Beulich8d379da2006-09-26 10:52:32 +020078ENTRY(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +020079#ifdef CONFIG_X86_64
Glauber Costa40faf462008-06-24 11:37:57 -030080 add $7,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030081 jc bad_get_user
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070082 mov PER_CPU_VAR(current_task), %_ASM_DX
83 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +020084 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070085 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800864: movq -7(%_ASM_AX),%rdx
Glauber Costaef8c1a22008-06-24 11:21:53 -030087 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070088 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 ret
Ville Syrjälä96477b42012-12-12 13:34:03 +020090#else
91 add $7,%_ASM_AX
92 jc bad_get_user_8
Andy Lutomirski13d4ea02016-07-14 13:22:57 -070093 mov PER_CPU_VAR(current_task), %_ASM_DX
94 cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +020095 jae bad_get_user_8
96 ASM_STAC
H. Peter Anvin16640162013-02-11 23:14:48 -0800974: movl -7(%_ASM_AX),%edx
985: movl -3(%_ASM_AX),%ecx
Ville Syrjälä96477b42012-12-12 13:34:03 +020099 xor %eax,%eax
100 ASM_CLAC
101 ret
102#endif
Jan Beulich8d379da2006-09-26 10:52:32 +0200103ENDPROC(__get_user_8)
Al Viro784d5692016-01-11 11:04:34 -0500104EXPORT_SYMBOL(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107bad_get_user:
Glauber Costaef8c1a22008-06-24 11:21:53 -0300108 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -0300109 mov $(-EFAULT),%_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -0700110 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 ret
Jan Beulich8d379da2006-09-26 10:52:32 +0200112END(bad_get_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Ville Syrjälä96477b42012-12-12 13:34:03 +0200114#ifdef CONFIG_X86_32
115bad_get_user_8:
Ville Syrjälä96477b42012-12-12 13:34:03 +0200116 xor %edx,%edx
117 xor %ecx,%ecx
118 mov $(-EFAULT),%_ASM_AX
119 ASM_CLAC
120 ret
Ville Syrjälä96477b42012-12-12 13:34:03 +0200121END(bad_get_user_8)
122#endif
123
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700124 _ASM_EXTABLE(1b,bad_get_user)
125 _ASM_EXTABLE(2b,bad_get_user)
126 _ASM_EXTABLE(3b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300127#ifdef CONFIG_X86_64
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700128 _ASM_EXTABLE(4b,bad_get_user)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200129#else
130 _ASM_EXTABLE(4b,bad_get_user_8)
131 _ASM_EXTABLE(5b,bad_get_user_8)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300132#endif