arch/tile: finish enabling support for TILE-Gx 64-bit chip
[linux-2.6.git] / arch / tile / lib / usercopy_64.S
1 /*
2  * Copyright 2011 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  */
14
15 #include <linux/linkage.h>
16 #include <asm/errno.h>
17 #include <asm/cache.h>
18 #include <arch/chip.h>
19
20 /* Access user memory, but use MMU to avoid propagating kernel exceptions. */
21
22         .pushsection .fixup,"ax"
23
24 get_user_fault:
25         { movei r1, -EFAULT; move r0, zero }
26         jrp lr
27         ENDPROC(get_user_fault)
28
29 put_user_fault:
30         { movei r0, -EFAULT; jrp lr }
31         ENDPROC(put_user_fault)
32
33         .popsection
34
35 /*
36  * __get_user_N functions take a pointer in r0, and return 0 in r1
37  * on success, with the value in r0; or else -EFAULT in r1.
38  */
39 #define __get_user_N(bytes, LOAD) \
40         STD_ENTRY(__get_user_##bytes); \
41 1:      { LOAD r0, r0; move r1, zero }; \
42         jrp lr; \
43         STD_ENDPROC(__get_user_##bytes); \
44         .pushsection __ex_table,"a"; \
45         .quad 1b, get_user_fault; \
46         .popsection
47
48 __get_user_N(1, ld1u)
49 __get_user_N(2, ld2u)
50 __get_user_N(4, ld4u)
51 __get_user_N(8, ld)
52
53 /*
54  * __put_user_N functions take a value in r0 and a pointer in r1,
55  * and return 0 in r0 on success or -EFAULT on failure.
56  */
57 #define __put_user_N(bytes, STORE) \
58         STD_ENTRY(__put_user_##bytes); \
59 1:      { STORE r1, r0; move r0, zero }; \
60         jrp lr; \
61         STD_ENDPROC(__put_user_##bytes); \
62         .pushsection __ex_table,"a"; \
63         .quad 1b, put_user_fault; \
64         .popsection
65
66 __put_user_N(1, st1)
67 __put_user_N(2, st2)
68 __put_user_N(4, st4)
69 __put_user_N(8, st)
70
71 /*
72  * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
73  * It returns the length, including the terminating NUL, or zero on exception.
74  * If length is greater than the bound, returns one plus the bound.
75  */
76 STD_ENTRY(strnlen_user_asm)
77         { beqz r1, 2f; addi r3, r0, -1 }  /* bias down to include NUL */
78 1:      { ld1u r4, r0; addi r1, r1, -1 }
79         beqz r4, 2f
80         { bnezt r1, 1b; addi r0, r0, 1 }
81 2:      { sub r0, r0, r3; jrp lr }
82         STD_ENDPROC(strnlen_user_asm)
83         .pushsection .fixup,"ax"
84 strnlen_user_fault:
85         { move r0, zero; jrp lr }
86         ENDPROC(strnlen_user_fault)
87         .section __ex_table,"a"
88         .quad 1b, strnlen_user_fault
89         .popsection
90
91 /*
92  * strncpy_from_user_asm takes the kernel target pointer in r0,
93  * the userspace source pointer in r1, and the length bound (including
94  * the trailing NUL) in r2.  On success, it returns the string length
95  * (not including the trailing NUL), or -EFAULT on failure.
96  */
97 STD_ENTRY(strncpy_from_user_asm)
98         { beqz r2, 2f; move r3, r0 }
99 1:      { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
100         { st1 r0, r4; addi r0, r0, 1 }
101         beqz r2, 2f
102         bnezt r4, 1b
103         addi r0, r0, -1   /* don't count the trailing NUL */
104 2:      { sub r0, r0, r3; jrp lr }
105         STD_ENDPROC(strncpy_from_user_asm)
106         .pushsection .fixup,"ax"
107 strncpy_from_user_fault:
108         { movei r0, -EFAULT; jrp lr }
109         ENDPROC(strncpy_from_user_fault)
110         .section __ex_table,"a"
111         .quad 1b, strncpy_from_user_fault
112         .popsection
113
114 /*
115  * clear_user_asm takes the user target address in r0 and the
116  * number of bytes to zero in r1.
117  * It returns the number of uncopiable bytes (hopefully zero) in r0.
118  * Note that we don't use a separate .fixup section here since we fall
119  * through into the "fixup" code as the last straight-line bundle anyway.
120  */
121 STD_ENTRY(clear_user_asm)
122         { beqz r1, 2f; or r2, r0, r1 }
123         andi r2, r2, 7
124         beqzt r2, .Lclear_aligned_user_asm
125 1:      { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
126         bnezt r1, 1b
127 2:      { move r0, r1; jrp lr }
128         .pushsection __ex_table,"a"
129         .quad 1b, 2b
130         .popsection
131
132 .Lclear_aligned_user_asm:
133 1:      { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 }
134         bnezt r1, 1b
135 2:      { move r0, r1; jrp lr }
136         STD_ENDPROC(clear_user_asm)
137         .pushsection __ex_table,"a"
138         .quad 1b, 2b
139         .popsection
140
141 /*
142  * flush_user_asm takes the user target address in r0 and the
143  * number of bytes to flush in r1.
144  * It returns the number of unflushable bytes (hopefully zero) in r0.
145  */
146 STD_ENTRY(flush_user_asm)
147         beqz r1, 2f
148         { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
149         { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
150         { and r0, r0, r2; and r1, r1, r2 }
151         { sub r1, r1, r0 }
152 1:      { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
153         { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b }
154 2:      { move r0, r1; jrp lr }
155         STD_ENDPROC(flush_user_asm)
156         .pushsection __ex_table,"a"
157         .quad 1b, 2b
158         .popsection
159
160 /*
161  * inv_user_asm takes the user target address in r0 and the
162  * number of bytes to invalidate in r1.
163  * It returns the number of not inv'able bytes (hopefully zero) in r0.
164  */
165 STD_ENTRY(inv_user_asm)
166         beqz r1, 2f
167         { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
168         { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
169         { and r0, r0, r2; and r1, r1, r2 }
170         { sub r1, r1, r0 }
171 1:      { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
172         { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b }
173 2:      { move r0, r1; jrp lr }
174         STD_ENDPROC(inv_user_asm)
175         .pushsection __ex_table,"a"
176         .quad 1b, 2b
177         .popsection
178
179 /*
180  * finv_user_asm takes the user target address in r0 and the
181  * number of bytes to flush-invalidate in r1.
182  * It returns the number of not finv'able bytes (hopefully zero) in r0.
183  */
184 STD_ENTRY(finv_user_asm)
185         beqz r1, 2f
186         { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
187         { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
188         { and r0, r0, r2; and r1, r1, r2 }
189         { sub r1, r1, r0 }
190 1:      { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
191         { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b }
192 2:      { move r0, r1; jrp lr }
193         STD_ENDPROC(finv_user_asm)
194         .pushsection __ex_table,"a"
195         .quad 1b, 2b
196         .popsection