diff options
Diffstat (limited to 'arch/x86/lib/getuser_64.S')
-rw-r--r-- | arch/x86/lib/getuser_64.S | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/arch/x86/lib/getuser_64.S b/arch/x86/lib/getuser_64.S new file mode 100644 index 000000000000..5448876261f8 --- /dev/null +++ b/arch/x86/lib/getuser_64.S | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * __get_user functions. | ||
3 | * | ||
4 | * (C) Copyright 1998 Linus Torvalds | ||
5 | * (C) Copyright 2005 Andi Kleen | ||
6 | * | ||
7 | * These functions have a non-standard call interface | ||
8 | * to make them more efficient, especially as they | ||
9 | * return an error value in addition to the "real" | ||
10 | * return value. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * __get_user_X | ||
15 | * | ||
16 | * Inputs: %rcx contains the address. | ||
17 | * The register is modified, but all changes are undone | ||
18 | * before returning because the C code doesn't know about it. | ||
19 | * | ||
20 | * Outputs: %rax is error code (0 or -EFAULT) | ||
21 | * %rdx contains zero-extended value | ||
22 | * | ||
23 | * %r8 is destroyed. | ||
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> | ||
30 | #include <asm/dwarf2.h> | ||
31 | #include <asm/page.h> | ||
32 | #include <asm/errno.h> | ||
33 | #include <asm/asm-offsets.h> | ||
34 | #include <asm/thread_info.h> | ||
35 | |||
36 | .text | ||
37 | ENTRY(__get_user_1) | ||
38 | CFI_STARTPROC | ||
39 | GET_THREAD_INFO(%r8) | ||
40 | cmpq threadinfo_addr_limit(%r8),%rcx | ||
41 | jae bad_get_user | ||
42 | 1: movzb (%rcx),%edx | ||
43 | xorl %eax,%eax | ||
44 | ret | ||
45 | CFI_ENDPROC | ||
46 | ENDPROC(__get_user_1) | ||
47 | |||
48 | ENTRY(__get_user_2) | ||
49 | CFI_STARTPROC | ||
50 | GET_THREAD_INFO(%r8) | ||
51 | addq $1,%rcx | ||
52 | jc 20f | ||
53 | cmpq threadinfo_addr_limit(%r8),%rcx | ||
54 | jae 20f | ||
55 | decq %rcx | ||
56 | 2: movzwl (%rcx),%edx | ||
57 | xorl %eax,%eax | ||
58 | ret | ||
59 | 20: decq %rcx | ||
60 | jmp bad_get_user | ||
61 | CFI_ENDPROC | ||
62 | ENDPROC(__get_user_2) | ||
63 | |||
64 | ENTRY(__get_user_4) | ||
65 | CFI_STARTPROC | ||
66 | GET_THREAD_INFO(%r8) | ||
67 | addq $3,%rcx | ||
68 | jc 30f | ||
69 | cmpq threadinfo_addr_limit(%r8),%rcx | ||
70 | jae 30f | ||
71 | subq $3,%rcx | ||
72 | 3: movl (%rcx),%edx | ||
73 | xorl %eax,%eax | ||
74 | ret | ||
75 | 30: subq $3,%rcx | ||
76 | jmp bad_get_user | ||
77 | CFI_ENDPROC | ||
78 | ENDPROC(__get_user_4) | ||
79 | |||
80 | ENTRY(__get_user_8) | ||
81 | CFI_STARTPROC | ||
82 | GET_THREAD_INFO(%r8) | ||
83 | addq $7,%rcx | ||
84 | jc 40f | ||
85 | cmpq threadinfo_addr_limit(%r8),%rcx | ||
86 | jae 40f | ||
87 | subq $7,%rcx | ||
88 | 4: movq (%rcx),%rdx | ||
89 | xorl %eax,%eax | ||
90 | ret | ||
91 | 40: subq $7,%rcx | ||
92 | jmp bad_get_user | ||
93 | CFI_ENDPROC | ||
94 | ENDPROC(__get_user_8) | ||
95 | |||
96 | bad_get_user: | ||
97 | CFI_STARTPROC | ||
98 | xorl %edx,%edx | ||
99 | movq $(-EFAULT),%rax | ||
100 | ret | ||
101 | CFI_ENDPROC | ||
102 | END(bad_get_user) | ||
103 | |||
104 | .section __ex_table,"a" | ||
105 | .quad 1b,bad_get_user | ||
106 | .quad 2b,bad_get_user | ||
107 | .quad 3b,bad_get_user | ||
108 | .quad 4b,bad_get_user | ||
109 | .previous | ||