/* $NetBSD: copy.S,v 1.18 2020/06/30 16:20:01 maxv Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Digital Equipment Corporation and Ralph Campbell. * * 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. 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. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) * * @(#)locore.s 8.5 (Berkeley) 1/4/94 */ /* * copy(9) - kernel space to/from user space copy functions. * fetch(9) - fetch data from user-space. * store(9) - store data to user-space. */ #include #include #include "assym.h" .set noreorder /* * int copyinstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied) * Copy a NUL-terminated string, at most maxlen characters long, from the * user's address space. Return the number of characters copied (including * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; * else return 0 or EFAULT. */ LEAF(copyinstr) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(copystrerr) blt a0, zero, _C_LABEL(copystrefault) PTR_S v0, PCB_ONFAULT(v1) move t0, a2 beq a2, zero, 4f nop 1: lbu v0, 0(a0) PTR_SUBU a2, a2, 1 beq v0, zero, 2f sb v0, 0(a1) # write trailing NUL PTR_ADDU a0, a0, 1 bne a2, zero, 1b PTR_ADDU a1, a1, 1 4: li v0, ENAMETOOLONG 2: beq a3, zero, 3f PTR_SUBU a2, t0, a2 PTR_S a2, 0(a3) 3: j ra # v0 is 0 or ENAMETOOLONG PTR_S zero, PCB_ONFAULT(v1) END(copyinstr) /* * int copyoutstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied); * Copy a NIL-terminated string, at most maxlen characters long, into the * user's address space. Return the number of characters copied (including * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; * else return 0 or EFAULT. */ LEAF(copyoutstr) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(copystrerr) blt a1, zero, _C_LABEL(copystrefault) PTR_S v0, PCB_ONFAULT(v1) move t0, a2 beq a2, zero, 4f nop 1: lbu v0, 0(a0) PTR_SUBU a2, a2, 1 beq v0, zero, 2f sb v0, 0(a1) PTR_ADDU a0, a0, 1 bne a2, zero, 1b PTR_ADDU a1, a1, 1 4: li v0, ENAMETOOLONG 2: beq a3, zero, 3f PTR_SUBU a2, t0, a2 PTR_S a2, 0(a3) 3: j ra # v0 is 0 or ENAMETOOLONG PTR_S zero, PCB_ONFAULT(v1) END(copyoutstr) LEAF(copystrerr) j ra PTR_S zero, PCB_ONFAULT(v1) END(copystrerr) LEAF(copystrefault) b copystrerr li v0, EFAULT END(copystrefault) /* * kcopy(const void *src, void *dst, size_t len); * * Copy len bytes from src to dst, aborting if we encounter a fatal * page fault. * * kcopy() _must_ save and restore the old fault handler since it is * called by uiomove(), which may be in the path of servicing a non-fatal * page fault. */ NESTED(kcopy, 2*CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, 2*CALLFRAME_SIZ # set up stack frame /* Frame contains RA (31) and S0 (16). */ .mask 0x80010000, -SZREG REG_S ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # save ra REG_S s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # save s0 move v0, a0 # swap a0, a1 for call to memcpy move a0, a1 move a1, v0 PTR_L v1, L_PCB(MIPS_CURLWP) # set up fault handler PTR_LA v0, _C_LABEL(kcopyerr) PTR_L s0, PCB_ONFAULT(v1) # save old handler jal memcpy PTR_S v0, PCB_ONFAULT(v1) PTR_L v1, L_PCB(MIPS_CURLWP) # restore the old handler REG_L ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # restore ra PTR_S s0, PCB_ONFAULT(v1) REG_L s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # restore s0 PTR_ADDU sp, sp, 2*CALLFRAME_SIZ # kill stack frame j ra move v0, zero # success! END(kcopy) LEAF(kcopyerr) PTR_L v1, L_PCB(MIPS_CURLWP) # restore the old handler REG_L ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # restore ra PTR_S s0, PCB_ONFAULT(v1) REG_L s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # restore s0 j ra PTR_ADDU sp, sp, 2*CALLFRAME_SIZ # kill stack frame END(kcopyerr) /* * int copyin(void *uaddr, void *kaddr, size_t len) * Copies len bytes of data from the user-space address uaddr to the * kernel-space address kaddr. copyin returns 0 on success or EFAULT * if a bad address is encountered. */ NESTED(copyin, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, -4 REG_S ra, CALLFRAME_RA(sp) blt a0, zero, _C_LABEL(copyefault) move v0, a0 # swap a0, a1 for call to memcpy move a0, a1 move a1, v0 PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(copyerr) jal memcpy PTR_S v0, PCB_ONFAULT(v1) PTR_L v1, L_PCB(MIPS_CURLWP) REG_L ra, CALLFRAME_RA(sp) PTR_ADDU sp, sp, CALLFRAME_SIZ PTR_S zero, PCB_ONFAULT(v1) j ra move v0, zero END(copyin) /* * int copyout(void *kaddr, void *uaddr, size_t len) * Copies len bytes of data from the kernel-space address kaddr to the * user-space address uaddr. copyout returns 0 on success or EFAULT * if a bad address is encountered. */ NESTED(copyout, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, -4 REG_S ra, CALLFRAME_RA(sp) blt a1, zero, _C_LABEL(copyefault) move v0, a0 # swap a0, a1 for call to memcpy move a0, a1 move a1, v0 PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(copyerr) jal memcpy PTR_S v0, PCB_ONFAULT(v1) PTR_L v1, L_PCB(MIPS_CURLWP) REG_L ra, CALLFRAME_RA(sp) PTR_ADDU sp, sp, CALLFRAME_SIZ PTR_S zero, PCB_ONFAULT(v1) j ra move v0, zero END(copyout) LEAF(copyerr) PTR_L v1, L_PCB(MIPS_CURLWP) REG_L ra, CALLFRAME_RA(sp) PTR_ADDU sp, sp, CALLFRAME_SIZ j ra PTR_S zero, PCB_ONFAULT(v1) END(copyerr) LEAF(copyefault) b copyerr li v0, EFAULT END(copyefault) LEAF(kfetch_32) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(kfetcherr) bgez a0, _C_LABEL(kfetcherr) PTR_S v0, PCB_ONFAULT(v1) INT_L v0, 0(a0) # fetch int /* * Normally a sync instructions would be used but this has to work on * MIPS1 which doesn't have a sync. */ nop # load delay for mips1 move t0, v0 # dependent instruction xor t0, v0 # make t0 zero j ra PTR_S t0, PCB_ONFAULT(v1) END(kfetch_32) /**************************************************************************/ #define UFETCHSTORE_PROLOGUE \ PTR_L v1, L_PCB(MIPS_CURLWP) ;\ PTR_LA v0, _C_LABEL(ufetchstore_fault) ;\ blt a0, zero, _C_LABEL(ufetchstore_efault) ;\ PTR_S v0, PCB_ONFAULT(v1) /* keep to a single insn; it's used in a branch delay slot */ #define UFETCHSTORE_EPILOGUE ;\ PTR_S zero, PCB_ONFAULT(v1) #define UFETCHTORE_RETURN_SUCCESS ;\ j ra ;\ move v0, zero /* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */ LEAF(_ufetch_8) UFETCHSTORE_PROLOGUE lbu v0, 0(a0) /* v0 = *uaddr */ UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ sb v0, 0(a1) /* *valp = v0 */ UFETCHTORE_RETURN_SUCCESS END(_ufetch_8) /* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */ LEAF(_ufetch_16) UFETCHSTORE_PROLOGUE lhu v0, 0(a0) /* v0 = *uaddr */ UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ sh v0, 0(a1) /* *valp = v0 */ UFETCHTORE_RETURN_SUCCESS END(_ufetch_16) /* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */ LEAF(_ufetch_32) UFETCHSTORE_PROLOGUE lw v0, 0(a0) /* v0 = *uaddr */ UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ sw v0, 0(a1) /* *valp = v0 */ UFETCHTORE_RETURN_SUCCESS END(_ufetch_32) #ifdef _LP64 /* LINTSTUB: int _ufetch_64(const uint64_t *uaddr, uint64_t *valp); */ LEAF(_ufetch_64) UFETCHSTORE_PROLOGUE ld v0, 0(a0) /* v0 = *uaddr */ UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1, LOL) */ sd v0, 0(a1) /* *valp = v0 */ UFETCHTORE_RETURN_SUCCESS END(_ufetch_64) #endif /* _LP64 */ /* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */ LEAF(_ustore_8) UFETCHSTORE_PROLOGUE sb a1, 0(a0) /* *uaddr = val */ UFETCHSTORE_EPILOGUE UFETCHTORE_RETURN_SUCCESS END(_ustore_8) /* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */ LEAF(_ustore_16) UFETCHSTORE_PROLOGUE sh a1, 0(a0) /* *uaddr = val */ UFETCHSTORE_EPILOGUE UFETCHTORE_RETURN_SUCCESS END(_ustore_16) /* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */ LEAF(_ustore_32) UFETCHSTORE_PROLOGUE sw a1, 0(a0) /* *uaddr = val */ UFETCHSTORE_EPILOGUE UFETCHTORE_RETURN_SUCCESS END(_ustore_32) #ifdef _LP64 /* LINTSTUB: int _ustore_64(uint64_t *uaddr, uint64_t val); */ LEAF(_ustore_64) UFETCHSTORE_PROLOGUE sd a1, 0(a0) /* *uaddr = val */ UFETCHSTORE_EPILOGUE UFETCHTORE_RETURN_SUCCESS END(_ustore_64) #endif /* _LP64 */ LEAF(ufetchstore_efault) li v0, EFAULT XLEAF(ufetchstore_fault) j ra UFETCHSTORE_EPILOGUE END(ufetchstore_efault) /**************************************************************************/ /* * uint32_t mips_ufetch32(const void *) * Fetches a 32-bit datum from the user-space address and * returns it in v0. * * We have this in addition to the MI fetch(9) API for the convenience * of bds_emul.S and fp.S. */ LEAF(mips_ufetch32) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(mips_ufetch32_fault) blt a0, zero, _C_LABEL(mips_ufetch32_fault) PTR_S v0, PCB_ONFAULT(v1) INT_L v0, 0(a0) # fetch int j ra PTR_S zero, PCB_ONFAULT(v1) END(mips_ufetch32) /* * int mips_ustore32_isync(void *, uint32_t) * Have to flush instruction cache afterwards. */ LEAF(mips_ustore32_isync) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(mips_ufetch32_fault) blt a0, zero, _C_LABEL(mips_ufetch32_fault) PTR_S v0, PCB_ONFAULT(v1) INT_S a1, 0(a0) # store word PTR_S zero, PCB_ONFAULT(v1) PTR_L t9, _C_LABEL(mips_cache_ops) + MIPSX_FLUSHICACHE move v0, zero j t9 # NOTE: must not clobber v0! li a1, 4 # size of word END(mips_ustore32_isync) LEAF(mips_ufetch32_fault) li v0, -1 j ra PTR_S zero, PCB_ONFAULT(v1) END(mips_ufetch32_fault) /**************************************************************************/ /* * int badaddr(void addr, int len) * See if access to addr with a len type instruction causes a machine check. * len is length of access (1=byte, 2=short, 4=long) */ LEAF(badaddr) PTR_L v1, L_PCB(MIPS_CURLWP) PTR_LA v0, _C_LABEL(baderr) bne a1, 1, 2f PTR_S v0, PCB_ONFAULT(v1) b 5f lbu v0, (a0) 2: bne a1, 2, 4f nop b 5f lhu v0, (a0) 4: INT_L v0, (a0) 5: /* * Normally a sync instructions would be used but this has to work on * MIPS1 which doesn't have a sync. */ nop move t0, v0 # dependent instruction xor t0, t0 # zero t0 PTR_S t0, PCB_ONFAULT(v1) # clear onfault j ra move v0, zero # made it w/o errors END(badaddr) LEAF(kfetcherr) PTR_S zero, PCB_ONFAULT(v1) j ra move v0, a1 END(kfetcherr) LEAF(fswberr) XLEAF(baderr) PTR_S zero, PCB_ONFAULT(v1) j ra li v0, -1 END(fswberr)