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> |
1da177e4 LT |
31 | #include <asm/page.h> |
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> |
1da177e4 LT |
36 | |
37 | .text | |
8d379dad JB |
38 | ENTRY(__get_user_1) |
39 | CFI_STARTPROC | |
40faf463 GC |
40 | GET_THREAD_INFO(%_ASM_DX) |
41 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
1da177e4 | 42 | jae bad_get_user |
40faf463 | 43 | 1: movzb (%_ASM_AX),%edx |
ef8c1a2d | 44 | xor %eax,%eax |
1da177e4 | 45 | ret |
8d379dad JB |
46 | CFI_ENDPROC |
47 | ENDPROC(__get_user_1) | |
1da177e4 | 48 | |
8d379dad JB |
49 | ENTRY(__get_user_2) |
50 | CFI_STARTPROC | |
40faf463 | 51 | add $1,%_ASM_AX |
92628753 | 52 | jc bad_get_user |
40faf463 GC |
53 | GET_THREAD_INFO(%_ASM_DX) |
54 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 55 | jae bad_get_user |
40faf463 | 56 | 2: movzwl -1(%_ASM_AX),%edx |
ef8c1a2d | 57 | xor %eax,%eax |
1da177e4 | 58 | ret |
8d379dad JB |
59 | CFI_ENDPROC |
60 | ENDPROC(__get_user_2) | |
1da177e4 | 61 | |
8d379dad JB |
62 | ENTRY(__get_user_4) |
63 | CFI_STARTPROC | |
40faf463 | 64 | add $3,%_ASM_AX |
92628753 | 65 | jc bad_get_user |
40faf463 GC |
66 | GET_THREAD_INFO(%_ASM_DX) |
67 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 68 | jae bad_get_user |
40faf463 | 69 | 3: mov -3(%_ASM_AX),%edx |
ef8c1a2d | 70 | xor %eax,%eax |
1da177e4 | 71 | ret |
8d379dad JB |
72 | CFI_ENDPROC |
73 | ENDPROC(__get_user_4) | |
1da177e4 | 74 | |
6c2d4586 | 75 | #ifdef CONFIG_X86_64 |
8d379dad JB |
76 | ENTRY(__get_user_8) |
77 | CFI_STARTPROC | |
40faf463 | 78 | add $7,%_ASM_AX |
92628753 | 79 | jc bad_get_user |
40faf463 GC |
80 | GET_THREAD_INFO(%_ASM_DX) |
81 | cmp TI_addr_limit(%_ASM_DX),%_ASM_AX | |
92628753 | 82 | jae bad_get_user |
40faf463 | 83 | 4: movq -7(%_ASM_AX),%_ASM_DX |
ef8c1a2d | 84 | xor %eax,%eax |
1da177e4 | 85 | ret |
8d379dad JB |
86 | CFI_ENDPROC |
87 | ENDPROC(__get_user_8) | |
6c2d4586 | 88 | #endif |
1da177e4 LT |
89 | |
90 | bad_get_user: | |
8d379dad | 91 | CFI_STARTPROC |
ef8c1a2d | 92 | xor %edx,%edx |
40faf463 | 93 | mov $(-EFAULT),%_ASM_AX |
1da177e4 | 94 | ret |
8d379dad JB |
95 | CFI_ENDPROC |
96 | END(bad_get_user) | |
1da177e4 LT |
97 | |
98 | .section __ex_table,"a" | |
87e2f1e7 GC |
99 | _ASM_PTR 1b,bad_get_user |
100 | _ASM_PTR 2b,bad_get_user | |
101 | _ASM_PTR 3b,bad_get_user | |
6c2d4586 | 102 | #ifdef CONFIG_X86_64 |
87e2f1e7 | 103 | _ASM_PTR 4b,bad_get_user |
6c2d4586 | 104 | #endif |