2.11BSD/sys/pdp/mch_copy.s
/*
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)mch_copy.s 1.3 (2.11BSD GTE) 1/9/94
*/
#include "DEFS.h"
#include "../machine/mch_iopage.h"
/*
* Fetch and set user byte routines:
* fubyte(addr): fetch user data space byte
* fuibyte(addr): fetch user instruction space byte
* subyte(addr, byte): set user data space byte
* suibyte(addr, byte): set user instruction space byte
* caddr_t addr;
* u_char byte;
*
* The fetch routines return the requested byte or -1 on fault. The set
* routines return 0 on success, -1 on failure. The data space routines are
* really the corresponding instruction space routines if NONSEPARATE is
* defined.
*/
ENTRY(fubyte)
#ifndef NONSEPARATE
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1
bic $1,r1 / r1 = addr&~1
mfpd (r1) / tmp = user data word at (addr&~1)
mov (sp)+,r0
cmp r1,4(sp) / if (addr&1)
beq 1f / tmp >>= 8
swab r0
1:
bic $!377,r0 / return((u_char)tmp)
mov (sp)+,nofault / restore fault trap, and return
rts pc
#endif !NONSEPARATE
ENTRY(fuibyte)
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1
bic $1,r1 / r1 = addr&~1
mfpi (r1) / tmp = user instruction word at
mov (sp)+,r0 / (addr&~1)
cmp r1,4(sp) / if (addr&1)
beq 1f / tmp >>= 8
swab r0
1:
bic $!377,r0 / return((u_char)tmp)
mov (sp)+,nofault / restore fault trap, and return
rts pc
ENTRY(subyte)
#ifndef NONSEPARATE
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1
bic $1,r1 / r1 = addr&~1
mfpd (r1) / tmp = user data word at (addr&~1)
cmp r1,6(sp) / if (addr&1)
beq 1f
movb 10(sp),1(sp) / *((char *)tmp + 1) = byte
br 2f
1: / else
movb 10(sp),(sp) / *((char *)tmp) = byte
2:
mtpd (r1) / user data word (addr&~1) = tmp
clr r0 / return success
mov (sp)+,nofault / restore fault trap, and return
rts pc
#endif !NONSEPARATE
ENTRY(suibyte)
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1
bic $1,r1 / r1 = addr&~1
mfpi (r1) / tmp = user instruction word at
cmp r1,6(sp) / (addr&~1)
beq 1f / if (addr&1)
movb 10(sp),1(sp) / *((char *)tmp + 1) = byte
br 2f
1: / else
movb 10(sp),(sp) / *((char *)tmp) = byte
2:
mtpi (r1) / user instruction word (addr&~1) = tmp
clr r0 / return success
mov (sp)+,nofault / restore fault trap, and return
rts pc
/*
* Fetch and set user word routines:
* fuiword(addr): fetch user instruction space word
* fuword(addr): fetch user data space word
* suiword(addr, word): set user instruction space word
* suword(addr, word): set user data space word
* caddr_t addr;
* u_short word;
*
* The fetch routines return the requested word or -1 on fault. The set
* routines return 0 on success, -1 on failure. Addr must be even. The data
* space routines are really the corresponding instruction space routines if
* NONSEPARATE is defined.
*/
ENTRY(fuword)
#ifndef NONSEPARATE
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1 / r1 = addr
mfpd (r1) / r0 = user data word at addr
mov (sp)+,r0
mov (sp)+,nofault / restore fault trap, and return
rts pc
#endif !NONSEPARATE
ENTRY(fuiword)
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1 / r1 = addr
mfpi (r1) / r0 = user instruction word at addr
mov (sp)+,r0
mov (sp)+,nofault / restore fault trap, and return
rts pc
ENTRY(suword)
#ifndef NONSEPARATE
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1 / r1 = addr
mov 6(sp),-(sp) / user data word at addr = word
mtpd (r1)
clr r0 / resturn success
mov (sp)+,nofault / restore fault trap, and return
rts pc
#endif !NONSEPARATE
ENTRY(suiword)
mov nofault,-(sp) / set fault trap
mov $fsfault,nofault
mov 4(sp),r1 / r1 = adddr
mov 6(sp),-(sp) / user instruction word at addr = word
mtpi (r1)
clr r0 / return success
mov (sp)+,nofault / restore fault trap, and return
rts pc
/*
* Common fault trap for fetch/set user byte/word routines. Returns -1 to
* indicate fault. Stack contains saved fault trap followed by return
* address.
*/
fsfault:
mov (sp)+,nofault / restore fault trap,
mov $-1,r0 / return failure (-1)
rts pc
/*
* copyin(fromaddr, toaddr, length)
* caddr_t fromaddr, toaddr;
* u_int length;
*
* copyiin(fromaddr, toaddr, length)
* caddr_t fromaddr, toaddr;
* u_int length;
*
* Copy length/2 words from user space fromaddr to kernel space address
* toaddr. Fromaddr and toaddr must be even. Returns zero on success,
* EFAULT on failure. Copyin copies from data space, copyiin from
* instruction space.
*/
ENTRY(copyin)
#ifndef NONSEPARATE
jsr pc,copysetup / r1 = fromaddr, r2 = toaddr,
1: / r0 = length/2
mfpd (r1)+ / do
mov (sp)+,(r2)+ / *toaddr++ = *fromaddr++
sob r0,1b / while (--length)
br copycleanup
#endif !NONSEPARATE
ENTRY(copyiin)
jsr pc,copysetup / r1 = fromaddr, r2 = toaddr,
1: / r0 = length/2
mfpi (r1)+ / do
mov (sp)+,(r2)+ / *toaddr++ = *fromaddr++
sob r0,1b / while (--length)
br copycleanup
/*
* copyout(fromaddr, toaddr, length)
* caddr_t fromaddr, toaddr;
* u_int length;
*
* copyiout(fromaddr, toaddr, length)
* caddr_t fromaddr, toaddr;
* u_int length;
*
* Copy length/2 words from kernel space fromaddr to user space address
* toaddr. Fromaddr and toaddr must be even. Returns zero on success,
* EFAULT on failure. Copyout copies to data space, copyiout to
* instruction space.
*/
ENTRY(copyout)
#ifndef NONSEPARATE
jsr pc,copysetup / r1 = fromaddr, r2 = toaddr,
1: / r0 = length/2
mov (r1)+,-(sp) / do
mtpd (r2)+ / *toaddr++ = *fromaddr++
sob r0,1b / while (--length)
br copycleanup
#endif !NONSEPARATE
ENTRY(copyiout)
jsr pc,copysetup / r1 = fromaddr, r2 = toaddr,
1: / r0 = length/2
mov (r1)+,-(sp) / do
mtpi (r2)+ / *toaddr++ = *fromaddr++
sob r0,1b / while (--length)
br copycleanup
/*
* Common set up code for the copy(in|out) routines. Performs zero length
* check, set up fault trap, and loads fromaddr, toaddr and length into the
* registers r1, r2 and r0 respectively. Leaves old values of r2 and
* nofault on stack.
*/
copysetup:
mov (sp)+,r0 / snag return address
mov r2,-(sp) / reserve r2 for our use,
mov nofault,-(sp) / save nofault so we can set our own
mov r0,-(sp) / trap and push return address back
mov $copyfault,nofault
mov 14(sp),r0 / r0 = (unsigned)length/2
beq 1f / (exit early if length equals zero)
asr r0
bic $100000,r0
mov 10(sp),r1 / r1 = fromaddr
mov 12(sp),r2 / r2 = toaddr
rts pc
1:
tst (sp)+ / short circuit the copy for zero
br copycleanup / length returning "success" ...
copyfault:
mov $EFAULT,r0 / we faulted out, return EFAULT
/*FALLTHROUGH*/
/*
* Common clean up code for the copy(in|out) routines. When copy routines
* finish successfully r0 has already been decremented to zero which is
* exactly what we want to return for success ... Tricky, hhmmm?
*/
copycleanup:
mov (sp)+,nofault / restore fault trap,
mov (sp)+,r2 / and reserved registers
rts pc
#ifdef INET
/*
* Kernel/Network copying routines.
*
* NOTE:
* The m[ft]sd functions operate at high ipl. This is done mostly
* because it's simpler to do a ``mov $10340,PS'' than ``bic $30000,PS;
* bis $10000,PS''. But these functions will never take up enough time
* to cause anyone any problems.
*
* WARNING:
* All functions assume that the segments in supervisor space
* containing the source or target variables are never remapped.
*
* void
* mtsd(addr, word)
* caddr_t addr; destination address in supervisor space
* int word word to store
*
* Move To Supervisor Data, simplified interface for the kernel to store
* single words in the supervisor data space.
*/
ENTRY(mtsd)
mov 2(sp),r0 / get the destination address
mov PS,-(sp) / save psw
mov $10340,PS / previous supervisor
mov 6(sp),-(sp) / grab word
mtpd (r0) / and store it in supervisor space
mov (sp)+,PS / restore psw
rts pc / return
/*
* int
* mfsd(addr)
* caddr_t addr; source address in supervisor space
*
* Move From Supervisor Data, simplified interface for the kernel to get
* single words from the supervisor data space.
*/
ENTRY(mfsd)
mov 2(sp),r0 / get the address of the data
mov PS,-(sp) / save psw
mov $10340,PS / previous supervisor
mfpd (r0) / get the word
mov (sp)+,r0 / return value
mov (sp)+,PS / restore psw
rts pc / return
#endif
/*
* error = vcopyin(fromaddr, toaddr, length)
* int error;
* caddr_t fromaddr, toaddr;
* u_int length;
*
* Copy length bytes from user address space fromaddr to kernel space toaddr.
* Returns zero on success, EFAULT on failure. Vcopyin is only called when
* fromaddr, toaddr or length is odd and the length doesn't justify an
* fmove.
*/
ENTRY(vcopyin)
mov r2,-(sp) / allocate a couple registers
mov r3,-(sp)
mov nofault,-(sp)
mov $5f,nofault / set up error trap
mov 10(sp),r1 / r1 = fromaddr (user address)
mov 12(sp),r2 / r2 = toaddr (kernel address)
mov 14(sp),r0 / r0 = length
beq 4f / (exit early if 0)
bit $1,r1 / fromaddr odd?
beq 1f
dec r1 / yes, grab the even word and snarf
mfpd (r1)+ / the high byte to start us off
swab (sp)
movb (sp)+,(r2)+
dec r0
1:
mov r0,r3 / save trailing byte indicator and
asr r0 / convert length remaining to units of
beq 3f / words
2:
mfpd (r1)+ / grab next word from user space
movb (sp),(r2)+ / move the first byte
swab (sp) / and the second ...
movb (sp)+,(r2)+
sob r0,2b
3: / r0 = 0
asr r3 / need to copy in trailing byte?
bcc 4f / nope, all done
mfpd (r1) / grab last word and take the low
movb (sp)+,(r2) / byte
4:
mov (sp)+,nofault / restore error trap
mov (sp)+,r3 / restore registers
mov (sp)+,r2
rts pc / and return
5:
mov $EFAULT,r0 / we got a memory fault give them the
br 4b / error
/*
* error = vcopyout(fromaddr, toaddr, length)
* int error;
* caddr_t fromaddr, toaddr;
* u_int length;
*
* Copy length bytes from kernel address space fromaddr to user space toaddr.
* Returns zero on success, EFAULT on failure. Vcopyout is only called when
* fromaddr, toaddr or length is odd and the length doesn't justify an fmove.
*/
ENTRY(vcopyout)
mov r2,-(sp) / allocate a couple extra registers
mov r3,-(sp)
mov nofault,-(sp)
mov $5f,nofault / set up error trap
mov 10(sp),r1 / r1 = fromaddr (kernel space)
mov 12(sp),r2 / r2 = toaddr (user address)
mov 14(sp),r0 / r0 = length
beq 4f / (exit early if 0)
bit $1,r2 / toaddr odd?
beq 1f
dec r2 / yes, grab even word so we can stuff
mfpd (r2) / our first byte into the high byte
movb (r1)+,1(sp) / of that word
mtpd (r2)+
dec r0
1:
mov r0,r3 / save trailing byte indicator and
asr r0 / convert length remaining to units of
beq 3f / words
2:
movb (r1)+,-(sp) / form word to copy out on the stack
movb (r1)+,1(sp)
mtpd (r2)+ / and send it on its way
sob r0,2b
3: / r0 = 0
asr r3 / need to copy out trailing byte?
bcc 4f / nope, all done
mfpd (r2) / have to stuff our last byte out so
movb (r1),(sp) / stick it into the lower byte and
mtpd (r2) / rewrite it
4:
mov (sp)+,nofault / restore previous error trap
mov (sp)+,r3 / restore registers
mov (sp)+,r2
rts pc / and return
5:
mov $EFAULT,r0 / user memory fault ... return
br 4b / EFAULT
/*
* error = copyinstr(fromaddr, toaddr, maxlength, &lencopied)
* int error;
* caddr_t fromaddr, toaddr;
* u_int maxlength, *lencopied;
*
* Copy a null terminated string from the user address space into the kernel
* address space. Returns zero on success, EFAULT on user memory management
* trap, ENOENT if maxlength exceeded. If lencopied is non-zero, *lencopied
* gets the length of the copy (including the null terminating byte).
*/
ENTRY(copyinstr)
mov r2,-(sp) / allocate a couple extra registers
mov r3,-(sp)
mov nofault,-(sp)
mov $7f,nofault / set up error trap
mov 10(sp),r1 / r1 = fromaddr (user address)
mov 12(sp),r2 / r2 = toaddr (kernel address)
mov 14(sp),r0 / r0 = maxlength (remaining space)
beq 3f / (exit early with ENOENT if 0)
bit $1,r1 / fromaddr odd?
beq 1f
dec r1 / yes, grab the even word to start
mfpd (r1)+ / us off
mov (sp)+,r3
br 2f / and enter the loop halfway in ...
1:
mfpd (r1)+ / grab next word from user space
mov (sp)+,r3
movb r3,(r2)+ / move the first byte
beq 4f
dec r0
beq 3f
2:
swab r3 / and the second ...
movb r3,(r2)+
beq 4f
sob r0,1b
3:
mov $ENOENT,r0 / ran out of room - indicate failure
br 5f / and exit ...
4:
clr r0 / success!
5:
tst 16(sp) / does the caller want the copy length?
beq 6f
sub 12(sp),r2 / yes, figure out how much we copied:
mov r2,*16(sp) / *lencopied = r2 {toaddr'} - toaddr
6:
mov (sp)+,nofault / restore error trap
mov (sp)+,r3 / restore registers
mov (sp)+,r2 / and return
rts pc
7:
mov $EFAULT,r0 / we got a memory fault give them the
br 5b / error
/*
* error = copyoutstr(fromaddr, toaddr, maxlength, lencopied)
* int error;
* caddr_t fromaddr, toaddr;
* u_int maxlength, *lencopied;
*
* Copy a null terminated string from the kernel address space to the user
* address space. Returns zero on success, EFAULT on user memory management
* trap, ENOENT if maxlength exceeded. If lencopied is non-zero, *lencopied
* gets the length of the copy (including the null terminating byte). Note
* that *lencopied will not by valid on EFAULT.
*/
ENTRY(copyoutstr)
mov r2,-(sp) / allocate a couple extra registers
mov r3,-(sp)
mov nofault,-(sp)
mov $7f,nofault / set up error trap
/*
* First find out how much we're going to be copying:
* min(strlen(fromaddr), maxlength).
*/
mov 10(sp),r0 / r0 = fromaddr (kernel address)
mov 14(sp),r1 / r1 = maxlength (remaining space)
beq 6f / (exit early with ENOENT if 0)
1:
tstb (r0)+ / found null?
beq 2f
sob r1,1b / run out of room?
mov 14(sp),r0 / ran out of room: r0 = maxlength
br 3f
2:
sub 10(sp),r0 / found null: r0 = strlen(fromaddr)
3:
tst 16(sp) / does the caller want the copy length?
beq 4f / yes,
mov r0,*16(sp) / lencopied = r0 (invalid on EFAULT)
4:
mov 10(sp),r1 / r1 = fromaddr (kernel space)
mov 12(sp),r2 / r2 = toaddr (user address)
bit $1,r2 / toaddr odd?
beq 5f
dec r2 / yes, grab even word so we can stuff
mfpd (r2) / our first byte into the high byte
movb (r1)+,1(sp) / of that word
mtpd (r2)+
dec r0
5:
mov r0,r3 / save trailing byte indicator and
asr r0 / convert space remaining to units of
beq 2f / words
1:
movb (r1)+,-(sp) / form word to copy out on the stack
movb (r1)+,1(sp)
mtpd (r2)+ / and send it on its way
sob r0,1b
2:
asr r3 / need to copy out trailing byte?
bcc 3f / nope, all done
mfpd (r2) / have to stuff our last byte out so
movb (r1)+,(sp) / stick it into the lower byte and
mtpd (r2) / rewrite it
3:
movb -(r1),r0 / did we copy the null out?
beq 5f
4:
mov $ENOENT,r0 / no, so indicate ENOENT
5:
mov (sp)+,nofault / restore previous error trap
mov (sp)+,r3 / restore registers
mov (sp)+,r2
rts pc / and return
/*
* Rapacious silliness here - someone has passed us maxlength == 0 ...
*/
6:
tst 16(sp) / do they want to know about it?
beq 4b / (guess not ...)
clr *16(sp) / *lencopied = 0
br 4b / return ENOENT
7:
mov $EFAULT,r0 / user memory fault ... return
br 5b / EFAULT