8354 sync regcomp(3C) with upstream (fix make catalog)
[unleashed/tickless.git] / usr / src / uts / sun4u / ml / mach_copy.s
blob9666341e7de0049cf1f189258af8307a69280d9c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/param.h>
30 #include <sys/errno.h>
31 #include <sys/asm_linkage.h>
32 #include <sys/vtrace.h>
33 #include <sys/machthread.h>
34 #include <sys/clock.h>
35 #include <sys/asi.h>
36 #include <sys/fsr.h>
37 #include <sys/privregs.h>
39 #if !defined(lint)
40 #include "assym.h"
41 #endif /* lint */
43 #define FP_USED 1
44 #define LOFAULT_SET 2
47 * Error barrier:
48 * We use membar sync to establish an error barrier for
49 * deferred errors. Membar syncs are added before any update
50 * to t_lofault to ensure that deferred errors from earlier
51 * accesses will not be reported after the membar. This error
52 * isolation is important when we try to recover from async
53 * errors which tries to distinguish kernel accesses to user
54 * data.
58 * Zero a block of storage.
60 * uzero is used by the kernel to zero a block in user address space.
63 #if defined(lint)
65 /* ARGSUSED */
66 int
67 kzero(void *addr, size_t count)
68 { return(0); }
70 /* ARGSUSED */
71 void
72 uzero(void *addr, size_t count)
75 #else /* lint */
77 ENTRY(uzero)
79 ! Set a new lo_fault handler only if we came in with one
80 ! already specified.
82 wr %g0, ASI_USER, %asi
83 ldn [THREAD_REG + T_LOFAULT], %o5
84 tst %o5
85 bz,pt %ncc, .do_zero
86 sethi %hi(.zeroerr), %o2
87 or %o2, %lo(.zeroerr), %o2
88 membar #Sync
89 ba,pt %ncc, .do_zero
90 stn %o2, [THREAD_REG + T_LOFAULT]
92 ENTRY(kzero)
94 ! Always set a lo_fault handler
96 wr %g0, ASI_P, %asi
97 ldn [THREAD_REG + T_LOFAULT], %o5
98 sethi %hi(.zeroerr), %o2
99 or %o5, LOFAULT_SET, %o5
100 or %o2, %lo(.zeroerr), %o2
101 membar #Sync
102 ba,pt %ncc, .do_zero
103 stn %o2, [THREAD_REG + T_LOFAULT]
106 * We got here because of a fault during kzero or if
107 * uzero or bzero was called with t_lofault non-zero.
108 * Otherwise we've already run screaming from the room.
109 * Errno value is in %g1. Note that we're here iff
110 * we did set t_lofault.
112 .zeroerr:
114 ! Undo asi register setting. Just set it to be the
115 ! kernel default without checking.
117 wr %g0, ASI_P, %asi
119 ! If saved t_lofault has FP_USED set, clear the %fprs register
121 btst FP_USED, %o5
122 bz,pt %ncc, 1f ! skip if not used
124 membar #Sync
125 wr %g0, %g0, %fprs ! clear fprs
126 andn %o5, FP_USED, %o5 ! turn off flag bit
128 ! We did set t_lofault. It may well have been zero coming in.
131 tst %o5
132 membar #Sync
133 bne,pn %ncc, 3f
134 andncc %o5, LOFAULT_SET, %o5
137 ! Old handler was zero. Just return the error.
139 retl ! return
140 mov %g1, %o0 ! error code from %g1
143 ! We're here because %o5 was non-zero. It was non-zero
144 ! because either LOFAULT_SET was present, a previous fault
145 ! handler was present or both. In all cases we need to reset
146 ! T_LOFAULT to the value of %o5 after clearing LOFAULT_SET
147 ! before we either simply return the error or we invoke the
148 ! previously specified handler.
150 be %ncc, 2b
151 stn %o5, [THREAD_REG + T_LOFAULT]
152 jmp %o5 ! goto real handler
154 SET_SIZE(kzero)
155 SET_SIZE(uzero)
157 #endif /* lint */
160 * Zero a block of storage.
163 #if defined(lint)
165 /* ARGSUSED */
166 void
167 bzero(void *addr, size_t count)
170 #else /* lint */
172 ENTRY(bzero)
173 wr %g0, ASI_P, %asi
175 ldn [THREAD_REG + T_LOFAULT], %o5 ! save old vector
176 tst %o5
177 bz,pt %ncc, .do_zero
178 sethi %hi(.zeroerr), %o2
179 or %o2, %lo(.zeroerr), %o2
180 membar #Sync ! sync error barrier
181 stn %o2, [THREAD_REG + T_LOFAULT] ! install new vector
183 .do_zero:
184 cmp %o1, 15 ! check for small counts
185 blu,pn %ncc, .byteclr ! just clear bytes
188 cmp %o1, 192 ! check for large counts
189 blu %ncc, .bzero_small
192 sethi %hi(use_hw_bzero), %o2
193 ld [%o2 + %lo(use_hw_bzero)], %o2
194 tst %o2
195 bz %icc, .bzero_small
198 rd %fprs, %o2 ! check for unused fp
199 btst FPRS_FEF, %o2
200 bnz %icc, .bzero_small
203 ldn [THREAD_REG + T_LWP], %o2
204 tst %o2
205 bz,pn %ncc, .bzero_small
208 ! Check for block alignment
209 btst (64-1), %o0
210 bz %icc, .bzl_block
213 ! Check for double-word alignment
214 btst (8-1), %o0
215 bz %icc, .bzl_dword
218 ! Check for word alignment
219 btst (4-1), %o0
220 bz %icc, .bzl_word
223 ! Clear bytes until word aligned
224 .bzl_byte:
225 stba %g0, [%o0]%asi
226 add %o0, 1, %o0
227 btst (4-1), %o0
228 bnz %icc, .bzl_byte
229 sub %o1, 1, %o1
231 ! Check for dword-aligned
232 btst (8-1), %o0
233 bz %icc, .bzl_dword
236 ! Clear words until double-word aligned
237 .bzl_word:
238 sta %g0, [%o0]%asi
239 add %o0, 4, %o0
240 btst (8-1), %o0
241 bnz %icc, .bzl_word
242 sub %o1, 4, %o1
244 .bzl_dword:
245 ! Clear dwords until block aligned
246 stxa %g0, [%o0]%asi
247 add %o0, 8, %o0
248 btst (64-1), %o0
249 bnz %icc, .bzl_dword
250 sub %o1, 8, %o1
252 .bzl_block:
253 membar #StoreStore|#StoreLoad|#LoadStore
254 wr %g0, FPRS_FEF, %fprs
256 ! Set the lower bit in the saved t_lofault to indicate
257 ! that we need to clear the %fprs register on the way
258 ! out
259 or %o5, FP_USED, %o5
261 ! Clear block
262 fzero %d0
263 fzero %d2
264 fzero %d4
265 fzero %d6
266 fzero %d8
267 fzero %d10
268 fzero %d12
269 fzero %d14
270 rd %asi, %o3
271 wr %g0, ASI_BLK_P, %asi
272 cmp %o3, ASI_P
273 bne,a %icc, 1f
274 wr %g0, ASI_BLK_AIUS, %asi
276 mov 256, %o3
277 ba,pt %ncc, .bzl_doblock
280 .bzl_blkstart:
281 ! stda %d0, [%o0+192]%asi ! in dly slot of branch that got us here
282 stda %d0, [%o0+128]%asi
283 stda %d0, [%o0+64]%asi
284 stda %d0, [%o0]%asi
285 .bzl_zinst:
286 add %o0, %o3, %o0
287 sub %o1, %o3, %o1
288 .bzl_doblock:
289 cmp %o1, 256
290 bgeu,a %ncc, .bzl_blkstart
291 stda %d0, [%o0+192]%asi
293 cmp %o1, 64
294 blu %ncc, .bzl_finish
296 andn %o1, (64-1), %o3
297 srl %o3, 4, %o2 ! using blocks, 1 instr / 16 words
298 set .bzl_zinst, %o4
299 sub %o4, %o2, %o4
300 jmp %o4
303 .bzl_finish:
304 membar #StoreLoad|#StoreStore
305 wr %g0, %g0, %fprs
306 andn %o5, FP_USED, %o5
308 rd %asi, %o4
309 wr %g0, ASI_P, %asi
310 cmp %o4, ASI_BLK_P
311 bne,a %icc, 1f
312 wr %g0, ASI_USER, %asi
315 .bzlf_dword:
316 ! double words
317 cmp %o1, 8
318 blu %ncc, .bzlf_word
320 stxa %g0, [%o0]%asi
321 add %o0, 8, %o0
322 sub %o1, 8, %o1
323 ba,pt %ncc, .bzlf_dword
326 .bzlf_word:
327 ! words
328 cmp %o1, 4
329 blu %ncc, .bzlf_byte
331 sta %g0, [%o0]%asi
332 add %o0, 4, %o0
333 sub %o1, 4, %o1
334 ba,pt %ncc, .bzlf_word
338 add %o0, 1, %o0 ! increment address
339 .bzlf_byte:
340 subcc %o1, 1, %o1 ! decrement count
341 bgeu,a %ncc, 1b
342 stba %g0, [%o0]%asi ! zero a byte
345 ! If we used the FP registers, that bit was turned
346 ! off after we were finished. We're just concerned with
347 ! whether t_lofault was set when we came in. We end up
348 ! here from either kzero() or bzero(). kzero() *always*
349 ! sets a lofault handler. It ors LOFAULT_SET into %o5
350 ! to indicate it has done this even if the value of %o5
351 ! is otherwise zero. bzero() sets a lofault handler *only*
352 ! if one was previously set. Accordingly we need to examine
353 ! %o5 and if it is non-zero be sure to clear LOFAULT_SET
354 ! before resetting the error handler.
356 tst %o5
357 bz,pt %ncc, 1f
358 andn %o5, LOFAULT_SET, %o5
359 membar #Sync ! sync error barrier
360 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
362 retl
363 clr %o0 ! return (0)
365 .bzero_small:
368 ! Check for word alignment.
370 btst 3, %o0
371 bz .bzero_probe
372 mov 0x100, %o3 ! constant size of main loop
375 ! clear bytes until word aligned
377 1: stba %g0,[%o0]%asi
378 add %o0, 1, %o0
379 btst 3, %o0
380 bnz 1b
381 sub %o1, 1, %o1
382 .bzero_probe:
385 ! if needed move a word to become double-word aligned.
387 btst 7, %o0 ! is double aligned?
388 bz %icc, .bzero_nobuf
390 sta %g0, [%o0]%asi ! clr to double boundry
391 sub %o1, 4, %o1
392 ba,pt %ncc, .bzero_nobuf
393 add %o0, 4, %o0
395 !stxa %g0, [%o0+0xf8]%asi
396 .bzero_blk:
397 stxa %g0, [%o0+0xf0]%asi
398 stxa %g0, [%o0+0xe8]%asi
399 stxa %g0, [%o0+0xe0]%asi
400 stxa %g0, [%o0+0xd8]%asi
401 stxa %g0, [%o0+0xd0]%asi
402 stxa %g0, [%o0+0xc8]%asi
403 stxa %g0, [%o0+0xc0]%asi
404 stxa %g0, [%o0+0xb8]%asi
405 stxa %g0, [%o0+0xb0]%asi
406 stxa %g0, [%o0+0xa8]%asi
407 stxa %g0, [%o0+0xa0]%asi
408 stxa %g0, [%o0+0x98]%asi
409 stxa %g0, [%o0+0x90]%asi
410 stxa %g0, [%o0+0x88]%asi
411 stxa %g0, [%o0+0x80]%asi
412 stxa %g0, [%o0+0x78]%asi
413 stxa %g0, [%o0+0x70]%asi
414 stxa %g0, [%o0+0x68]%asi
415 stxa %g0, [%o0+0x60]%asi
416 stxa %g0, [%o0+0x58]%asi
417 stxa %g0, [%o0+0x50]%asi
418 stxa %g0, [%o0+0x48]%asi
419 stxa %g0, [%o0+0x40]%asi
420 stxa %g0, [%o0+0x38]%asi
421 stxa %g0, [%o0+0x30]%asi
422 stxa %g0, [%o0+0x28]%asi
423 stxa %g0, [%o0+0x20]%asi
424 stxa %g0, [%o0+0x18]%asi
425 stxa %g0, [%o0+0x10]%asi
426 stxa %g0, [%o0+0x08]%asi
427 stxa %g0, [%o0]%asi
428 .zinst:
429 add %o0, %o3, %o0 ! increment source address
430 sub %o1, %o3, %o1 ! decrement count
431 .bzero_nobuf:
432 cmp %o1, 0x100 ! can we do whole chunk?
433 bgeu,a %ncc, .bzero_blk
434 stxa %g0, [%o0+0xf8]%asi ! do first double of chunk
436 cmp %o1, 7 ! can we zero any more double words
437 bleu %ncc, .byteclr ! too small go zero bytes
439 andn %o1, 7, %o3 ! %o3 bytes left, double-word aligned
440 srl %o3, 1, %o2 ! using doubles, need 1 instr / 2 words
441 set .zinst, %o4 ! address of clr instructions
442 sub %o4, %o2, %o4 ! jmp address relative to instr
443 jmp %o4
446 ! do leftover bytes
449 add %o0, 1, %o0 ! increment address
450 .byteclr:
451 subcc %o1, 1, %o1 ! decrement count
452 bgeu,a %ncc, 3b
453 stba %g0, [%o0]%asi ! zero a byte
455 .bzero_finished:
457 ! We're just concerned with whether t_lofault was set
458 ! when we came in. We end up here from either kzero()
459 ! or bzero(). kzero() *always* sets a lofault handler.
460 ! It ors LOFAULT_SET into %o5 to indicate it has done
461 ! this even if the value of %o5 is otherwise zero.
462 ! bzero() sets a lofault handler *only* if one was
463 ! previously set. Accordingly we need to examine
464 ! %o5 and if it is non-zero be sure to clear LOFAULT_SET
465 ! before resetting the error handler.
467 tst %o5
468 bz %ncc, 1f
469 andn %o5, LOFAULT_SET, %o5
470 membar #Sync ! sync error barrier
471 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault
473 retl
474 clr %o0 ! return (0)
476 SET_SIZE(bzero)
477 #endif /* lint */