Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/tile/lib/usercopy_32.S
10817 views
1
/*
2
* Copyright 2010 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
{ move r0, zero; move r1, zero }
26
{ movei r2, -EFAULT; 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 r2
37
* on success, with the value in r0; or else -EFAULT in r2.
38
*/
39
#define __get_user_N(bytes, LOAD) \
40
STD_ENTRY(__get_user_##bytes); \
41
1: { LOAD r0, r0; move r1, zero; move r2, zero }; \
42
jrp lr; \
43
STD_ENDPROC(__get_user_##bytes); \
44
.pushsection __ex_table,"a"; \
45
.word 1b, get_user_fault; \
46
.popsection
47
48
__get_user_N(1, lb_u)
49
__get_user_N(2, lh_u)
50
__get_user_N(4, lw)
51
52
/*
53
* __get_user_8 takes a pointer in r0, and returns 0 in r2
54
* on success, with the value in r0/r1; or else -EFAULT in r2.
55
*/
56
STD_ENTRY(__get_user_8);
57
1: { lw r0, r0; addi r1, r0, 4 };
58
2: { lw r1, r1; move r2, zero };
59
jrp lr;
60
STD_ENDPROC(__get_user_8);
61
.pushsection __ex_table,"a";
62
.word 1b, get_user_fault;
63
.word 2b, get_user_fault;
64
.popsection
65
66
/*
67
* __put_user_N functions take a value in r0 and a pointer in r1,
68
* and return 0 in r0 on success or -EFAULT on failure.
69
*/
70
#define __put_user_N(bytes, STORE) \
71
STD_ENTRY(__put_user_##bytes); \
72
1: { STORE r1, r0; move r0, zero }; \
73
jrp lr; \
74
STD_ENDPROC(__put_user_##bytes); \
75
.pushsection __ex_table,"a"; \
76
.word 1b, put_user_fault; \
77
.popsection
78
79
__put_user_N(1, sb)
80
__put_user_N(2, sh)
81
__put_user_N(4, sw)
82
83
/*
84
* __put_user_8 takes a value in r0/r1 and a pointer in r2,
85
* and returns 0 in r0 on success or -EFAULT on failure.
86
*/
87
STD_ENTRY(__put_user_8)
88
1: { sw r2, r0; addi r2, r2, 4 }
89
2: { sw r2, r1; move r0, zero }
90
jrp lr
91
STD_ENDPROC(__put_user_8)
92
.pushsection __ex_table,"a"
93
.word 1b, put_user_fault
94
.word 2b, put_user_fault
95
.popsection
96
97
98
/*
99
* strnlen_user_asm takes the pointer in r0, and the length bound in r1.
100
* It returns the length, including the terminating NUL, or zero on exception.
101
* If length is greater than the bound, returns one plus the bound.
102
*/
103
STD_ENTRY(strnlen_user_asm)
104
{ bz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */
105
1: { lb_u r4, r0; addi r1, r1, -1 }
106
bz r4, 2f
107
{ bnzt r1, 1b; addi r0, r0, 1 }
108
2: { sub r0, r0, r3; jrp lr }
109
STD_ENDPROC(strnlen_user_asm)
110
.pushsection .fixup,"ax"
111
strnlen_user_fault:
112
{ move r0, zero; jrp lr }
113
ENDPROC(strnlen_user_fault)
114
.section __ex_table,"a"
115
.word 1b, strnlen_user_fault
116
.popsection
117
118
/*
119
* strncpy_from_user_asm takes the kernel target pointer in r0,
120
* the userspace source pointer in r1, and the length bound (including
121
* the trailing NUL) in r2. On success, it returns the string length
122
* (not including the trailing NUL), or -EFAULT on failure.
123
*/
124
STD_ENTRY(strncpy_from_user_asm)
125
{ bz r2, 2f; move r3, r0 }
126
1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
127
{ sb r0, r4; addi r0, r0, 1 }
128
bz r2, 2f
129
bnzt r4, 1b
130
addi r0, r0, -1 /* don't count the trailing NUL */
131
2: { sub r0, r0, r3; jrp lr }
132
STD_ENDPROC(strncpy_from_user_asm)
133
.pushsection .fixup,"ax"
134
strncpy_from_user_fault:
135
{ movei r0, -EFAULT; jrp lr }
136
ENDPROC(strncpy_from_user_fault)
137
.section __ex_table,"a"
138
.word 1b, strncpy_from_user_fault
139
.popsection
140
141
/*
142
* clear_user_asm takes the user target address in r0 and the
143
* number of bytes to zero in r1.
144
* It returns the number of uncopiable bytes (hopefully zero) in r0.
145
* Note that we don't use a separate .fixup section here since we fall
146
* through into the "fixup" code as the last straight-line bundle anyway.
147
*/
148
STD_ENTRY(clear_user_asm)
149
{ bz r1, 2f; or r2, r0, r1 }
150
andi r2, r2, 3
151
bzt r2, .Lclear_aligned_user_asm
152
1: { sb r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
153
bnzt r1, 1b
154
2: { move r0, r1; jrp lr }
155
.pushsection __ex_table,"a"
156
.word 1b, 2b
157
.popsection
158
159
.Lclear_aligned_user_asm:
160
1: { sw r0, zero; addi r0, r0, 4; addi r1, r1, -4 }
161
bnzt r1, 1b
162
2: { move r0, r1; jrp lr }
163
STD_ENDPROC(clear_user_asm)
164
.pushsection __ex_table,"a"
165
.word 1b, 2b
166
.popsection
167
168
/*
169
* flush_user_asm takes the user target address in r0 and the
170
* number of bytes to flush in r1.
171
* It returns the number of unflushable bytes (hopefully zero) in r0.
172
*/
173
STD_ENTRY(flush_user_asm)
174
bz r1, 2f
175
{ movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
176
{ sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
177
{ and r0, r0, r2; and r1, r1, r2 }
178
{ sub r1, r1, r0 }
179
1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
180
{ addi r0, r0, CHIP_FLUSH_STRIDE(); bnzt r1, 1b }
181
2: { move r0, r1; jrp lr }
182
STD_ENDPROC(flush_user_asm)
183
.pushsection __ex_table,"a"
184
.word 1b, 2b
185
.popsection
186
187
/*
188
* inv_user_asm takes the user target address in r0 and the
189
* number of bytes to invalidate in r1.
190
* It returns the number of not inv'able bytes (hopefully zero) in r0.
191
*/
192
STD_ENTRY(inv_user_asm)
193
bz r1, 2f
194
{ movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
195
{ sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
196
{ and r0, r0, r2; and r1, r1, r2 }
197
{ sub r1, r1, r0 }
198
1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
199
{ addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b }
200
2: { move r0, r1; jrp lr }
201
STD_ENDPROC(inv_user_asm)
202
.pushsection __ex_table,"a"
203
.word 1b, 2b
204
.popsection
205
206
/*
207
* finv_user_asm takes the user target address in r0 and the
208
* number of bytes to flush-invalidate in r1.
209
* It returns the number of not finv'able bytes (hopefully zero) in r0.
210
*/
211
STD_ENTRY(finv_user_asm)
212
bz r1, 2f
213
{ movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
214
{ sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
215
{ and r0, r0, r2; and r1, r1, r2 }
216
{ sub r1, r1, r0 }
217
1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
218
{ addi r0, r0, CHIP_FINV_STRIDE(); bnzt r1, 1b }
219
2: { move r0, r1; jrp lr }
220
STD_ENDPROC(finv_user_asm)
221
.pushsection __ex_table,"a"
222
.word 1b, 2b
223
.popsection
224
225