blob: b33b1fb1e6d46728ed707f640063306ca99c2ae2 [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>
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
Glauber Costa40faf462008-06-24 11:37:57 -0300431: movzb (%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030044 xor %eax,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020046 CFI_ENDPROC
47ENDPROC(__get_user_1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Jan Beulich8d379da2006-09-26 10:52:32 +020049ENTRY(__get_user_2)
50 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030051 add $1,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030052 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030053 GET_THREAD_INFO(%_ASM_DX)
54 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030055 jae bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -0300562: movzwl -1(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030057 xor %eax,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020059 CFI_ENDPROC
60ENDPROC(__get_user_2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Jan Beulich8d379da2006-09-26 10:52:32 +020062ENTRY(__get_user_4)
63 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030064 add $3,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030065 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030066 GET_THREAD_INFO(%_ASM_DX)
67 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030068 jae bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -0300693: mov -3(%_ASM_AX),%edx
Glauber Costaef8c1a22008-06-24 11:21:53 -030070 xor %eax,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020072 CFI_ENDPROC
73ENDPROC(__get_user_4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Glauber Costa6c2d4582008-06-24 12:05:11 -030075#ifdef CONFIG_X86_64
Jan Beulich8d379da2006-09-26 10:52:32 +020076ENTRY(__get_user_8)
77 CFI_STARTPROC
Glauber Costa40faf462008-06-24 11:37:57 -030078 add $7,%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030079 jc bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -030080 GET_THREAD_INFO(%_ASM_DX)
81 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
Glauber Costa92628752008-06-24 11:13:16 -030082 jae bad_get_user
Glauber Costa40faf462008-06-24 11:37:57 -0300834: movq -7(%_ASM_AX),%_ASM_DX
Glauber Costaef8c1a22008-06-24 11:21:53 -030084 xor %eax,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020086 CFI_ENDPROC
87ENDPROC(__get_user_8)
Glauber Costa6c2d4582008-06-24 12:05:11 -030088#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90bad_get_user:
Jan Beulich8d379da2006-09-26 10:52:32 +020091 CFI_STARTPROC
Glauber Costaef8c1a22008-06-24 11:21:53 -030092 xor %edx,%edx
Glauber Costa40faf462008-06-24 11:37:57 -030093 mov $(-EFAULT),%_ASM_AX
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 ret
Jan Beulich8d379da2006-09-26 10:52:32 +020095 CFI_ENDPROC
96END(bad_get_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
H. Peter Anvin1a27bc02012-04-20 12:19:51 -070098 _ASM_EXTABLE(1b,bad_get_user)
99 _ASM_EXTABLE(2b,bad_get_user)
100 _ASM_EXTABLE(3b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300101#ifdef CONFIG_X86_64
H. Peter Anvin1a27bc02012-04-20 12:19:51 -0700102 _ASM_EXTABLE(4b,bad_get_user)
Glauber Costa6c2d4582008-06-24 12:05:11 -0300103#endif