Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * __get_user functions. | |
3 | * | |
4 | * (C) Copyright 1998 Linus Torvalds | |
5 | * (C) Copyright 2005 Andi Kleen | |
6c2d4586 | 6 | * (C) Copyright 2008 Glauber Costa |
1da177e4 LT |
7 | * |
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 | * | |
6c2d4586 | 17 | * Inputs: %[r|e]ax contains the address. |
1da177e4 LT |
18 | * The register is modified, but all changes are undone |
19 | * before returning because the C code doesn't know about it. | |
20 | * | |
6c2d4586 GC |
21 | * Outputs: %[r|e]ax is error code (0 or -EFAULT) |
22 | * %[r|e]dx contains zero-extended value | |
23 | * | |
1da177e4 LT |
24 | * |
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> | |
8d379dad | 30 | #include <asm/dwarf2.h> |
0341c14d | 31 | #include <asm/page_types.h> |
1da177e4 | 32 | #include <asm/errno.h> |
e2d5df93 | 33 | #include <asm/asm-offsets.h> |
1da177e4 | 34 | #include <asm/thread_info.h> |
40faf463 | 35 | #include <asm/asm.h> |
63bcff2a | 36 | #include <asm/smap.h> |
1da177e4 LT |
37 | |
38 | .text | |
8d379dad JB |
39 | ENTRY(__get_user_1) |
40 | CFI_STARTPROC | |
40faf463 GC |
41 | GET_THREAD_INFO(%_ASM_DX) |
42 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
1da177e4 | 43 | jae bad_get_user |
63bcff2a | 44 | ASM_STAC |
40faf463 | 45 | 1: movzb (%_ASM_AX),%edx |
ef8c1a2d | 46 | xor %eax,%eax |
63bcff2a | 47 | ASM_CLAC |
1da177e4 | 48 | ret |
8d379dad JB |
49 | CFI_ENDPROC |
50 | ENDPROC(__get_user_1) | |
1da177e4 | 51 | |
8d379dad JB |
52 | ENTRY(__get_user_2) |
53 | CFI_STARTPROC | |
40faf463 | 54 | add $1,%_ASM_AX |
92628753 | 55 | jc bad_get_user |
40faf463 GC |
56 | GET_THREAD_INFO(%_ASM_DX) |
57 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 58 | jae bad_get_user |
63bcff2a | 59 | ASM_STAC |
40faf463 | 60 | 2: movzwl -1(%_ASM_AX),%edx |
ef8c1a2d | 61 | xor %eax,%eax |
63bcff2a | 62 | ASM_CLAC |
1da177e4 | 63 | ret |
8d379dad JB |
64 | CFI_ENDPROC |
65 | ENDPROC(__get_user_2) | |
1da177e4 | 66 | |
8d379dad JB |
67 | ENTRY(__get_user_4) |
68 | CFI_STARTPROC | |
40faf463 | 69 | add $3,%_ASM_AX |
92628753 | 70 | jc bad_get_user |
40faf463 GC |
71 | GET_THREAD_INFO(%_ASM_DX) |
72 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 73 | jae bad_get_user |
63bcff2a | 74 | ASM_STAC |
40faf463 | 75 | 3: mov -3(%_ASM_AX),%edx |
ef8c1a2d | 76 | xor %eax,%eax |
63bcff2a | 77 | ASM_CLAC |
1da177e4 | 78 | ret |
8d379dad JB |
79 | CFI_ENDPROC |
80 | ENDPROC(__get_user_4) | |
1da177e4 | 81 | |
6c2d4586 | 82 | #ifdef CONFIG_X86_64 |
8d379dad JB |
83 | ENTRY(__get_user_8) |
84 | CFI_STARTPROC | |
40faf463 | 85 | add $7,%_ASM_AX |
92628753 | 86 | jc bad_get_user |
40faf463 GC |
87 | GET_THREAD_INFO(%_ASM_DX) |
88 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 89 | jae bad_get_user |
63bcff2a | 90 | ASM_STAC |
40faf463 | 91 | 4: movq -7(%_ASM_AX),%_ASM_DX |
ef8c1a2d | 92 | xor %eax,%eax |
63bcff2a | 93 | ASM_CLAC |
1da177e4 | 94 | ret |
8d379dad JB |
95 | CFI_ENDPROC |
96 | ENDPROC(__get_user_8) | |
6c2d4586 | 97 | #endif |
1da177e4 LT |
98 | |
99 | bad_get_user: | |
8d379dad | 100 | CFI_STARTPROC |
ef8c1a2d | 101 | xor %edx,%edx |
40faf463 | 102 | mov $(-EFAULT),%_ASM_AX |
63bcff2a | 103 | ASM_CLAC |
1da177e4 | 104 | ret |
8d379dad JB |
105 | CFI_ENDPROC |
106 | END(bad_get_user) | |
1da177e4 | 107 | |
1a27bc0d PA |
108 | _ASM_EXTABLE(1b,bad_get_user) |
109 | _ASM_EXTABLE(2b,bad_get_user) | |
110 | _ASM_EXTABLE(3b,bad_get_user) | |
6c2d4586 | 111 | #ifdef CONFIG_X86_64 |
1a27bc0d | 112 | _ASM_EXTABLE(4b,bad_get_user) |
6c2d4586 | 113 | #endif |