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
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]
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>
37 #include <sys/privregs.h>
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
58 * Zero a block of storage.
60 * uzero is used by the kernel to zero a block in user address space.
67 kzero
(void
*addr
, size_t count
)
72 uzero
(void
*addr
, size_t count
)
79 ! Set
a new lo_fault handler only if we came in with one
82 wr
%g0
, ASI_USER
, %asi
83 ldn
[THREAD_REG
+ T_LOFAULT
], %o5
86 sethi
%hi
(.zeroerr), %o2
87 or %o2
, %lo
(.zeroerr), %o2
90 stn
%o2
, [THREAD_REG
+ T_LOFAULT
]
94 ! Always set
a lo_fault handler
97 ldn
[THREAD_REG
+ T_LOFAULT
], %o5
98 sethi
%hi
(.zeroerr), %o2
99 or %o5
, LOFAULT_SET
, %o5
100 or %o2
, %lo
(.zeroerr), %o2
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.
114 ! Undo asi register setting. Just set it to
be the
115 ! kernel default without checking.
119 ! If saved t_lofault has FP_USED set
, clear the
%fprs register
122 bz
,pt
%ncc
, 1f
! skip if
not used
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.
134 andncc
%o5
, LOFAULT_SET
, %o5
137 ! Old handler was zero. Just return the error.
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.
151 stn %o5, [THREAD_REG + T_LOFAULT]
152 jmp %o5 ! goto real handler
160 * Zero a block of storage.
167 bzero(void *addr, size_t count)
175 ldn [THREAD_REG + T_LOFAULT], %o5 ! save old vector
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
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
195 bz %icc, .bzero_small
198 rd %fprs, %o2 ! check for unused fp
200 bnz %icc, .bzero_small
203 ldn [THREAD_REG + T_LWP], %o2
205 bz,pn %ncc, .bzero_small
208 ! Check for block alignment
213 ! Check for double-word alignment
218 ! Check for word alignment
223 ! Clear bytes until word aligned
231 ! Check for dword-aligned
236 ! Clear words until double-word aligned
245 ! Clear dwords until block aligned
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
271 wr %g0, ASI_BLK_P, %asi
274 wr %g0, ASI_BLK_AIUS, %asi
277 ba,pt %ncc, .bzl_doblock
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
290 bgeu,a %ncc, .bzl_blkstart
291 stda %d0, [%o0+192]%asi
294 blu %ncc, .bzl_finish
296 andn %o1, (64-1), %o3
297 srl %o3, 4, %o2 ! using blocks, 1 instr / 16 words
304 membar #StoreLoad|#StoreStore
306 andn %o5, FP_USED, %o5
312 wr %g0, ASI_USER, %asi
323 ba,pt %ncc, .bzlf_dword
334 ba,pt %ncc, .bzlf_word
338 add %o0, 1, %o0 ! increment address
340 subcc %o1, 1, %o1 ! decrement count
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.
358 andn
%o5
, LOFAULT_SET
, %o5
359 membar
#Sync ! sync error barrier
360 stn
%o5
, [THREAD_REG
+ T_LOFAULT
] ! restore old t_lofault
368 ! Check for word alignment.
372 mov
0x100, %o3
! constant size of main loop
375 ! clear bytes until word aligned
377 1: stba
%g0
,[%o0
]%asi
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
392 ba,pt
%ncc
, .bzero_nobuf
395 !stxa
%g0
, [%o0+
0xf8]%asi
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
429 add %o0
, %o3
, %o0
! increment source address
430 sub %o1
, %o3
, %o1
! decrement count
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
449 add %o0
, 1, %o0
! increment address
451 subcc
%o1
, 1, %o1
! decrement count
453 stba
%g0
, [%o0
]%asi
! zero
a byte
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.
469 andn %o5, LOFAULT_SET, %o5
470 membar #Sync ! sync error barrier
471 stn %o5, [THREAD_REG + T_LOFAULT] ! restore old t_lofault