Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/tile/lib/usercopy_64.S
10820 views
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
197
198