blob: d3bf9f99ca770fb779a547713ce98a3304a1d34a [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>
Jan Beulich8d379da2006-09-26 10:52:32 +020029#include <asm/dwarf2.h>
Jeremy Fitzhardinge0341c142009-02-13 11:14:01 -080030#include <asm/page_types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <asm/errno.h>
Sam Ravnborge2d5df92005-09-09 21:28:48 +020032#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <asm/thread_info.h>
Glauber Costa40faf462008-06-24 11:37:57 -030034#include <asm/asm.h>
H. Peter Anvin63bcff22012-09-21 12:43:12 -070035#include <asm/smap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37 .text
Jan Beulich8d379da2006-09-26 10:52:32 +020038ENTRY(__get_user_1)
39 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030040 GET_THREAD_INFO(%_ASM_DX)
41 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070043 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300441: movzb (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030045 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070046 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020048 CFI_ENDPROC
49ENDPROC(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Jan Beulich8d379da2006-09-26 10:52:32 +020051ENTRY(__get_user_2)
52 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030053 add $1,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030054 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030055 GET_THREAD_INFO(%_ASM_DX)
56 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030057 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070058 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300592: movzwl -1(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030060 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070061 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020063 CFI_ENDPROC
64ENDPROC(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Jan Beulich8d379da2006-09-26 10:52:32 +020066ENTRY(__get_user_4)
67 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030068 add $3,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030069 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030070 GET_THREAD_INFO(%_ASM_DX)
71 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030072 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070073 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300743: mov -3(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030075 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070076 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020078 CFI_ENDPROC
79ENDPROC(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Jan Beulich8d379da2006-09-26 10:52:32 +020081ENTRY(__get_user_8)
82 CFI_STARTPROC
Ville Syrjälä96477b42012-12-12 13:34:03 +020083#ifdef CONFIG_X86_64
Glauber Costa40faf462008-06-24 11:37:57 -030084 add $7,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030085 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030086 GET_THREAD_INFO(%_ASM_DX)
87 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Ville Syrjälä96477b42012-12-12 13:34:03 +020088 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070089 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300904: movq -7(%_ASM_AX),%_ASM_DX
Glauber Costaef8c1a22008-06-24 11:21:53 -030091 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070092 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 ret
Ville Syrjälä96477b42012-12-12 13:34:03 +020094#else
95 add $7,%_ASM_AX
96 jc bad_get_user_8
97 GET_THREAD_INFO(%_ASM_DX)
98 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
99 jae bad_get_user_8
100 ASM_STAC
1014: mov -7(%_ASM_AX),%edx
1025: mov -3(%_ASM_AX),%ecx
103 xor %eax,%eax
104 ASM_CLAC
105 ret
106#endif
Jan Beulich8d379da2006-09-26 10:52:32 +0200107 CFI_ENDPROC
108ENDPROC(__get_user_8)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111bad_get_user:
Jan Beulich8d379da2006-09-26 10:52:32 +0200112 CFI_STARTPROC
Glauber Costaef8c1a22008-06-24 11:21:53 -0300113 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -0300114 mov $(-EFAULT),%_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -0700115 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 ret
Jan Beulich8d379da2006-09-26 10:52:32 +0200117 CFI_ENDPROC
118END(bad_get_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Ville Syrjälä96477b42012-12-12 13:34:03 +0200120#ifdef CONFIG_X86_32
121bad_get_user_8:
122 CFI_STARTPROC
123 xor %edx,%edx
124 xor %ecx,%ecx
125 mov $(-EFAULT),%_ASM_AX
126 ASM_CLAC
127 ret
128 CFI_ENDPROC
129END(bad_get_user_8)
130#endif
131
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700132 _ASM_EXTABLE(1b,bad_get_user)
133 _ASM_EXTABLE(2b,bad_get_user)
134 _ASM_EXTABLE(3b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300135#ifdef CONFIG_X86_64
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700136 _ASM_EXTABLE(4b,bad_get_user)
Ville Syrjälä96477b42012-12-12 13:34:03 +0200137#else
138 _ASM_EXTABLE(4b,bad_get_user_8)
139 _ASM_EXTABLE(5b,bad_get_user_8)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300140#endif