1/* $NetBSD: copy.S,v 1.1 2002/11/09 02:02:33 nisimura 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * Copyright (C) 1989 Digital Equipment Corporation. 39 * Permission to use, copy, modify, and distribute this software and 40 * its documentation for any purpose and without fee is hereby granted, 41 * provided that the above copyright notice appears in all copies. 42 * Digital Equipment Corporation makes no representations about the 43 * suitability of this software for any purpose. It is provided "as is" 44 * without express or implied warranty. 45 * 46 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, 47 * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) 48 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, 49 * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) 50 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, 51 * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) 52 * 53 * @(#)locore.s 8.5 (Berkeley) 1/4/94 54 */ 55 56/* 57 * copy(9) - kernel space to/from user space copy functions. 58 * fetch(9) - fetch data from user-space. 59 * store(9) - store data to user-space. 60 */ 61 62#include <sys/errno.h> 63#include <mips/asm.h> 64#include "assym.h" 65 66 .set noreorder 67/* 68 * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied) 69 * Copy a NIL-terminated string, at most maxlen characters long. Return the 70 * number of characters copied (including the NIL) in *lencopied. If the 71 * string is too long, return ENAMETOOLONG; else return 0. 72 */ 73LEAF(copystr) 74 move t0, a2 75 beq a2, zero, 4f 761: 77 lbu v0, 0(a0) 78 subu a2, a2, 1 79 beq v0, zero, 2f 80 sb v0, 0(a1) # each byte until NIL 81 addu a0, a0, 1 82 bne a2, zero, 1b # less than maxlen 83 addu a1, a1, 1 844: 85 li v0, ENAMETOOLONG # run out of space 862: 87 beq a3, zero, 3f # return num. of copied bytes 88 subu a2, t0, a2 # if the 4th arg was non-NULL 89 sw a2, 0(a3) 903: 91 j ra # v0 is 0 or ENAMETOOLONG 92 nop 93END(copystr) 94 95/* 96 * int copyinstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied) 97 * Copy a NIL-terminated string, at most maxlen characters long, from the 98 * user's address space. Return the number of characters copied (including 99 * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; 100 * else return 0 or EFAULT. 101 */ 102LEAF(copyinstr) 103 lw v1, _C_LABEL(curpcb) 104 la v0, _C_LABEL(copystrerr) 105 blt a0, zero, _C_LABEL(copystrerr) 106 sw v0, U_PCB_ONFAULT(v1) 107 move t0, a2 108 beq a2, zero, 4f 1091: 110 lbu v0, 0(a0) 111 subu a2, a2, 1 112 beq v0, zero, 2f 113 sb v0, 0(a1) 114 addu a0, a0, 1 115 bne a2, zero, 1b 116 addu a1, a1, 1 1174: 118 li v0, ENAMETOOLONG 1192: 120 beq a3, zero, 3f 121 subu a2, t0, a2 122 sw a2, 0(a3) 1233: 124 j ra # v0 is 0 or ENAMETOOLONG 125 sw zero, U_PCB_ONFAULT(v1) 126END(copyinstr) 127 128/* 129 * int copyoutstr(void *uaddr, void *kaddr, size_t maxlen, size_t *lencopied); 130 * Copy a NIL-terminated string, at most maxlen characters long, into the 131 * user's address space. Return the number of characters copied (including 132 * the NIL) in *lencopied. If the string is too long, return ENAMETOOLONG; 133 * else return 0 or EFAULT. 134 */ 135LEAF(copyoutstr) 136 lw v1, _C_LABEL(curpcb) 137 la v0, _C_LABEL(copystrerr) 138 blt a1, zero, _C_LABEL(copystrerr) 139 sw v0, U_PCB_ONFAULT(v1) 140 move t0, a2 141 beq a2, zero, 4f 1421: 143 lbu v0, 0(a0) 144 subu a2, a2, 1 145 beq v0, zero, 2f 146 sb v0, 0(a1) 147 addu a0, a0, 1 148 bne a2, zero, 1b 149 addu a1, a1, 1 1504: 151 li v0, ENAMETOOLONG 1522: 153 beq a3, zero, 3f 154 subu a2, t0, a2 155 sw a2, 0(a3) 1563: 157 j ra # v0 is 0 or ENAMETOOLONG 158 sw zero, U_PCB_ONFAULT(v1) 159END(copyoutstr) 160 161LEAF(copystrerr) 162 sw zero, U_PCB_ONFAULT(v1) 163 j ra 164 li v0, EFAULT # return EFAULT 165END(copystrerr) 166 167/* 168 * kcopy(const void *src, void *dst, size_t len); 169 * 170 * Copy len bytes from src to dst, aborting if we encounter a fatal 171 * page fault. 172 * 173 * kcopy() _must_ save and restore the old fault handler since it is 174 * called by uiomove(), which may be in the path of servicing a non-fatal 175 * page fault. 176 */ 177NESTED(kcopy, 48, ra) 178 subu sp, sp, 48 # set up stack frame 179 /* Frame contains RA (31) and S0 (16). */ 180 .mask 0x80010000, -4 181 sw ra, 44(sp) # save ra 182 sw s0, 32(sp) # save s0 183 move v0, a0 # swap a0, a1 for call to memcpy 184 move a0, a1 185 move a1, v0 186 lw v1, _C_LABEL(curpcb) # set up fault handler 187 la v0, _C_LABEL(kcopyerr) 188 lw s0, U_PCB_ONFAULT(v1) # save old handler 189 jal memcpy 190 sw v0, U_PCB_ONFAULT(v1) 191 192 lw v1, _C_LABEL(curpcb) # restore the old handler 193 lw ra, 44(sp) # restore ra 194 sw s0, U_PCB_ONFAULT(v1) 195 lw s0, 32(sp) # restore s0 196 addu sp, sp, 48 # kill stack frame 197 j ra 198 move v0, zero # success! 199END(kcopy) 200 201LEAF(kcopyerr) 202 lw v1, _C_LABEL(curpcb) # restore the old handler 203 lw ra, 44(sp) # restore ra 204 sw s0, U_PCB_ONFAULT(v1) 205 lw s0, 32(sp) # restore s0 206 addu sp, sp, 48 # kill stack frame 207 j ra 208 li v0, EFAULT # return EFAULT 209END(kcopyerr) 210 211/* 212 * int copyin(void *uaddr, void *kaddr, size_t len) 213 * Copies len bytes of data from the user-space address uaddr to the 214 * kernel-space address kaddr. copyin returns 0 on success or EFAULT 215 * if a bad address is encountered. 216 */ 217NESTED(copyin, CALLFRAME_SIZ, ra) 218 subu sp, sp, CALLFRAME_SIZ 219 .mask 0x80000000, -4 220 sw ra, CALLFRAME_RA(sp) 221 blt a0, zero, _C_LABEL(copyerr) 222 move v0, a0 # swap a0, a1 for call to memcpy 223 move a0, a1 224 move a1, v0 225 lw v1, _C_LABEL(curpcb) 226 la v0, _C_LABEL(copyerr) 227 jal memcpy 228 sw v0, U_PCB_ONFAULT(v1) 229 230 lw v1, _C_LABEL(curpcb) 231 lw ra, CALLFRAME_RA(sp) 232 addu sp, sp, CALLFRAME_SIZ 233 sw zero, U_PCB_ONFAULT(v1) 234 j ra 235 move v0, zero 236END(copyin) 237 238/* 239 * int copyout(void *kaddr, void *uaddr, size_t len) 240 * Copies len bytes of data from the kernel-space address kaddr to the 241 * user-space address uaddr. copyout returns 0 on success or EFAULT 242 * if a bad address is encountered. 243 */ 244NESTED(copyout, CALLFRAME_SIZ, ra) 245 subu sp, sp, CALLFRAME_SIZ 246 .mask 0x80000000, -4 247 sw ra, CALLFRAME_RA(sp) 248 blt a1, zero, _C_LABEL(copyerr) 249 move v0, a0 # swap a0, a1 for call to memcpy 250 move a0, a1 251 move a1, v0 252 lw v1, _C_LABEL(curpcb) 253 la v0, _C_LABEL(copyerr) 254 jal memcpy 255 sw v0, U_PCB_ONFAULT(v1) 256 257 lw v1, _C_LABEL(curpcb) 258 lw ra, CALLFRAME_RA(sp) 259 addu sp, sp, CALLFRAME_SIZ 260 sw zero, U_PCB_ONFAULT(v1) 261 j ra 262 move v0, zero 263END(copyout) 264 265LEAF(copyerr) 266 lw v1, _C_LABEL(curpcb) 267 lw ra, CALLFRAME_RA(sp) 268 addu sp, sp, CALLFRAME_SIZ 269 sw zero, U_PCB_ONFAULT(v1) 270 j ra 271 li v0, EFAULT # return EFAULT 272END(copyerr) 273 274/* 275 * int fuswintr(void *) 276 * Fetches a short word of data from the user-space address. 277 * This function is safe to call during an interrupt context. 278 */ 279LEAF(fuswintr) 280 lw v1, _C_LABEL(curpcb) 281 la v0, _C_LABEL(fswintrberr) 282 lw a2, U_PCB_ONFAULT(v1) 283 blt a0, zero, _C_LABEL(fswintrberr) 284 sw v0, U_PCB_ONFAULT(v1) 285 lhu v0, 0(a0) # fetch short 286 j ra 287 sw a2, U_PCB_ONFAULT(v1) 288END(fuswintr) 289 290/* 291 * int suswintr(void *, short); 292 * Stores a short word of data to the user-space address. 293 * This function is safe to call during an interrupt context. 294 */ 295LEAF(suswintr) 296 lw v1, _C_LABEL(curpcb) 297 la v0, _C_LABEL(fswintrberr) 298 lw a2, U_PCB_ONFAULT(v1) 299 blt a0, zero, _C_LABEL(fswintrberr) 300 sw v0, U_PCB_ONFAULT(v1) 301 sh a1, 0(a0) # store short 302 sw a2, U_PCB_ONFAULT(v1) 303 j ra 304 move v0, zero 305END(suswintr) 306 307/* 308 * int fuword(void *) 309 * Fetches a word of data from the user-space address. 310 */ 311LEAF(fuword) 312XLEAF(fuiword) 313 lw v1, _C_LABEL(curpcb) 314 la v0, _C_LABEL(fswberr) 315 blt a0, zero, _C_LABEL(fswberr) 316 sw v0, U_PCB_ONFAULT(v1) 317 lw v0, 0(a0) # fetch word 318 j ra 319 sw zero, U_PCB_ONFAULT(v1) 320END(fuword) 321 322/* 323 * int fusword(void *) 324 * Fetches a short word of data from the user-space address. 325 */ 326LEAF(fusword) 327XLEAF(fuisword) 328 lw v1, _C_LABEL(curpcb) 329 la v0, _C_LABEL(fswberr) 330 blt a0, zero, _C_LABEL(fswberr) 331 sw v0, U_PCB_ONFAULT(v1) 332 lhu v0, 0(a0) # fetch short 333 j ra 334 sw zero, U_PCB_ONFAULT(v1) 335END(fusword) 336 337/* 338 * int fubyte(void *) 339 * Fetch a byte from the user's address space. 340 */ 341LEAF(fubyte) 342XLEAF(fuibyte) 343 lw v1, _C_LABEL(curpcb) 344 la v0, _C_LABEL(fswberr) 345 blt a0, zero, _C_LABEL(fswberr) 346 sw v0, U_PCB_ONFAULT(v1) 347 lbu v0, 0(a0) # fetch byte 348 j ra 349 sw zero, U_PCB_ONFAULT(v1) 350END(fubyte) 351 352/* 353 * int suword(void *, int) 354 * Stores a word of data to the user-space address. 355 */ 356LEAF(suword) 357 lw v1, _C_LABEL(curpcb) 358 la v0, _C_LABEL(fswberr) 359 blt a0, zero, _C_LABEL(fswberr) 360 sw v0, U_PCB_ONFAULT(v1) 361 sw a1, 0(a0) # store word 362 sw zero, U_PCB_ONFAULT(v1) 363 j ra 364 move v0, zero 365END(suword) 366 367/* 368 * int suiword(void *, int) 369 * Have to flush instruction cache afterwards. 370 */ 371LEAF(suiword) 372 lw v1, _C_LABEL(curpcb) 373 la v0, _C_LABEL(fswberr) 374 blt a0, zero, _C_LABEL(fswberr) 375 sw v0, U_PCB_ONFAULT(v1) 376 sw a1, 0(a0) # store word 377 sw zero, U_PCB_ONFAULT(v1) 378 move v0, zero 379 lw v1, _C_LABEL(mips_cache_ops) + MIPSX_FLUSHICACHE 380 j v1 # NOTE: must not clobber v0! 381 li a1, 4 # size of word 382END(suiword) 383 384/* 385 * int susword(void *, short) 386 * Stores a short word of data to the user-space address. 387 */ 388LEAF(susword) 389XLEAF(suisword) 390 lw v1, _C_LABEL(curpcb) 391 la v0, _C_LABEL(fswberr) 392 blt a0, zero, _C_LABEL(fswberr) 393 sw v0, U_PCB_ONFAULT(v1) 394 sh a1, 0(a0) # store short 395 sw zero, U_PCB_ONFAULT(v1) 396 j ra 397 move v0, zero 398END(susword) 399 400/* 401 * int subyte(void *, int) 402 * Stores a byte of data to the user-space address. 403 */ 404LEAF(subyte) 405XLEAF(suibyte) 406 lw v1, _C_LABEL(curpcb) 407 la v0, _C_LABEL(fswberr) 408 blt a0, zero, _C_LABEL(fswberr) 409 sw v0, U_PCB_ONFAULT(v1) 410 sb a1, 0(a0) # store byte 411 sw zero, U_PCB_ONFAULT(v1) 412 j ra 413 move v0, zero 414END(subyte) 415 416/* 417 * int badaddr(void addr, int len) 418 * See if access to addr with a len type instruction causes a machine check. 419 * len is length of access (1=byte, 2=short, 4=long) 420 */ 421LEAF(badaddr) 422 lw v1, _C_LABEL(curpcb) 423 la v0, _C_LABEL(baderr) 424 bne a1, 1, 2f 425 sw v0, U_PCB_ONFAULT(v1) 426 b 5f 427 lbu v0, (a0) 4282: 429 bne a1, 2, 4f 430 nop 431 b 5f 432 lhu v0, (a0) 4334: 434 lw v0, (a0) 4355: 436 sw zero, U_PCB_ONFAULT(v1) 437 j ra 438 move v0, zero # made it w/o errors 439END(badaddr) 440 441/* 442 * Error routine for {f,s}uswintr. The fault handler in trap.c 443 * checks for pcb_onfault set to this fault handler and 444 * "bails out" before calling the VM fault handler. 445 * (We can not call VM code from interrupt level.) 446 */ 447LEAF(fswintrberr) 448 nop 449 sw a2, U_PCB_ONFAULT(v1) 450 j ra 451 li v0, -1 452END(fswintrberr) 453 454LEAF(fswberr) 455XLEAF(baderr) 456 sw zero, U_PCB_ONFAULT(v1) 457 j ra 458 li v0, -1 459END(fswberr) 460