#include "opt_m68k_arch.h"
#include <sys/errno.h>
#include <machine/asm.h>
#include "assym.h"
.file "copy.s"
.text
#ifdef CI_CURPCB
#define GETCURPCB(r) movl _C_LABEL(cpu_info_store)+CI_CURPCB,r
#else
#define GETCURPCB(r) movl _C_LABEL(curpcb),r
#endif
#ifdef DIAGNOSTIC
.Lbadfc:
PANIC("copy.s: bad sfc or dfc")
jra .Lbadfc
#define CHECK_SFC movec %sfc,%d0; subql #FC_USERD,%d0; bne .Lbadfc
#define CHECK_DFC movec %dfc,%d0; subql #FC_USERD,%d0; bne .Lbadfc
#else
#define CHECK_SFC
#define CHECK_DFC
#endif
ENTRY(copyin)
CHECK_SFC
movl 12(%sp),%d0 | check count
jeq .Lciret | == 0, don't do anything
movl %d2,-(%sp) | save scratch register
GETCURPCB(%a0) | set fault handler
movl #.Lcifault,PCB_ONFAULT(%a0)
movl 8(%sp),%a0 | src address
movl 12(%sp),%a1 | dest address
movl %a0,%d1
btst #0,%d1 | src address odd?
jeq .Lcieven | no, skip alignment
movsb (%a0)+,%d2 | yes, copy a byte
movb %d2,(%a1)+
subql #1,%d0 | adjust count
jeq .Lcidone | count 0, all done
.Lcieven:
movl %a1,%d1
btst #0,%d1 | dest address odd?
jne .Lcibytes | yes, must copy bytes
movl %d0,%d1 | OK, both even. Get count
lsrl #2,%d1 | and convert to longwords
jeq .Lcibytes | count 0, skip longword loop
subql #1,%d1 | predecrement for dbf
.Lcilloop:
movsl (%a0)+,%d2 | copy a longword
movl %d2,(%a1)+
dbf %d1,.Lcilloop | decrement low word of count
subil #0x10000,%d1 | decrement high word of count
jcc .Lcilloop
andl #3,%d0 | what remains
jeq .Lcidone | nothing, all done
.Lcibytes:
subql #1,%d0 | predecrement for dbf
.Lcibloop:
movsb (%a0)+,%d2 | copy a byte
movb %d2,(%a1)+
dbf %d0,.Lcibloop | decrement low word of count
subil #0x10000,%d0 | decrement high word of count
jcc .Lcibloop
clrl %d0 | no error
.Lcidone:
GETCURPCB(%a0) | clear fault handler
clrl PCB_ONFAULT(%a0)
movl (%sp)+,%d2 | restore scratch register
.Lciret:
rts
.Lcifault:
jra .Lcidone
ENTRY(copyout)
CHECK_DFC
movl 12(%sp),%d0 | check count
jeq .Lcoret | == 0, don't do anything
movl %d2,-(%sp) | save scratch register
GETCURPCB(%a0) | set fault handler
movl #.Lcofault,PCB_ONFAULT(%a0)
movl 8(%sp),%a0 | src address
movl 12(%sp),%a1 | dest address
movl %a0,%d1
btst #0,%d1 | src address odd?
jeq .Lcoeven | no, skip alignment
movb (%a0)+,%d2 | yes, copy a byte
movsb %d2,(%a1)+
subql #1,%d0 | adjust count
jeq .Lcodone | count 0, all done
.Lcoeven:
movl %a1,%d1
btst #0,%d1 | dest address odd?
jne .Lcobytes | yes, must copy bytes
movl %d0,%d1 | OK, both even. Get count
lsrl #2,%d1 | and convert to longwords
jeq .Lcobytes | count 0, skip longword loop
subql #1,%d1 | predecrement for dbf
.Lcolloop:
movl (%a0)+,%d2 | copy a longword
movsl %d2,(%a1)+
dbf %d1,.Lcolloop | decrement low word of count
subil #0x10000,%d1 | decrement high word of count
jcc .Lcolloop
andl #3,%d0 | what remains
jeq .Lcodone | nothing, all done
.Lcobytes:
subql #1,%d0 | predecrement for dbf
.Lcobloop:
movb (%a0)+,%d2 | copy a byte
movsb %d2,(%a1)+
dbf %d0,.Lcobloop | decrement low word of count
subil #0x10000,%d0 | decrement high word of count
jcc .Lcobloop
clrl %d0 | no error
.Lcodone:
GETCURPCB(%a0) | clear fault handler
clrl PCB_ONFAULT(%a0)
movl (%sp)+,%d2 | restore scratch register
.Lcoret:
rts
.Lcofault:
jra .Lcodone
ENTRY(copyinstr)
CHECK_SFC
GETCURPCB(%a0) | set fault handler
movl #.Lcisfault,PCB_ONFAULT(%a0)
movl 4(%sp),%a0 | a0 = fromaddr
movl 8(%sp),%a1 | a1 = toaddr
clrl %d0
movl 12(%sp),%d1 | count
jeq .Lcistoolong | nothing to copy
subql #1,%d1 | predecrement for dbeq
.Lcisloop:
movsb (%a0)+,%d0 | copy a byte
movb %d0,(%a1)+
dbeq %d1,.Lcisloop | decrement low word of count
jeq .Lcisdone | copied null, exit
subil #0x10000,%d1 | decrement high word of count
jcc .Lcisloop | more room, keep going
.Lcistoolong:
moveq #ENAMETOOLONG,%d0 | ran out of space
.Lcisdone:
tstl 16(%sp) | length desired?
jeq .Lcisexit
subl 4(%sp),%a0 | yes, calculate length copied
movl 16(%sp),%a1 | store at return location
movl %a0,(%a1)
.Lcisexit:
GETCURPCB(%a0) | clear fault handler
clrl PCB_ONFAULT(%a0)
rts
.Lcisfault:
jra .Lcisdone
ENTRY(copyoutstr)
CHECK_DFC
GETCURPCB(%a0) | set fault handler
movl #.Lcosfault,PCB_ONFAULT(%a0)
movl 4(%sp),%a0 | a0 = fromaddr
movl 8(%sp),%a1 | a1 = toaddr
clrl %d0
movl 12(%sp),%d1 | count
jeq .Lcostoolong | nothing to copy
subql #1,%d1 | predecrement for dbeq
.Lcosloop:
movb (%a0)+,%d0 | copy a byte
movsb %d0,(%a1)+
dbeq %d1,.Lcosloop | decrement low word of count
jeq .Lcosdone | copied null, exit
subil #0x10000,%d1 | decrement high word of count
jcc .Lcosloop | more room, keep going
.Lcostoolong:
moveq #ENAMETOOLONG,%d0 | ran out of space
.Lcosdone:
tstl 16(%sp) | length desired?
jeq .Lcosexit
subl 4(%sp),%a0 | yes, calculate length copied
movl 16(%sp),%a1 | store at return location
movl %a0,(%a1)
.Lcosexit:
GETCURPCB(%a0) | clear fault handler
clrl PCB_ONFAULT(%a0)
rts
.Lcosfault:
jra .Lcosdone
ENTRY(kcopy)
link %a6,#-4
GETCURPCB(%a0) | set fault handler
movl PCB_ONFAULT(%a0),-4(%a6) | save old handler first
movl #.Lkcfault,PCB_ONFAULT(%a0)
movl 16(%a6),-(%sp) | push len
movl 8(%a6),-(%sp) | push src
movl 12(%a6),-(%sp) | push dst
jbsr _C_LABEL(memcpy) | copy it
addl #12,%sp | pop args
clrl %d0 | success!
.Lkcdone:
GETCURPCB(%a0) | restore fault handler
movl -4(%a6),PCB_ONFAULT(%a0)
unlk %a6
rts
.Lkcfault:
addl #16,%sp | pop args and return address
jra .Lkcdone
#define UFETCH_PROLOGUE \
CHECK_SFC ; \
movl 4(%sp),%a0 ; \
GETCURPCB(%a1) ; \
movl #.Lufetchstore_fault,PCB_ONFAULT(%a1)
ENTRY(_ufetch_8)
UFETCH_PROLOGUE
movsb (%a0),%d0 | do read from user space
movl 8(%sp),%a0 | destination address
movb %d0,(%a0)
jra .Lufetchstore_success
ENTRY(_ufetch_16)
UFETCH_PROLOGUE
movsw (%a0),%d0 | do read from user space
movl 8(%sp),%a0 | destination address
movw %d0,(%a0)
jra .Lufetchstore_success
ENTRY(_ufetch_32)
UFETCH_PROLOGUE
movsl (%a0),%d0 | do read from user space
movl 8(%sp),%a0 | destination address
movl %d0,(%a0)
jra .Lufetchstore_success
#define USTORE_PROLOGUE \
CHECK_DFC ; \
movl 4(%sp),%a0 ; \
GETCURPCB(%a1) ; \
movl #.Lufetchstore_fault,PCB_ONFAULT(%a1)
ENTRY(_ustore_8)
USTORE_PROLOGUE
movb 11(%sp),%d0 | value to store
movsb %d0,(%a0) | do write to user space
jra .Lufetchstore_success
ENTRY(_ustore_16)
USTORE_PROLOGUE
movw 10(%sp),%d0 | value to store
movsw %d0,(%a0) | do write to user space
jra .Lufetchstore_success
ENTRY(_ustore_32)
USTORE_PROLOGUE
movl 8(%sp),%d0 | value to store
movsl %d0,(%a0) | do write to user space
jra .Lufetchstore_success
.Lufetchstore_success:
clrl %d0 | return 0
.Lufetchstore_fault:
clrl PCB_ONFAULT(%a1) | clear fault handler
rts
#if defined(M68040) || defined(M68060)
ENTRY(suline)
CHECK_DFC
movl 4(%sp),%a0 | address to write
GETCURPCB(%a1) | current pcb
movl .Lsuline_fault,PCB_ONFAULT(%a1) | fault handler
movl 8(%sp),%a1 | address of line data
movl (%a1)+,%d0 | get lword
movsl %d0,(%a0)+ | put lword
nop
movl (%a1)+,%d0 | get lword
movsl %d0,(%a0)+ | put lword
nop
movl (%a1)+,%d0 | get lword
movsl %d0,(%a0)+ | put lword
nop
movl (%a1)+,%d0 | get lword
movsl %d0,(%a0)+ | put lword
nop
moveq #0,%d0 | return 0 for success
1: GETCURPCB(%a1) | current pcb
clrl PCB_ONFAULT(%a1) | clear fault handler
rts
.Lsuline_fault:
moveq #-1,%d0 | return -1 for error
jra 1b
#endif