1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/param.h>
29 #include <sys/errno.h>
30 #include <sys/asm_linkage.h>
31 #include <sys/vtrace.h>
32 #include <sys/machthread.h>
33 #include <sys/clock.h>
34 #include <sys/asi.h>
35 #include <sys/fsr.h>
36 #include <sys/privregs.h>
37
38 #if !defined(lint)
39 #include "assym.h"
40 #endif /* lint */
41
42 /*
43 * Error barrier:
44 * We use membar sync to establish an error barrier for
45 * deferred errors. Membar syncs are added before any update
46 * to t_lofault to ensure that deferred errors from earlier
47 * accesses will not be reported after the membar. This error
48 * isolation is important when we try to recover from async
49 * errors which tries to distinguish kernel accesses to user
50 * data.
51 */
52
53 /*
54 * Copy a null terminated string from one point to another in
55 * the kernel address space.
56 * NOTE - don't use %o5 in this routine as copy{in,out}str uses it.
57 *
58 * copystr(from, to, maxlength, lencopied)
59 * caddr_t from, to;
60 * u_int maxlength, *lencopied;
61 */
62
63 #if defined(lint)
64
65 /* ARGSUSED */
66 int
67 copystr(const char *from, char *to, size_t maxlength, size_t *lencopied)
68 { return(0); }
69
70 #else /* lint */
71
72 ENTRY(copystr)
73 orcc %o2, %g0, %o4 ! save original count
74 bg,a %ncc, 1f
75 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst
76
77 !
78 ! maxlength <= 0
79 !
80 bz %ncc, .cs_out ! maxlength = 0
81 mov ENAMETOOLONG, %o0
82
83 b 2f ! maxlength < 0
84 mov EFAULT, %o0 ! return failure
85
86 !
87 ! Do a byte by byte loop.
88 ! We do this instead of a word by word copy because most strings
89 ! are small and this takes a small number of cache lines.
90 !
91 0:
92 stb %g1, [%o1] ! store byte
93 tst %g1
94 bnz,pt %icc, 1f
95 add %o1, 1, %o1 ! incr dst addr
96
97 ba,pt %ncc, .cs_out ! last byte in string
98 mov 0, %o0 ! ret code = 0
99 1:
100 subcc %o2, 1, %o2 ! test count
101 bgeu,a %ncc, 0b
102 ldub [%o0 + %o1], %g1 ! delay slot, get source byte
103
104 mov 0, %o2 ! max number of bytes moved
105 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG
106 .cs_out:
107 tst %o3
108 bz %ncc, 2f
109 sub %o4, %o2, %o4 ! compute length and store it
110 stn %o4, [%o3]
111 2:
112 retl
113 nop
114 SET_SIZE(copystr)
115
116 #endif /* lint */
117
118
119 /*
120 * Copy a null terminated string from the user address space into
121 * the kernel address space.
122 */
123 #if defined(lint)
124
125 /* ARGSUSED */
126 int
127 copyinstr(const char *uaddr, char *kaddr, size_t maxlength,
128 size_t *lencopied)
129 { return (0); }
130
131 #else /* lint */
132
133 ENTRY(copyinstr)
134 sethi %hi(.copyinstr_err), %o4
135 ldn [THREAD_REG + T_LOFAULT], %o5 ! catch faults
136 or %o4, %lo(.copyinstr_err), %o4
137 membar #Sync ! sync error barrier
138 stn %o4, [THREAD_REG + T_LOFAULT]
139
140 brz,a,pn %o2, .copyinstr_out
141 mov ENAMETOOLONG, %o0
142
143 mov %o2, %g3 ! g3 is the current count
144 mov %o1, %g4 ! g4 is the dest addr
145
146 b 1f
147 sub %o0, %o1, %g2 ! g2 gets the difference of src and dst
148
149 !
150 ! Do a byte by byte loop.
151 ! We do this instead of a word by word copy because most strings
152 ! are small and this takes a small number of cache lines.
153 !
154 0:
155 stb %g1, [%g4] ! store byte
156 tst %g1
157 bnz,pt %icc, 1f
158 add %g4, 1, %g4 ! incr dst addr
159
160 ba,pt %ncc, .copyinstr_out ! last byte in string
161 mov 0, %o0 ! ret code = 0
162 1:
163 subcc %g3, 1, %g3 ! test count
164 bgeu,a %ncc, 0b
165 lduba [%g2+%g4]ASI_USER, %g1 ! delay slot, get source byte
166
167 mov 0, %g3 ! max number of bytes moved
168 ba,pt %ncc, .copyinstr_out
169 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG
170
171 /*
172 * Fault while trying to move from or to user space.
173 * Set and return error code.
174 */
175 .copyinstr_err:
176 membar #Sync ! sync error barrier
177 stn %o5, [THREAD_REG + T_LOFAULT]
178 ldn [THREAD_REG + T_COPYOPS], %o4
179 brz %o4, 1f
180 nop
181 ldn [%o4 + CP_COPYINSTR], %g1
182 jmp %g1
183 nop
184 1:
185 retl
186 mov EFAULT, %o0
187 .copyinstr_out:
188 tst %o3 ! want length?
189 bz %ncc, 2f
190 sub %o2, %g3, %o2 ! compute length and store it
191 stn %o2, [%o3]
192 2:
193 membar #Sync ! sync error barrier
194 retl
195 stn %o5, [THREAD_REG + T_LOFAULT] ! stop catching faults
196 SET_SIZE(copyinstr)
197 #endif
198
199 #if defined(lint)
200
201 /* ARGSUSED */
202 int
203 copyinstr_noerr(const char *uaddr, char *kaddr, size_t maxlength,
204 size_t *lencopied)
205 { return (0); }
206
207 #else /* lint */
208
209 ENTRY(copyinstr_noerr)
210 mov %o2, %o4 ! save original count
211
212 ! maxlength is unsigned so the only error is if it's 0
213 brz,a,pn %o2, .copyinstr_noerr_out
214 mov ENAMETOOLONG, %o0
215
216 b 1f
217 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst
218
219 !
220 ! Do a byte by byte loop.
221 ! We do this instead of a word by word copy because most strings
222 ! are small and this takes a small number of cache lines.
223 !
224 0:
225 stb %g1, [%o1] ! store byte
226 tst %g1 ! null byte?
227 bnz 1f
228 add %o1, 1, %o1 ! incr dst addr
229
230 ba,pt %ncc, .copyinstr_noerr_out ! last byte in string
231 mov 0, %o0 ! ret code = 0
232 1:
233 subcc %o2, 1, %o2 ! test count
234 bgeu,a %ncc, 0b
235 lduba [%o0 + %o1]ASI_USER, %g1 ! delay slot, get source byte
236
237 mov 0, %o2 ! max number of bytes moved
238 b .copyinstr_noerr_out
239 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG
240 .copyinstr_noerr_out:
241 tst %o3 ! want length?
242 bz %ncc, 2f
243 sub %o4, %o2, %o4
244 stn %o4, [%o3]
245 2:
246 retl
247 nop
248 SET_SIZE(copyinstr_noerr)
249
250 #endif /* lint */
251
252 /*
253 * Copy a null terminated string from the kernel
254 * address space to the user address space.
255 */
256
257 #if defined(lint)
258
259 /* ARGSUSED */
260 int
261 copyoutstr(const char *kaddr, char *uaddr, size_t maxlength,
262 size_t *lencopied)
263 { return (0); }
264
265 #else /* lint */
266
267 ENTRY(copyoutstr)
268 sethi %hi(.copyoutstr_err), %o5
269 ldn [THREAD_REG + T_LOFAULT], %o4 ! catch faults
270 or %o5, %lo(.copyoutstr_err), %o5
271 membar #Sync ! sync error barrier
272 stn %o5, [THREAD_REG + T_LOFAULT]
273 mov %o4, %o5
274
275 brz,a,pn %o2, .copyoutstr_out
276 mov ENAMETOOLONG, %o0
277
278 mov %o2, %g3 ! g3 is the current count
279 mov %o1, %g4 ! g4 is the dest addr
280
281 b 1f
282 sub %o0, %o1, %g2 ! g2 gets the difference of src and dst
283
284 !
285 ! Do a byte by byte loop.
286 ! We do this instead of a word by word copy because most strings
287 ! are small and this takes a small number of cache lines.
288 !
289 0:
290 stba %g1, [%g4]ASI_USER ! store byte
291 tst %g1
292 bnz,pt %icc, 1f
293 add %g4, 1, %g4 ! incr dst addr
294
295 ba,pt %ncc, .copyoutstr_out ! last byte in string
296 mov 0, %o0 ! ret code = 0
297 1:
298 subcc %g3, 1, %g3 ! test count
299 bgeu,a %ncc, 0b
300 ldub [%g2 + %g4], %g1 ! delay slot, get source byte
301
302 mov 0, %g3 ! max number of bytes moved
303 ba,pt %ncc, .copyoutstr_out
304 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG
305
306 /*
307 * Fault while trying to move from or to user space.
308 * Set and return error code.
309 */
310 .copyoutstr_err:
311 membar #Sync ! sync error barrier
312 stn %o5, [THREAD_REG + T_LOFAULT]
313 ldn [THREAD_REG + T_COPYOPS], %o4
314 brz %o4, 1f
315 nop
316 ldn [%o4 + CP_COPYOUTSTR], %g1
317 jmp %g1
318 nop
319 1:
320 retl
321 mov EFAULT, %o0
322 .copyoutstr_out:
323 tst %o3 ! want length?
324 bz %ncc, 2f
325 sub %o2, %g3, %o2 ! compute length and store it
326 stn %o2, [%o3]
327 2:
328 membar #Sync ! sync error barrier
329 retl
330 stn %o5, [THREAD_REG + T_LOFAULT] ! stop catching faults
331 SET_SIZE(copyoutstr)
332
333 #endif /* lint */
334
335 #if defined(lint)
336
337 /* ARGSUSED */
338 int
339 copyoutstr_noerr(const char *kaddr, char *uaddr, size_t maxlength,
340 size_t *lencopied)
341 { return (0); }
342
343 #else /* lint */
344
345 ENTRY(copyoutstr_noerr)
346 mov %o2, %o4 ! save original count
347
348 brz,a,pn %o2, .copyoutstr_noerr_out
349 mov ENAMETOOLONG, %o0
350
351 b 1f
352 sub %o0, %o1, %o0 ! o0 gets the difference of src and dst
353
354 !
355 ! Do a byte by byte loop.
356 ! We do this instead of a word by word copy because most strings
357 ! are small and this takes a small number of cache lines.
358 !
359 0:
360 stba %g1, [%o1]ASI_USER ! store byte
361 tst %g1 ! null byte?
362 bnz 1f
363 add %o1, 1, %o1 ! incr dst addr
364
365 b .copyoutstr_noerr_out ! last byte in string
366 mov 0, %o0 ! ret code = 0
367 1:
368 subcc %o2, 1, %o2 ! test count
369 bgeu,a %ncc, 0b
370 ldub [%o0+%o1], %g1 ! delay slot, get source byte
371
372 mov 0, %o2 ! max number of bytes moved
373 b .copyoutstr_noerr_out
374 mov ENAMETOOLONG, %o0 ! ret code = ENAMETOOLONG
375 .copyoutstr_noerr_out:
376 tst %o3 ! want length?
377 bz %ncc, 2f
378 sub %o4, %o2, %o4
379 stn %o4, [%o3]
380 2:
381 retl
382 nop
383 SET_SIZE(copyoutstr_noerr)
384
385 #endif /* lint */
386
387
388 /*
389 * Copy a block of storage. If the source and target regions overlap,
390 * one or both of the regions will be silently corrupted.
391 * No fault handler installed (to be called under on_fault())
392 */
393
394 #if defined(lint)
395
396 /* ARGSUSED */
397 void
398 ucopy(const void *ufrom, void *uto, size_t ulength)
399 {}
400
401 #else /* lint */
402
403 ENTRY(ucopy)
404 save %sp, -SA(MINFRAME), %sp ! get another window
405
406 subcc %g0, %i2, %i3
407 add %i0, %i2, %i0
408 bz,pn %ncc, 5f
409 add %i1, %i2, %i1
410 lduba [%i0 + %i3]ASI_USER, %i4
411 4: stba %i4, [%i1 + %i3]ASI_USER
412 inccc %i3
413 bcc,a,pt %ncc, 4b
414 lduba [%i0 + %i3]ASI_USER, %i4
415 5:
416 ret
417 restore %g0, 0, %o0 ! return (0)
418
419 SET_SIZE(ucopy)
420 #endif /* lint */
421
422 /*
423 * Copy a user-land string. If the source and target regions overlap,
424 * one or both of the regions will be silently corrupted.
425 * No fault handler installed (to be called under on_fault())
426 */
427
428 #if defined(lint)
429
430 /* ARGSUSED */
431 void
432 ucopystr(const char *ufrom, char *uto, size_t umaxlength, size_t *ulencopied)
433 {}
434
435 #else /* lint */
436
437 ENTRY(ucopystr)
438 save %sp, -SA(MINFRAME), %sp ! get another window
439
440 brz %i2, 5f
441 clr %i5
442
443 lduba [%i0 + %i5]ASI_USER, %i4
444 4: stba %i4, [%i1 + %i5]ASI_USER
445 brz,pn %i4, 5f
446 inc %i5
447 deccc %i2
448 bnz,a,pt %ncc, 4b
449 lduba [%i0 + %i5]ASI_USER, %i4
450 5:
451 brnz,a,pt %i3, 6f
452 stn %i5, [%i3]
453 6:
454 ret
455 restore %g0, 0, %o0 ! return (0)
456
457 SET_SIZE(ucopystr)
458 #endif /* lint */