NetBSD/sys/arch/m68k/m68k/copy.s

416 lines
11 KiB
ArmAsm

/*
* Copyright (c) 1993 Adam Glass.
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1980, 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: Utah Hdr: locore.s 1.58 91/04/22
* from: (hp300) @(#)locore.s 7.11 (Berkeley) 5/9/91
* $Id: copy.s,v 1.11 1994/05/06 17:37:37 briggs Exp $
*/
#include <sys/errno.h>
#include <machine/asm.h>
#include "assym.s"
#ifdef sun3 /* but code this simple prolly won't work for sun3x -- cgd */
#define SETUP_SFC moveq #FC_USERD, d1; movec d1, sfc
#define RESTORE_SFC moveq #FC_CONTROL, d1; movec d1, sfc
#define SETUP_DFC moveq #FC_USERD, d1; movec d1, dfc
#define RESTORE_DFC moveq #FC_CONTROL, d1; movec d1, dfc
#else
#define SETUP_SFC
#define RESTORE_SFC
#define SETUP_DFC
#define RESTORE_DFC
#endif
.text
/*
* copyinstr(fromaddr, toaddr, maxlength, &lencopied)
*
* Copy a null terminated string from the user address space into
* the kernel address space.
*/
ENTRY(copyinstr)
movl d2,sp@- | high counter
movl _curpcb,a0 | current pcb
movl #Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
movl sp@(8),a0 | a0 = fromaddr
movl sp@(12),a1 | a1 = toaddr
SETUP_SFC
moveq #0,d2
movw sp@(16),d2 | d2 = maxlength MSW
movl sp@(16),d0 | d0 = maxlength
jlt Lcisflt1 | negative count, error
jeq Lcisdone | zero count, all done
movw sp@(18),d0 | d0 = maxlength LSW
jeq Lcoloop | low-order word zero
subql #1,d0 | set up for dbeq
Lcisloop:
movsb a0@+,d1 | grab a byte
movb d1,a1@+ | copy it
dbeq d0,Lcisloop | if !null and more, continue
jne Lcoloop | down to zero...
moveq #0,d0 | got a null, all done
Lcisdone:
RESTORE_SFC
tstl sp@(20) | return length desired?
jeq Lcisret | no, just return
subl sp@(8),a0 | determine how much was copied
movl sp@(20),a1 | return location
movl a0,a1@ | stash it
Lcisret:
movl _curpcb,a0 | current pcb
clrl a0@(PCB_ONFAULT) | clear fault addr
movl sp@+, d2
rts
Lcoloop:
subql #1, d2
jeq Lcisflt2
movw #0xffff, d0
jra Lcisloop
Lcisflt1:
moveq #EFAULT,d0 | copy fault
jra Lcisdone
Lcisflt2:
moveq #ENAMETOOLONG,d0 | ran out of space
jra Lcisdone
/*
* copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
*
* Copy a null terminated string from the kernel
* address space to the user address space.
* NOTE: maxlength must be < 64K
*/
ENTRY(copyoutstr)
movl _curpcb,a0 | current pcb
movl #Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
movl sp@(4),a0 | a0 = fromaddr
movl sp@(8),a1 | a1 = toaddr
SETUP_DFC
moveq #0,d0
movw sp@(14),d0 | d0 = maxlength
jlt Lcosflt1 | negative count, error
jeq Lcosdone | zero count, all done
subql #1,d0 | set up for dbeq
Lcosloop:
movb a0@+,d1 | grab a byte
movsb d1,a1@+ | copy it
dbeq d0,Lcosloop | if !null and more, continue
jne Lcosflt2 | ran out of room, error
moveq #0,d0 | got a null, all done
Lcosdone:
RESTORE_DFC
tstl sp@(16) | return length desired?
jeq Lcosret | no, just return
subl sp@(4),a0 | determine how much was copied
movl sp@(16),a1 | return location
movl a0,a1@ | stash it
Lcosret:
movl _curpcb,a0 | current pcb
clrl a0@(PCB_ONFAULT) | clear fault addr
rts
Lcosflt1:
moveq #EFAULT,d0 | copy fault
jra Lcosdone
Lcosflt2:
moveq #ENAMETOOLONG,d0 | ran out of space
jra Lcosdone
/*
* copystr(fromaddr, toaddr, maxlength, &lencopied)
*
* Copy a null terminated string from one point to another in
* the kernel address space.
* NOTE: maxlength must be < 64K
*/
ENTRY(copystr)
movl sp@(4),a0 | a0 = fromaddr
movl sp@(8),a1 | a1 = toaddr
moveq #0,d0
movw sp@(14),d0 | d0 = maxlength
jlt Lcsflt1 | negative count, error
jeq Lcsdone | zero count, all done
subql #1,d0 | set up for dbeq
Lcsloop:
movb a0@+,a1@+ | copy a byte
dbeq d0,Lcsloop | if !null and more, continue
jne Lcsflt2 | ran out of room, error
moveq #0,d0 | got a null, all done
Lcsdone:
tstl sp@(16) | return length desired?
jeq Lcsret | no, just return
subl sp@(4),a0 | determine how much was copied
movl sp@(16),a1 | return location
movl a0,a1@ | stash it
Lcsret:
rts
Lcsflt1:
moveq #EFAULT,d0 | copy fault
jra Lcsdone
Lcsflt2:
moveq #ENAMETOOLONG,d0 | ran out of space
jra Lcsdone
/*
* Copyin(from, to, len)
*
* Copy specified amount of data from user space into the kernel.
* NOTE: len must be < 64K
*/
ENTRY(copyin)
movl d2,sp@- | scratch register
movl _curpcb,a0 | current pcb
movl #Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
SETUP_SFC
movl sp@(16),d2 | check count
jlt Lciflt | negative, error
jeq Lcidone | zero, done
movl sp@(8),a0 | src address
movl sp@(12),a1 | dest address
movl a0,d0
btst #0,d0 | src address odd?
jeq Lcieven | no, go check dest
movsb a0@+,d1 | yes, get a byte
movb d1,a1@+ | put a byte
subql #1,d2 | adjust count
jeq Lcidone | exit if done
Lcieven:
movl a1,d0
btst #0,d0 | dest address odd?
jne Lcibyte | yes, must copy by bytes
movl d2,d0 | no, get count
lsrl #2,d0 | convert to longwords
jeq Lcibyte | no longwords, copy bytes
subql #1,d0 | set up for dbf
Lcilloop:
movsl a0@+,d1 | get a long
movl d1,a1@+ | put a long
dbf d0,Lcilloop | til done
andl #3,d2 | what remains
jeq Lcidone | all done
Lcibyte:
subql #1,d2 | set up for dbf
Lcibloop:
movsb a0@+,d1 | get a byte
movb d1,a1@+ | put a byte
dbf d2,Lcibloop | til done
Lcidone:
moveq #0,d0 | success
Lciexit:
RESTORE_SFC
movl _curpcb,a0 | current pcb
clrl a0@(PCB_ONFAULT) | clear fault catcher
movl sp@+,d2 | restore scratch reg
rts
Lciflt:
moveq #EFAULT,d0 | got a fault
jra Lciexit
/*
* Copyout(from, to, len)
*
* Copy specified amount of data from kernel to the user space
* NOTE: len must be < 64K
*/
ENTRY(copyout)
movl d2,sp@- | scratch register
movl _curpcb,a0 | current pcb
movl #Lcoflt,a0@(PCB_ONFAULT) | catch faults
SETUP_DFC
movl sp@(16),d2 | check count
jlt Lcoflt | negative, error
jeq Lcodone | zero, done
movl sp@(8),a0 | src address
movl sp@(12),a1 | dest address
movl a0,d0
btst #0,d0 | src address odd?
jeq Lcoeven | no, go check dest
movb a0@+,d1 | yes, get a byte
movsb d1,a1@+ | put a byte
subql #1,d2 | adjust count
jeq Lcodone | exit if done
Lcoeven:
movl a1,d0
btst #0,d0 | dest address odd?
jne Lcobyte | yes, must copy by bytes
movl d2,d0 | no, get count
lsrl #2,d0 | convert to longwords
jeq Lcobyte | no longwords, copy bytes
subql #1,d0 | set up for dbf
Lcolloop:
movl a0@+,d1 | get a long
movsl d1,a1@+ | put a long
dbf d0,Lcolloop | til done
andl #3,d2 | what remains
jeq Lcodone | all done
Lcobyte:
subql #1,d2 | set up for dbf
Lcobloop:
movb a0@+,d1 | get a byte
movsb d1,a1@+ | put a byte
dbf d2,Lcobloop | til done
Lcodone:
moveq #0,d0 | success
Lcoexit:
RESTORE_DFC
movl _curpcb,a0 | current pcb
clrl a0@(PCB_ONFAULT) | clear fault catcher
movl sp@+,d2 | restore scratch reg
rts
Lcoflt:
moveq #EFAULT,d0 | got a fault
jra Lcoexit
/*
* {fu,su},{byte,sword,word}
*/
ALTENTRY(fuiword, _fuword)
ENTRY(fuword)
SETUP_SFC
movl sp@(4),a0 | address to read
movl _curpcb,a1 | current pcb
movl #Lferr,a1@(PCB_ONFAULT) | where to return to on a fault
movsl a0@,d0 | do read from user space
jra Lfdone
ENTRY(fusword)
SETUP_SFC
movl sp@(4),a0
movl _curpcb,a1 | current pcb
movl #Lferr,a1@(PCB_ONFAULT) | where to return to on a fault
moveq #0,d0
movsw a0@,d0 | do read from user space
jra Lfdone
ENTRY(fuswintr)
SETUP_SFC
movl sp@(4),a0
movl _curpcb,a1 | current pcb
movl #_fubail,a1@(PCB_ONFAULT) | where to return to on a fault
moveq #0,d0
movsw a0@,d0 | do read from user space
jra Lfdone
ALTENTRY(fuibyte, _fubyte)
ENTRY(fubyte)
SETUP_SFC
movl sp@(4),a0 | address to read
movl _curpcb,a1 | current pcb
movl #Lferr,a1@(PCB_ONFAULT) | where to return to on a fault
moveq #0,d0
movsb a0@,d0 | do read from user space
jra Lfdone
/*
* error routine for fuswintr. Fails before page faulting. Otherwise
* it's the same as Lferr. Needs to be external for trap.c.
*/
ENTRY(fubail)
moveq #-1,d0 | error indicator
jra Lfdone
Lferr:
moveq #-1,d0 | error indicator
Lfdone:
RESTORE_SFC
clrl a1@(PCB_ONFAULT) | clear fault address
rts
ALTENTRY(suiword, _suword)
ENTRY(suword)
SETUP_DFC
movl sp@(4),a0 | address to write
movl sp@(8),d0 | value to put there
movl _curpcb,a1 | current pcb
movl #Lserr,a1@(PCB_ONFAULT) | where to return to on a fault
movsl d0,a0@ | do write to user space
moveq #0,d0 | indicate no fault
jra Lsdone
ENTRY(susword)
SETUP_DFC
movl sp@(4),a0 | address to write
movw sp@(10),d0 | value to put there
movl _curpcb,a1 | current pcb
movl #Lserr,a1@(PCB_ONFAULT) | where to return to on a fault
movsw d0,a0@ | do write to user space
moveq #0,d0 | indicate no fault
jra Lsdone
ENTRY(suswintr)
SETUP_DFC
movl sp@(4),a0 | address to write
movw sp@(10),d0 | value to put there
movl _curpcb,a1 | current pcb
movl #_subail,a1@(PCB_ONFAULT) | where to return to on a fault
movsw d0,a0@ | do write to user space
moveq #0,d0 | indicate no fault
jra Lsdone
ALTENTRY(suibyte, _subyte)
ENTRY(subyte)
SETUP_DFC
movl sp@(4),a0 | address to write
movb sp@(11),d0 | value to put there
movl _curpcb,a1 | current pcb
movl #Lserr,a1@(PCB_ONFAULT) | where to return to on a fault
movsb d0,a0@ | do write to user space
moveq #0,d0 | indicate no fault
jra Lsdone
/*
* error routine for suswintr. Fails before page faulting. Otherwise
* it's the same as Lferr. Needs to be external for trap.c.
*/
ENTRY(subail)
moveq #-1,d0 | error indicator
jra Lsdone
Lserr:
moveq #-1,d0 | error indicator
Lsdone:
RESTORE_DFC
clrl a1@(PCB_ONFAULT) | clear fault address
rts
#undef SETUP_SFC
#undef RESTORE_SFC
#undef SETUP_DFC
#undef RESTORE_DFC