blob: 156b9c8046704d7a3119356e12977578f3e3792e [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 * The register is modified, but all changes are undone
19 * before returning because the C code doesn't know about it.
20 *
Glauber Costa6c2d4582008-06-24 12:05:11 -030021 * Outputs: %[r|e]ax is error code (0 or -EFAULT)
22 * %[r|e]dx contains zero-extended value
23 *
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
29#include <linux/linkage.h>
Jan Beulich8d379da2006-09-26 10:52:32 +020030#include <asm/dwarf2.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
38 .text
Jan Beulich8d379da2006-09-26 10:52:32 +020039ENTRY(__get_user_1)
40 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030041 GET_THREAD_INFO(%_ASM_DX)
42 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070044 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300451: movzb (%_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 +020049 CFI_ENDPROC
50ENDPROC(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Jan Beulich8d379da2006-09-26 10:52:32 +020052ENTRY(__get_user_2)
53 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030054 add $1,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030055 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030056 GET_THREAD_INFO(%_ASM_DX)
57 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030058 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070059 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300602: movzwl -1(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030061 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070062 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020064 CFI_ENDPROC
65ENDPROC(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Jan Beulich8d379da2006-09-26 10:52:32 +020067ENTRY(__get_user_4)
68 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030069 add $3,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030070 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030071 GET_THREAD_INFO(%_ASM_DX)
72 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030073 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070074 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300753: mov -3(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030076 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070077 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020079 CFI_ENDPROC
80ENDPROC(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Glauber Costa6c2d4582008-06-24 12:05:11 -030082#ifdef CONFIG_X86_64
Jan Beulich8d379da2006-09-26 10:52:32 +020083ENTRY(__get_user_8)
84 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030085 add $7,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030086 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030087 GET_THREAD_INFO(%_ASM_DX)
88 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030089 jae bad_get_user
H. Peter Anvin63bcff22012-09-21 12:43:12 -070090 ASM_STAC
Glauber Costa40faf462008-06-24 11:37:57 -0300914: movq -7(%_ASM_AX),%_ASM_DX
Glauber Costaef8c1a22008-06-24 11:21:53 -030092 xor %eax,%eax
H. Peter Anvin63bcff22012-09-21 12:43:12 -070093 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020095 CFI_ENDPROC
96ENDPROC(__get_user_8)
Glauber Costa6c2d4582008-06-24 12:05:11 -030097#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99bad_get_user:
Jan Beulich8d379da2006-09-26 10:52:32 +0200100 CFI_STARTPROC
Glauber Costaef8c1a22008-06-24 11:21:53 -0300101 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -0300102 mov $(-EFAULT),%_ASM_AX
H. Peter Anvin63bcff22012-09-21 12:43:12 -0700103 ASM_CLAC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 ret
Jan Beulich8d379da2006-09-26 10:52:32 +0200105 CFI_ENDPROC
106END(bad_get_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700108 _ASM_EXTABLE(1b,bad_get_user)
109 _ASM_EXTABLE(2b,bad_get_user)
110 _ASM_EXTABLE(3b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300111#ifdef CONFIG_X86_64
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700112 _ASM_EXTABLE(4b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300113#endif