#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_multiprocessor.h"
#include "opt_compat_netbsd.h"
#include "opt_compat_netbsd32.h"
#include "opt_lockdebug.h"
#include "assym.h"
#include <machine/param.h>
#include <machine/ctlreg.h>
#include <machine/asm.h>
#include <machine/locore.h>
#include <machine/psl.h>
#include "ksyms.h"
.register %g2,#scratch
.register %g3,#scratch
ENTRY(copyinstr)
! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
#ifdef NOTDEF_DEBUG
save %sp, -CC64FSZ, %sp
set 8f, %o0
mov %i0, %o1
mov %i1, %o2
mov %i2, %o3
call printf
mov %i3, %o4
restore
.data
8: .asciz "copyinstr: from=%x to=%x max=%x &len=%x\n"
_ALIGN
.text
#endif
brgz,pt %o2, 1f ! Make sure len is valid
sethi %hi(CPCB), %o4 ! (first instr of copy)
retl
mov ENAMETOOLONG, %o0
1:
LDPTR [%o4 + %lo(CPCB)], %o4 ! catch faults
set Lcsdone, %o5
membar #Sync
STPTR %o5, [%o4 + PCB_ONFAULT]
mov %o1, %o5 ! save = toaddr;
! XXX should do this in bigger chunks when possible
0: ! loop:
ldsba [%o0] ASI_AIUS, %g1 ! c = *fromaddr;
stb %g1, [%o1] ! *toaddr++ = c;
inc %o1
brz,a,pn %g1, Lcsdone ! if (c == NULL)
clr %o0 ! { error = 0; done; }
deccc %o2 ! if (--len > 0) {
bg,pt %icc, 0b ! fromaddr++;
inc %o0 ! goto loop;
ba,pt %xcc, Lcsdone ! }
mov ENAMETOOLONG, %o0 ! error = ENAMETOOLONG;
NOTREACHED
ENTRY(copyoutstr)
! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
#ifdef NOTDEF_DEBUG
save %sp, -CC64FSZ, %sp
set 8f, %o0
mov %i0, %o1
mov %i1, %o2
mov %i2, %o3
call printf
mov %i3, %o4
restore
.data
8: .asciz "copyoutstr: from=%x to=%x max=%x &len=%x\n"
_ALIGN
.text
#endif
brgz,pt %o2, 1f ! Make sure len is valid
sethi %hi(CPCB), %o4 ! (first instr of copy)
retl
mov ENAMETOOLONG, %o0
1:
LDPTR [%o4 + %lo(CPCB)], %o4 ! catch faults
set Lcsdone, %o5
membar #Sync
STPTR %o5, [%o4 + PCB_ONFAULT]
mov %o1, %o5 ! save = toaddr;
! XXX should do this in bigger chunks when possible
0: ! loop:
ldsb [%o0], %g1 ! c = *fromaddr;
stba %g1, [%o1] ASI_AIUS ! *toaddr++ = c;
inc %o1
brz,a,pn %g1, Lcsdone ! if (c == NULL)
clr %o0 ! { error = 0; done; }
deccc %o2 ! if (--len > 0) {
bg,pt %icc, 0b ! fromaddr++;
inc %o0 ! goto loop;
! }
mov ENAMETOOLONG, %o0 ! error = ENAMETOOLONG;
Lcsdone: ! done:
sub %o1, %o5, %o1 ! len = to - save;
brnz,a %o3, 1f ! if (lencopied)
STPTR %o1, [%o3] ! *lencopied = len;
1:
retl ! cpcb->pcb_onfault = 0;
STPTR %g0, [%o4 + PCB_ONFAULT]! return (error);
ENTRY(copyin)
! flushw ! Make sure we don't have stack probs & lose hibits of %o
#ifdef NOTDEF_DEBUG
save %sp, -CC64FSZ, %sp
set 1f, %o0
mov %i0, %o1
mov %i1, %o2
call printf
mov %i2, %o3
restore
.data
1: .asciz "copyin: src=%x dest=%x len=%x\n"
_ALIGN
.text
#endif
sethi %hi(CPCB), %o3
wr %g0, ASI_AIUS, %asi
LDPTR [%o3 + %lo(CPCB)], %o3
set Lcopyfault, %o4
! mov %o7, %g7 ! save return address
membar #Sync
STPTR %o4, [%o3 + PCB_ONFAULT]
cmp %o2, BCOPY_SMALL
Lcopyin_start:
bge,a Lcopyin_fancy ! if >= this many, go be fancy.
btst 7, %o0 ! (part of being fancy)
deccc %o2 ! while (--len >= 0)
bl 1f
0:
inc %o0
ldsba [%o0 - 1] %asi, %o4! *dst++ = (++src)[-1];
stb %o4, [%o1]
deccc %o2
bge 0b
inc %o1
1:
ba Lcopyin_done
clr %o0
NOTREACHED
Lcopyin_fancy:
! check for common case first: everything lines up.
! btst 7, %o0 ! done already
bne 1f
.empty
btst 7, %o1
be,a Lcopyin_doubles
dec 8, %o2 ! if all lined up, len -= 8, goto copyin_doubes
! If the low bits match, we can make these line up.
1:
xor %o0, %o1, %o3 ! t = src ^ dst;
btst 1, %o3 ! if (t & 1) {
be,a 1f
btst 1, %o0 ! [delay slot: if (src & 1)]
! low bits do not match, must copy by bytes.
0:
ldsba [%o0] %asi, %o4 ! do {
inc %o0 ! (++dst)[-1] = *src++;
inc %o1
deccc %o2
bnz 0b ! } while (--len != 0);
stb %o4, [%o1 - 1]
ba Lcopyin_done
clr %o0
NOTREACHED
! lowest bit matches, so we can copy by words, if nothing else
1:
be,a 1f ! if (src & 1) {
btst 2, %o3 ! [delay slot: if (t & 2)]
! although low bits match, both are 1: must copy 1 byte to align
ldsba [%o0] %asi, %o4 ! *dst++ = *src++;
stb %o4, [%o1]
inc %o0
inc %o1
dec %o2 ! len--;
btst 2, %o3 ! } [if (t & 2)]
1:
be,a 1f ! if (t & 2) {
btst 2, %o0 ! [delay slot: if (src & 2)]
dec 2, %o2 ! len -= 2;
0:
ldsha [%o0] %asi, %o4 ! do {
sth %o4, [%o1] ! *(short *)dst = *(short *)src;
inc 2, %o0 ! dst += 2, src += 2;
deccc 2, %o2 ! } while ((len -= 2) >= 0);
bge 0b
inc 2, %o1
b Lcopyin_mopb ! goto mop_up_byte;
btst 1, %o2 ! } [delay slot: if (len & 1)]
NOTREACHED
! low two bits match, so we can copy by longwords
1:
be,a 1f ! if (src & 2) {
btst 4, %o3 ! [delay slot: if (t & 4)]
! although low 2 bits match, they are 10: must copy one short to align
ldsha [%o0] %asi, %o4 ! (*short *)dst = *(short *)src;
sth %o4, [%o1]
inc 2, %o0 ! dst += 2;
inc 2, %o1 ! src += 2;
dec 2, %o2 ! len -= 2;
btst 4, %o3 ! } [if (t & 4)]
1:
be,a 1f ! if (t & 4) {
btst 4, %o0 ! [delay slot: if (src & 4)]
dec 4, %o2 ! len -= 4;
0:
lduwa [%o0] %asi, %o4 ! do {
st %o4, [%o1] ! *(int *)dst = *(int *)src;
inc 4, %o0 ! dst += 4, src += 4;
deccc 4, %o2 ! } while ((len -= 4) >= 0);
bge 0b
inc 4, %o1
b Lcopyin_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! } [delay slot: if (len & 2)]
NOTREACHED
! low three bits match, so we can copy by doublewords
1:
be 1f ! if (src & 4) {
dec 8, %o2 ! [delay slot: len -= 8]
lduwa [%o0] %asi, %o4 ! *(int *)dst = *(int *)src;
st %o4, [%o1]
inc 4, %o0 ! dst += 4, src += 4, len -= 4;
inc 4, %o1
dec 4, %o2 ! }
1:
Lcopyin_doubles:
ldxa [%o0] %asi, %g1 ! do {
stx %g1, [%o1] ! *(double *)dst = *(double *)src;
inc 8, %o0 ! dst += 8, src += 8;
deccc 8, %o2 ! } while ((len -= 8) >= 0);
bge Lcopyin_doubles
inc 8, %o1
! check for a usual case again (save work)
btst 7, %o2 ! if ((len & 7) == 0)
be Lcopyin_done ! goto copyin_done;
btst 4, %o2 ! if ((len & 4)) == 0)
be,a Lcopyin_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! [delay slot: if (len & 2)]
lduwa [%o0] %asi, %o4 ! *(int *)dst = *(int *)src;
st %o4, [%o1]
inc 4, %o0 ! dst += 4;
inc 4, %o1 ! src += 4;
btst 2, %o2 ! } [if (len & 2)]
1:
! mop up trailing word (if present) and byte (if present).
Lcopyin_mopw:
be Lcopyin_mopb ! no word, go mop up byte
btst 1, %o2 ! [delay slot: if (len & 1)]
ldsha [%o0] %asi, %o4 ! *(short *)dst = *(short *)src;
be Lcopyin_done ! if ((len & 1) == 0) goto done;
sth %o4, [%o1]
ldsba [%o0 + 2] %asi, %o4 ! dst[2] = src[2];
stb %o4, [%o1 + 2]
ba Lcopyin_done
clr %o0
NOTREACHED
! mop up trailing byte (if present).
Lcopyin_mopb:
be,a Lcopyin_done
nop
ldsba [%o0] %asi, %o4
stb %o4, [%o1]
Lcopyin_done:
sethi %hi(CPCB), %o3
! stb %o4,[%o1] ! Store last byte -- should not be needed
LDPTR [%o3 + %lo(CPCB)], %o3
membar #Sync
STPTR %g0, [%o3 + PCB_ONFAULT]
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore ASI
retl
clr %o0 ! return 0
ENTRY(copyout)
#ifdef NOTDEF_DEBUG
save %sp, -CC64FSZ, %sp
set 1f, %o0
mov %i0, %o1
set CTX_SECONDARY, %o4
mov %i1, %o2
ldxa [%o4] ASI_DMMU, %o4
call printf
mov %i2, %o3
restore
.data
1: .asciz "copyout: src=%x dest=%x len=%x ctx=%d\n"
_ALIGN
.text
#endif
Ldocopy:
sethi %hi(CPCB), %o3
wr %g0, ASI_AIUS, %asi
LDPTR [%o3 + %lo(CPCB)], %o3
set Lcopyfault, %o4
! mov %o7, %g7 ! save return address
membar #Sync
STPTR %o4, [%o3 + PCB_ONFAULT]
cmp %o2, BCOPY_SMALL
Lcopyout_start:
membar #StoreStore
bge,a Lcopyout_fancy ! if >= this many, go be fancy.
btst 7, %o0 ! (part of being fancy)
deccc %o2 ! while (--len >= 0)
bl 1f
.empty
0:
inc %o0
ldsb [%o0 - 1], %o4 ! (++dst)[-1] = *src++;
stba %o4, [%o1] %asi
deccc %o2
bge 0b
inc %o1
1:
ba Lcopyout_done
clr %o0
NOTREACHED
Lcopyout_fancy:
! check for common case first: everything lines up.
! btst 7, %o0 ! done already
bne 1f
.empty
btst 7, %o1
be,a Lcopyout_doubles
dec 8, %o2 ! if all lined up, len -= 8, goto copyout_doubes
! If the low bits match, we can make these line up.
1:
xor %o0, %o1, %o3 ! t = src ^ dst;
btst 1, %o3 ! if (t & 1) {
be,a 1f
btst 1, %o0 ! [delay slot: if (src & 1)]
! low bits do not match, must copy by bytes.
0:
ldsb [%o0], %o4 ! do {
inc %o0 ! (++dst)[-1] = *src++;
inc %o1
deccc %o2
bnz 0b ! } while (--len != 0);
stba %o4, [%o1 - 1] %asi
ba Lcopyout_done
clr %o0
NOTREACHED
! lowest bit matches, so we can copy by words, if nothing else
1:
be,a 1f ! if (src & 1) {
btst 2, %o3 ! [delay slot: if (t & 2)]
! although low bits match, both are 1: must copy 1 byte to align
ldsb [%o0], %o4 ! *dst++ = *src++;
stba %o4, [%o1] %asi
inc %o0
inc %o1
dec %o2 ! len--;
btst 2, %o3 ! } [if (t & 2)]
1:
be,a 1f ! if (t & 2) {
btst 2, %o0 ! [delay slot: if (src & 2)]
dec 2, %o2 ! len -= 2;
0:
ldsh [%o0], %o4 ! do {
stha %o4, [%o1] %asi ! *(short *)dst = *(short *)src;
inc 2, %o0 ! dst += 2, src += 2;
deccc 2, %o2 ! } while ((len -= 2) >= 0);
bge 0b
inc 2, %o1
b Lcopyout_mopb ! goto mop_up_byte;
btst 1, %o2 ! } [delay slot: if (len & 1)]
NOTREACHED
! low two bits match, so we can copy by longwords
1:
be,a 1f ! if (src & 2) {
btst 4, %o3 ! [delay slot: if (t & 4)]
! although low 2 bits match, they are 10: must copy one short to align
ldsh [%o0], %o4 ! (*short *)dst = *(short *)src;
stha %o4, [%o1] %asi
inc 2, %o0 ! dst += 2;
inc 2, %o1 ! src += 2;
dec 2, %o2 ! len -= 2;
btst 4, %o3 ! } [if (t & 4)]
1:
be,a 1f ! if (t & 4) {
btst 4, %o0 ! [delay slot: if (src & 4)]
dec 4, %o2 ! len -= 4;
0:
lduw [%o0], %o4 ! do {
sta %o4, [%o1] %asi ! *(int *)dst = *(int *)src;
inc 4, %o0 ! dst += 4, src += 4;
deccc 4, %o2 ! } while ((len -= 4) >= 0);
bge 0b
inc 4, %o1
b Lcopyout_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! } [delay slot: if (len & 2)]
NOTREACHED
! low three bits match, so we can copy by doublewords
1:
be 1f ! if (src & 4) {
dec 8, %o2 ! [delay slot: len -= 8]
lduw [%o0], %o4 ! *(int *)dst = *(int *)src;
sta %o4, [%o1] %asi
inc 4, %o0 ! dst += 4, src += 4, len -= 4;
inc 4, %o1
dec 4, %o2 ! }
1:
Lcopyout_doubles:
ldx [%o0], %g1 ! do {
stxa %g1, [%o1] %asi ! *(double *)dst = *(double *)src;
inc 8, %o0 ! dst += 8, src += 8;
deccc 8, %o2 ! } while ((len -= 8) >= 0);
bge Lcopyout_doubles
inc 8, %o1
! check for a usual case again (save work)
btst 7, %o2 ! if ((len & 7) == 0)
be Lcopyout_done ! goto copyout_done;
btst 4, %o2 ! if ((len & 4)) == 0)
be,a Lcopyout_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! [delay slot: if (len & 2)]
lduw [%o0], %o4 ! *(int *)dst = *(int *)src;
sta %o4, [%o1] %asi
inc 4, %o0 ! dst += 4;
inc 4, %o1 ! src += 4;
btst 2, %o2 ! } [if (len & 2)]
1:
! mop up trailing word (if present) and byte (if present).
Lcopyout_mopw:
be Lcopyout_mopb ! no word, go mop up byte
btst 1, %o2 ! [delay slot: if (len & 1)]
ldsh [%o0], %o4 ! *(short *)dst = *(short *)src;
be Lcopyout_done ! if ((len & 1) == 0) goto done;
stha %o4, [%o1] %asi
ldsb [%o0 + 2], %o4 ! dst[2] = src[2];
stba %o4, [%o1 + 2] %asi
ba Lcopyout_done
clr %o0
NOTREACHED
! mop up trailing byte (if present).
Lcopyout_mopb:
be,a Lcopyout_done
nop
ldsb [%o0], %o4
stba %o4, [%o1] %asi
Lcopyout_done:
sethi %hi(CPCB), %o3
LDPTR [%o3 + %lo(CPCB)], %o3
membar #Sync
STPTR %g0, [%o3 + PCB_ONFAULT]
! jmp %g7 + 8 ! Original instr
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore ASI
membar #StoreStore|#StoreLoad
retl ! New instr
clr %o0 ! return 0
! Copyin or copyout fault. Clear cpcb->pcb_onfault and return error.
! Note that although we were in memcpy, there is no state to clean up;
! the only special thing is that we have to return to [g7 + 8] rather than
! [o7 + 8].
Lcopyfault:
sethi %hi(CPCB), %o3
LDPTR [%o3 + %lo(CPCB)], %o3
STPTR %g0, [%o3 + PCB_ONFAULT]
membar #StoreStore|#StoreLoad
#ifdef NOTDEF_DEBUG
save %sp, -CC64FSZ, %sp
set 1f, %o0
call printf
nop
restore
.data
1: .asciz "copyfault: fault occurred\n"
_ALIGN
.text
#endif
retl
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore ASI
ENTRY(_ucas_32)
sethi %hi(CPCB), %o4
wr %g0, ASI_AIUS, %asi
LDPTR [%o4 + %lo(CPCB)], %o4
set Lcopyfault, %o5 ! reusing copyin/copyout
membar #Sync ! fault handler
STPTR %o5, [%o4 + PCB_ONFAULT]
casa [%o0] %asi, %o1, %o2 ! cas, result in %o2
sethi %hi(CPCB), %o4
LDPTR [%o4 + %lo(CPCB)], %o4
membar #Sync
STPTR %g0, [%o4 + PCB_ONFAULT]
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore ASI
membar #StoreStore|#StoreLoad
stw %o2, [%o3] ! store the cas result in *result
retl
clr %o0 ! return 0
#ifdef _LP64
ENTRY(_ucas_64)
sethi %hi(CPCB), %o4
wr %g0, ASI_AIUS, %asi
LDPTR [%o4 + %lo(CPCB)], %o4
set Lcopyfault, %o5 ! reusing copyin/copyout
membar #Sync ! fault handler
STPTR %o5, [%o4 + PCB_ONFAULT]
casxa [%o0] %asi, %o1, %o2 ! cas, result in %o2
sethi %hi(CPCB), %o4
LDPTR [%o4 + %lo(CPCB)], %o4
membar #Sync
STPTR %g0, [%o4 + PCB_ONFAULT]
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore ASI
membar #StoreStore|#StoreLoad
stx %o2, [%o3] ! store the cas result in *result
retl
clr %o0 ! return 0
#endif
#define UFETCHSTORE_PROLOGUE \
sethi %hi(CPCB), %o2 ;\
LDPTR [%o2 + %lo(CPCB)], %o2 ;\
set Lufetchstore_fault, %o3 ;\
STPTR %o3, [%o2 + PCB_ONFAULT] ;\
membar #Sync
#define _UFETCHSTORE_EPILOGUE \
STPTR %g0, [%o2 + PCB_ONFAULT] ;\
membar #StoreStore|#StoreLoad
#define UFETCHSTORE_EPILOGUE \
membar #Sync ;\
_UFETCHSTORE_EPILOGUE
#define UFETCHSTORE_RETURN_SUCCESS \
retl ;\
clr %o0
ENTRY(_ufetch_8)
UFETCHSTORE_PROLOGUE
lduba [%o0] ASI_AIUS, %o0 ! %o0 = *uaddr
UFETCHSTORE_EPILOGUE
stb %o0, [%o1] ! *valp = %o0
UFETCHSTORE_RETURN_SUCCESS
ENTRY(_ufetch_16)
UFETCHSTORE_PROLOGUE
lduha [%o0] ASI_AIUS, %o0 ! %o0 = *uaddr
UFETCHSTORE_EPILOGUE
sth %o0, [%o1] ! *valp = %o0
UFETCHSTORE_RETURN_SUCCESS
ENTRY(_ufetch_32)
UFETCHSTORE_PROLOGUE
lduwa [%o0] ASI_AIUS, %o0 ! %o0 = *uaddr
UFETCHSTORE_EPILOGUE
stw %o0, [%o1] ! *valp = %o0
UFETCHSTORE_RETURN_SUCCESS
#ifdef _LP64
ENTRY(_ufetch_64)
UFETCHSTORE_PROLOGUE
ldxa [%o0] ASI_AIUS, %o0 ! %o0 = *uaddr
UFETCHSTORE_EPILOGUE
stx %o0, [%o1] ! *valp = %o0
UFETCHSTORE_RETURN_SUCCESS
#endif
ENTRY(_ustore_8)
UFETCHSTORE_PROLOGUE
stba %o1, [%o0] ASI_AIUS ! *uaddr = val
UFETCHSTORE_EPILOGUE
UFETCHSTORE_RETURN_SUCCESS
ENTRY(_ustore_16)
UFETCHSTORE_PROLOGUE
stha %o1, [%o0] ASI_AIUS ! *uaddr = val
UFETCHSTORE_EPILOGUE
UFETCHSTORE_RETURN_SUCCESS
ENTRY(_ustore_32)
UFETCHSTORE_PROLOGUE
stwa %o1, [%o0] ASI_AIUS ! *uaddr = val
UFETCHSTORE_EPILOGUE
UFETCHSTORE_RETURN_SUCCESS
#ifdef _LP64
ENTRY(_ustore_64)
UFETCHSTORE_PROLOGUE
stxa %o1, [%o0] ASI_AIUS ! *uaddr = val
UFETCHSTORE_EPILOGUE
UFETCHSTORE_RETURN_SUCCESS
#endif
Lufetchstore_fault:
_UFETCHSTORE_EPILOGUE ! (won't fit in delay slot)
retl
nop ! error already in %o0
ENTRY(probeget)
#ifndef _LP64
!! Shuffle the args around into LP64 format
COMBINE(%o0, %o1, %o0)
mov %o2, %o1
mov %o3, %o2
#endif
mov %o2, %o4
! %o0 = addr, %o1 = asi, %o4 = (1,2,4)
sethi %hi(CPCB), %o2
LDPTR [%o2 + %lo(CPCB)], %o2 ! cpcb->pcb_onfault = Lfsbail;
#ifdef _LP64
set _C_LABEL(Lfsbail), %o5
#else
set _C_LABEL(Lfsprobe), %o5
#endif
STPTR %o5, [%o2 + PCB_ONFAULT]
or %o0, 0x9, %o3 ! if (PHYS_ASI(asi)) {
sub %o3, 0x1d, %o3
brz,a %o3, 0f
mov %g0, %o5
DLFLUSH(%o0,%o5) ! flush cache line
! }
0:
#ifndef _LP64
rdpr %pstate, %g1
wrpr %g1, PSTATE_AM, %pstate
#endif
btst 1, %o4
wr %o1, 0, %asi
membar #Sync
bz 0f ! if (len & 1)
btst 2, %o4
ba,pt %icc, 1f
lduba [%o0] %asi, %o0 ! value = *(char *)addr;
0:
bz 0f ! if (len & 2)
btst 4, %o4
ba,pt %icc, 1f
lduha [%o0] %asi, %o0 ! value = *(short *)addr;
0:
bz 0f ! if (len & 4)
btst 8, %o4
ba,pt %icc, 1f
lda [%o0] %asi, %o0 ! value = *(int *)addr;
0:
ldxa [%o0] %asi, %o0 ! value = *(long *)addr;
1:
#ifndef _LP64
SPLIT(%o0, %o0, %o1)
#endif
membar #Sync
#ifndef _LP64
wrpr %g1, 0, %pstate
#endif
brz %o5, 1f ! if (cache flush addr != 0)
nop
DLFLUSH2(%o5) ! flush cache line again
1:
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI
STPTR %g0, [%o2 + PCB_ONFAULT]
retl ! made it, clear onfault and return
membar #StoreStore|#StoreLoad
_C_LABEL(Lfsprobe):
#ifndef _LP64
wrpr %g1, 0, %pstate
#endif
STPTR %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
mov -1, %o1
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI
membar #StoreStore|#StoreLoad
retl ! and return error indicator
mov -1, %o0
.globl _C_LABEL(Lfsbail)
_C_LABEL(Lfsbail):
STPTR %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
membar #StoreStore|#StoreLoad
#ifndef _LP64
mov -1, %o1
#endif
retl ! and return error indicator
mov -1, %o0
ENTRY(probeset)
#ifndef _LP64
!! Shuffle the args around into LP64 format
COMBINE(%o0, %o1, %o0)
mov %o2, %o1
mov %o3, %o2
COMBINE(%o4, %o5, %o3)
#endif
mov %o2, %o4
! %o0 = addr, %o1 = asi, %o4 = (1,2,4), %o3 = val
sethi %hi(CPCB), %o2 ! Lfsbail requires CPCB in %o2
LDPTR [%o2 + %lo(CPCB)], %o2 ! cpcb->pcb_onfault = Lfsbail;
set _C_LABEL(Lfsbail), %o5
STPTR %o5, [%o2 + PCB_ONFAULT]
btst 1, %o4
wr %o1, 0, %asi
membar #Sync
bz 0f ! if (len & 1)
btst 2, %o4
ba,pt %icc, 1f
stba %o3, [%o0] %asi ! *(char *)addr = value;
0:
bz 0f ! if (len & 2)
btst 4, %o4
ba,pt %icc, 1f
stha %o3, [%o0] %asi ! *(short *)addr = value;
0:
bz 0f ! if (len & 4)
btst 8, %o4
ba,pt %icc, 1f
sta %o3, [%o0] %asi ! *(int *)addr = value;
0:
bz Lfsbail ! if (len & 8)
ba,pt %icc, 1f
sta %o3, [%o0] %asi ! *(int *)addr = value;
1: membar #Sync
clr %o0 ! made it, clear onfault and return 0
wr %g0, ASI_PRIMARY_NOFAULT, %asi ! Restore default ASI
STPTR %g0, [%o2 + PCB_ONFAULT]
retl
membar #StoreStore|#StoreLoad
ENTRY(kcopy)
#ifdef DEBUG
set pmapdebug, %o4
ld [%o4], %o4
btst 0x80, %o4 ! PDB_COPY
bz,pt %icc, 3f
nop
save %sp, -CC64FSZ, %sp
mov %i0, %o1
set 2f, %o0
mov %i1, %o2
call printf
mov %i2, %o3
! ta 1; nop
restore
.data
2: .asciz "kcopy(%p->%p,%x)\n"
_ALIGN
.text
3:
#endif
sethi %hi(CPCB), %o5 ! cpcb->pcb_onfault = Lkcerr;
LDPTR [%o5 + %lo(CPCB)], %o5
set Lkcerr, %o3
LDPTR [%o5 + PCB_ONFAULT], %g1! save current onfault handler
membar #LoadStore
STPTR %o3, [%o5 + PCB_ONFAULT]
membar #StoreStore|#StoreLoad
cmp %o2, BCOPY_SMALL
Lkcopy_start:
bge,a Lkcopy_fancy ! if >= this many, go be fancy.
btst 7, %o0 ! (part of being fancy)
deccc %o2 ! while (--len >= 0)
bl 1f
.empty
0:
ldsb [%o0], %o4 ! *dst++ = *src++;
inc %o0
stb %o4, [%o1]
deccc %o2
bge 0b
inc %o1
1:
membar #Sync ! Make sure all fauls are processed
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
membar #StoreStore|#StoreLoad
retl
clr %o0
NOTREACHED
Lkcopy_fancy:
! check for common case first: everything lines up.
! btst 7, %o0 ! done already
bne 1f
.empty
btst 7, %o1
be,a Lkcopy_doubles
dec 8, %o2 ! if all lined up, len -= 8, goto kcopy_doubes
! If the low bits match, we can make these line up.
1:
xor %o0, %o1, %o3 ! t = src ^ dst;
btst 1, %o3 ! if (t & 1) {
be,a 1f
btst 1, %o0 ! [delay slot: if (src & 1)]
! low bits do not match, must copy by bytes.
0:
ldsb [%o0], %o4 ! do {
inc %o0 ! *dst++ = *src++;
stb %o4, [%o1]
deccc %o2
bnz 0b ! } while (--len != 0);
inc %o1
membar #Sync ! Make sure all traps are taken
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
membar #StoreStore|#StoreLoad
retl
clr %o0
NOTREACHED
! lowest bit matches, so we can copy by words, if nothing else
1:
be,a 1f ! if (src & 1) {
btst 2, %o3 ! [delay slot: if (t & 2)]
! although low bits match, both are 1: must copy 1 byte to align
ldsb [%o0], %o4 ! *dst++ = *src++;
inc %o0
stb %o4, [%o1]
dec %o2 ! len--;
inc %o1
btst 2, %o3 ! } [if (t & 2)]
1:
be,a 1f ! if (t & 2) {
btst 2, %o0 ! [delay slot: if (src & 2)]
dec 2, %o2 ! len -= 2;
0:
ldsh [%o0], %o4 ! do {
inc 2, %o0 ! dst += 2, src += 2;
sth %o4, [%o1] ! *(short *)dst = *(short *)src;
deccc 2, %o2 ! } while ((len -= 2) >= 0);
bge 0b
inc 2, %o1
b Lkcopy_mopb ! goto mop_up_byte;
btst 1, %o2 ! } [delay slot: if (len & 1)]
NOTREACHED
! low two bits match, so we can copy by longwords
1:
be,a 1f ! if (src & 2) {
btst 4, %o3 ! [delay slot: if (t & 4)]
! although low 2 bits match, they are 10: must copy one short to align
ldsh [%o0], %o4 ! (*short *)dst = *(short *)src;
inc 2, %o0 ! dst += 2;
sth %o4, [%o1]
dec 2, %o2 ! len -= 2;
inc 2, %o1 ! src += 2;
btst 4, %o3 ! } [if (t & 4)]
1:
be,a 1f ! if (t & 4) {
btst 4, %o0 ! [delay slot: if (src & 4)]
dec 4, %o2 ! len -= 4;
0:
ld [%o0], %o4 ! do {
inc 4, %o0 ! dst += 4, src += 4;
st %o4, [%o1] ! *(int *)dst = *(int *)src;
deccc 4, %o2 ! } while ((len -= 4) >= 0);
bge 0b
inc 4, %o1
b Lkcopy_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! } [delay slot: if (len & 2)]
NOTREACHED
! low three bits match, so we can copy by doublewords
1:
be 1f ! if (src & 4) {
dec 8, %o2 ! [delay slot: len -= 8]
ld [%o0], %o4 ! *(int *)dst = *(int *)src;
inc 4, %o0 ! dst += 4, src += 4, len -= 4;
st %o4, [%o1]
dec 4, %o2 ! }
inc 4, %o1
1:
Lkcopy_doubles:
ldx [%o0], %g5 ! do {
inc 8, %o0 ! dst += 8, src += 8;
stx %g5, [%o1] ! *(double *)dst = *(double *)src;
deccc 8, %o2 ! } while ((len -= 8) >= 0);
bge Lkcopy_doubles
inc 8, %o1
! check for a usual case again (save work)
btst 7, %o2 ! if ((len & 7) == 0)
be Lkcopy_done ! goto kcopy_done;
btst 4, %o2 ! if ((len & 4)) == 0)
be,a Lkcopy_mopw ! goto mop_up_word_and_byte;
btst 2, %o2 ! [delay slot: if (len & 2)]
ld [%o0], %o4 ! *(int *)dst = *(int *)src;
inc 4, %o0 ! dst += 4;
st %o4, [%o1]
inc 4, %o1 ! src += 4;
btst 2, %o2 ! } [if (len & 2)]
1:
! mop up trailing word (if present) and byte (if present).
Lkcopy_mopw:
be Lkcopy_mopb ! no word, go mop up byte
btst 1, %o2 ! [delay slot: if (len & 1)]
ldsh [%o0], %o4 ! *(short *)dst = *(short *)src;
be Lkcopy_done ! if ((len & 1) == 0) goto done;
sth %o4, [%o1]
ldsb [%o0 + 2], %o4 ! dst[2] = src[2];
stb %o4, [%o1 + 2]
membar #Sync ! Make sure all traps are taken
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
membar #StoreStore|#StoreLoad
retl
clr %o0
NOTREACHED
! mop up trailing byte (if present).
Lkcopy_mopb:
bne,a 1f
ldsb [%o0], %o4
Lkcopy_done:
membar #Sync ! Make sure all traps are taken
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
membar #StoreStore|#StoreLoad
retl
clr %o0
NOTREACHED
1:
stb %o4, [%o1]
membar #Sync ! Make sure all traps are taken
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
membar #StoreStore|#StoreLoad
retl
clr %o0
NOTREACHED
Lkcerr:
#ifdef DEBUG
set pmapdebug, %o4
ld [%o4], %o4
btst 0x80, %o4 ! PDB_COPY
bz,pt %icc, 3f
nop
save %sp, -CC64FSZ, %sp
set 2f, %o0
call printf
nop
! ta 1; nop
restore
.data
2: .asciz "kcopy error\n"
_ALIGN
.text
3:
#endif
STPTR %g1, [%o5 + PCB_ONFAULT]! restore fault handler
retl ! and return error indicator
membar #StoreStore|#StoreLoad
NOTREACHED