1/* $NetBSD: copy.S,v 1.18 2020/06/30 16:20:01 maxv Exp $ */ 2 3/* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Digital Equipment Corporation and Ralph Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Copyright (C) 1989 Digital Equipment Corporation. 35 * Permission to use, copy, modify, and distribute this software and 36 * its documentation for any purpose and without fee is hereby granted, 37 * provided that the above copyright notice appears in all copies. 38 * Digital Equipment Corporation makes no representations about the 39 * suitability of this software for any purpose. It is provided "as is" 40 * without express or implied warranty. 41 * 42 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, 43 * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) 44 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, 45 * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) 46 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, 47 * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) 48 * 49 * @(#)locore.s 8.5 (Berkeley) 1/4/94 50 */ 51 52/* 53 * copy(9) - kernel space to/from user space copy functions. 54 * fetch(9) - fetch data from user-space. 55 * store(9) - store data to user-space. 56 */ 57 58#include <sys/errno.h> 59#include <mips/asm.h> 60#include "assym.h" 61 62 .set noreorder 63 64/* 65 * int copyinstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied) 66 * Copy a NUL-terminated string, at most maxlen characters long, from the 67 * user's address space. Return the number of characters copied (including 68 * the NUL) in *lencopied. If the string is too long, return ENAMETOOLONG; 69 * else return 0 or EFAULT. 70 */ 71LEAF(copyinstr) 72 PTR_L v1, L_PCB(MIPS_CURLWP) 73 PTR_LA v0, _C_LABEL(copystrerr) 74 blt a0, zero, _C_LABEL(copystrefault) 75 PTR_S v0, PCB_ONFAULT(v1) 76 move t0, a2 77 beq a2, zero, 4f 78 nop 791: 80 lbu v0, 0(a0) 81 PTR_SUBU a2, a2, 1 82 beq v0, zero, 2f 83 sb v0, 0(a1) # write trailing NUL 84 PTR_ADDU a0, a0, 1 85 bne a2, zero, 1b 86 PTR_ADDU a1, a1, 1 874: 88 li v0, ENAMETOOLONG 892: 90 beq a3, zero, 3f 91 PTR_SUBU a2, t0, a2 92 PTR_S a2, 0(a3) 933: 94 j ra # v0 is 0 or ENAMETOOLONG 95 PTR_S zero, PCB_ONFAULT(v1) 96END(copyinstr) 97 98/* 99 * int copyoutstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied); 100 * Copy a NIL-terminated string, at most maxlen characters long, into the 101 * user's address space. Return the number of characters copied (including 102 * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; 103 * else return 0 or EFAULT. 104 */ 105LEAF(copyoutstr) 106 PTR_L v1, L_PCB(MIPS_CURLWP) 107 PTR_LA v0, _C_LABEL(copystrerr) 108 blt a1, zero, _C_LABEL(copystrefault) 109 PTR_S v0, PCB_ONFAULT(v1) 110 move t0, a2 111 beq a2, zero, 4f 112 nop 1131: 114 lbu v0, 0(a0) 115 PTR_SUBU a2, a2, 1 116 beq v0, zero, 2f 117 sb v0, 0(a1) 118 PTR_ADDU a0, a0, 1 119 bne a2, zero, 1b 120 PTR_ADDU a1, a1, 1 1214: 122 li v0, ENAMETOOLONG 1232: 124 beq a3, zero, 3f 125 PTR_SUBU a2, t0, a2 126 PTR_S a2, 0(a3) 1273: 128 j ra # v0 is 0 or ENAMETOOLONG 129 PTR_S zero, PCB_ONFAULT(v1) 130END(copyoutstr) 131 132LEAF(copystrerr) 133 j ra 134 PTR_S zero, PCB_ONFAULT(v1) 135END(copystrerr) 136 137LEAF(copystrefault) 138 b copystrerr 139 li v0, EFAULT 140END(copystrefault) 141 142/* 143 * kcopy(const void *src, void *dst, size_t len); 144 * 145 * Copy len bytes from src to dst, aborting if we encounter a fatal 146 * page fault. 147 * 148 * kcopy() _must_ save and restore the old fault handler since it is 149 * called by uiomove(), which may be in the path of servicing a non-fatal 150 * page fault. 151 */ 152NESTED(kcopy, 2*CALLFRAME_SIZ, ra) 153 PTR_SUBU sp, sp, 2*CALLFRAME_SIZ # set up stack frame 154 /* Frame contains RA (31) and S0 (16). */ 155 .mask 0x80010000, -SZREG 156 REG_S ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # save ra 157 REG_S s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # save s0 158 move v0, a0 # swap a0, a1 for call to memcpy 159 move a0, a1 160 move a1, v0 161 PTR_L v1, L_PCB(MIPS_CURLWP) # set up fault handler 162 PTR_LA v0, _C_LABEL(kcopyerr) 163 PTR_L s0, PCB_ONFAULT(v1) # save old handler 164 jal memcpy 165 PTR_S v0, PCB_ONFAULT(v1) 166 167 PTR_L v1, L_PCB(MIPS_CURLWP) # restore the old handler 168 REG_L ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # restore ra 169 PTR_S s0, PCB_ONFAULT(v1) 170 REG_L s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # restore s0 171 PTR_ADDU sp, sp, 2*CALLFRAME_SIZ # kill stack frame 172 j ra 173 move v0, zero # success! 174END(kcopy) 175 176LEAF(kcopyerr) 177 PTR_L v1, L_PCB(MIPS_CURLWP) # restore the old handler 178 REG_L ra, CALLFRAME_SIZ+CALLFRAME_RA(sp) # restore ra 179 PTR_S s0, PCB_ONFAULT(v1) 180 REG_L s0, CALLFRAME_SIZ+CALLFRAME_S0(sp) # restore s0 181 j ra 182 PTR_ADDU sp, sp, 2*CALLFRAME_SIZ # kill stack frame 183END(kcopyerr) 184 185/* 186 * int copyin(void *uaddr, void *kaddr, size_t len) 187 * Copies len bytes of data from the user-space address uaddr to the 188 * kernel-space address kaddr. copyin returns 0 on success or EFAULT 189 * if a bad address is encountered. 190 */ 191NESTED(copyin, CALLFRAME_SIZ, ra) 192 PTR_SUBU sp, sp, CALLFRAME_SIZ 193 .mask 0x80000000, -4 194 REG_S ra, CALLFRAME_RA(sp) 195 blt a0, zero, _C_LABEL(copyefault) 196 move v0, a0 # swap a0, a1 for call to memcpy 197 move a0, a1 198 move a1, v0 199 PTR_L v1, L_PCB(MIPS_CURLWP) 200 PTR_LA v0, _C_LABEL(copyerr) 201 jal memcpy 202 PTR_S v0, PCB_ONFAULT(v1) 203 204 PTR_L v1, L_PCB(MIPS_CURLWP) 205 REG_L ra, CALLFRAME_RA(sp) 206 PTR_ADDU sp, sp, CALLFRAME_SIZ 207 PTR_S zero, PCB_ONFAULT(v1) 208 j ra 209 move v0, zero 210END(copyin) 211 212/* 213 * int copyout(void *kaddr, void *uaddr, size_t len) 214 * Copies len bytes of data from the kernel-space address kaddr to the 215 * user-space address uaddr. copyout returns 0 on success or EFAULT 216 * if a bad address is encountered. 217 */ 218NESTED(copyout, CALLFRAME_SIZ, ra) 219 PTR_SUBU sp, sp, CALLFRAME_SIZ 220 .mask 0x80000000, -4 221 REG_S ra, CALLFRAME_RA(sp) 222 blt a1, zero, _C_LABEL(copyefault) 223 move v0, a0 # swap a0, a1 for call to memcpy 224 move a0, a1 225 move a1, v0 226 PTR_L v1, L_PCB(MIPS_CURLWP) 227 PTR_LA v0, _C_LABEL(copyerr) 228 jal memcpy 229 PTR_S v0, PCB_ONFAULT(v1) 230 231 PTR_L v1, L_PCB(MIPS_CURLWP) 232 REG_L ra, CALLFRAME_RA(sp) 233 PTR_ADDU sp, sp, CALLFRAME_SIZ 234 PTR_S zero, PCB_ONFAULT(v1) 235 j ra 236 move v0, zero 237END(copyout) 238 239LEAF(copyerr) 240 PTR_L v1, L_PCB(MIPS_CURLWP) 241 REG_L ra, CALLFRAME_RA(sp) 242 PTR_ADDU sp, sp, CALLFRAME_SIZ 243 j ra 244 PTR_S zero, PCB_ONFAULT(v1) 245END(copyerr) 246 247LEAF(copyefault) 248 b copyerr 249 li v0, EFAULT 250END(copyefault) 251 252LEAF(kfetch_32) 253 PTR_L v1, L_PCB(MIPS_CURLWP) 254 PTR_LA v0, _C_LABEL(kfetcherr) 255 bgez a0, _C_LABEL(kfetcherr) 256 PTR_S v0, PCB_ONFAULT(v1) 257 INT_L v0, 0(a0) # fetch int 258 /* 259 * Normally a sync instructions would be used but this has to work on 260 * MIPS1 which doesn't have a sync. 261 */ 262 nop # load delay for mips1 263 move t0, v0 # dependent instruction 264 xor t0, v0 # make t0 zero 265 j ra 266 PTR_S t0, PCB_ONFAULT(v1) 267END(kfetch_32) 268 269/**************************************************************************/ 270 271#define UFETCHSTORE_PROLOGUE \ 272 PTR_L v1, L_PCB(MIPS_CURLWP) ;\ 273 PTR_LA v0, _C_LABEL(ufetchstore_fault) ;\ 274 blt a0, zero, _C_LABEL(ufetchstore_efault) ;\ 275 PTR_S v0, PCB_ONFAULT(v1) 276 277 /* keep to a single insn; it's used in a branch delay slot */ 278#define UFETCHSTORE_EPILOGUE ;\ 279 PTR_S zero, PCB_ONFAULT(v1) 280 281#define UFETCHTORE_RETURN_SUCCESS ;\ 282 j ra ;\ 283 move v0, zero 284 285/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */ 286LEAF(_ufetch_8) 287 UFETCHSTORE_PROLOGUE 288 lbu v0, 0(a0) /* v0 = *uaddr */ 289 UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ 290 sb v0, 0(a1) /* *valp = v0 */ 291 UFETCHTORE_RETURN_SUCCESS 292END(_ufetch_8) 293 294/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */ 295LEAF(_ufetch_16) 296 UFETCHSTORE_PROLOGUE 297 lhu v0, 0(a0) /* v0 = *uaddr */ 298 UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ 299 sh v0, 0(a1) /* *valp = v0 */ 300 UFETCHTORE_RETURN_SUCCESS 301END(_ufetch_16) 302 303/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */ 304LEAF(_ufetch_32) 305 UFETCHSTORE_PROLOGUE 306 lw v0, 0(a0) /* v0 = *uaddr */ 307 UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1) */ 308 sw v0, 0(a1) /* *valp = v0 */ 309 UFETCHTORE_RETURN_SUCCESS 310END(_ufetch_32) 311 312#ifdef _LP64 313/* LINTSTUB: int _ufetch_64(const uint64_t *uaddr, uint64_t *valp); */ 314LEAF(_ufetch_64) 315 UFETCHSTORE_PROLOGUE 316 ld v0, 0(a0) /* v0 = *uaddr */ 317 UFETCHSTORE_EPILOGUE /* load delay slot (MIPS1, LOL) */ 318 sd v0, 0(a1) /* *valp = v0 */ 319 UFETCHTORE_RETURN_SUCCESS 320END(_ufetch_64) 321#endif /* _LP64 */ 322 323/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */ 324LEAF(_ustore_8) 325 UFETCHSTORE_PROLOGUE 326 sb a1, 0(a0) /* *uaddr = val */ 327 UFETCHSTORE_EPILOGUE 328 UFETCHTORE_RETURN_SUCCESS 329END(_ustore_8) 330 331/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */ 332LEAF(_ustore_16) 333 UFETCHSTORE_PROLOGUE 334 sh a1, 0(a0) /* *uaddr = val */ 335 UFETCHSTORE_EPILOGUE 336 UFETCHTORE_RETURN_SUCCESS 337END(_ustore_16) 338 339/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */ 340LEAF(_ustore_32) 341 UFETCHSTORE_PROLOGUE 342 sw a1, 0(a0) /* *uaddr = val */ 343 UFETCHSTORE_EPILOGUE 344 UFETCHTORE_RETURN_SUCCESS 345END(_ustore_32) 346 347#ifdef _LP64 348/* LINTSTUB: int _ustore_64(uint64_t *uaddr, uint64_t val); */ 349LEAF(_ustore_64) 350 UFETCHSTORE_PROLOGUE 351 sd a1, 0(a0) /* *uaddr = val */ 352 UFETCHSTORE_EPILOGUE 353 UFETCHTORE_RETURN_SUCCESS 354END(_ustore_64) 355#endif /* _LP64 */ 356 357LEAF(ufetchstore_efault) 358 li v0, EFAULT 359XLEAF(ufetchstore_fault) 360 j ra 361 UFETCHSTORE_EPILOGUE 362END(ufetchstore_efault) 363 364/**************************************************************************/ 365 366/* 367 * uint32_t mips_ufetch32(const void *) 368 * Fetches a 32-bit datum from the user-space address and 369 * returns it in v0. 370 * 371 * We have this in addition to the MI fetch(9) API for the convenience 372 * of bds_emul.S and fp.S. 373 */ 374LEAF(mips_ufetch32) 375 PTR_L v1, L_PCB(MIPS_CURLWP) 376 PTR_LA v0, _C_LABEL(mips_ufetch32_fault) 377 blt a0, zero, _C_LABEL(mips_ufetch32_fault) 378 PTR_S v0, PCB_ONFAULT(v1) 379 INT_L v0, 0(a0) # fetch int 380 j ra 381 PTR_S zero, PCB_ONFAULT(v1) 382END(mips_ufetch32) 383 384/* 385 * int mips_ustore32_isync(void *, uint32_t) 386 * Have to flush instruction cache afterwards. 387 */ 388LEAF(mips_ustore32_isync) 389 PTR_L v1, L_PCB(MIPS_CURLWP) 390 PTR_LA v0, _C_LABEL(mips_ufetch32_fault) 391 blt a0, zero, _C_LABEL(mips_ufetch32_fault) 392 PTR_S v0, PCB_ONFAULT(v1) 393 INT_S a1, 0(a0) # store word 394 PTR_S zero, PCB_ONFAULT(v1) 395 PTR_L t9, _C_LABEL(mips_cache_ops) + MIPSX_FLUSHICACHE 396 move v0, zero 397 j t9 # NOTE: must not clobber v0! 398 li a1, 4 # size of word 399END(mips_ustore32_isync) 400 401LEAF(mips_ufetch32_fault) 402 li v0, -1 403 j ra 404 PTR_S zero, PCB_ONFAULT(v1) 405END(mips_ufetch32_fault) 406 407/**************************************************************************/ 408 409/* 410 * int badaddr(void addr, int len) 411 * See if access to addr with a len type instruction causes a machine check. 412 * len is length of access (1=byte, 2=short, 4=long) 413 */ 414LEAF(badaddr) 415 PTR_L v1, L_PCB(MIPS_CURLWP) 416 PTR_LA v0, _C_LABEL(baderr) 417 bne a1, 1, 2f 418 PTR_S v0, PCB_ONFAULT(v1) 419 b 5f 420 lbu v0, (a0) 4212: 422 bne a1, 2, 4f 423 nop 424 b 5f 425 lhu v0, (a0) 4264: 427 INT_L v0, (a0) 4285: 429 /* 430 * Normally a sync instructions would be used but this has to work on 431 * MIPS1 which doesn't have a sync. 432 */ 433 nop 434 move t0, v0 # dependent instruction 435 xor t0, t0 # zero t0 436 PTR_S t0, PCB_ONFAULT(v1) # clear onfault 437 j ra 438 move v0, zero # made it w/o errors 439END(badaddr) 440 441LEAF(kfetcherr) 442 PTR_S zero, PCB_ONFAULT(v1) 443 j ra 444 move v0, a1 445END(kfetcherr) 446 447LEAF(fswberr) 448XLEAF(baderr) 449 PTR_S zero, PCB_ONFAULT(v1) 450 j ra 451 li v0, -1 452END(fswberr) 453