1: /* 2: * Copyright (c) 1988 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)mch_copy.s 1.3 (2.11BSD GTE) 1/9/94 7: */ 8: 9: #include "DEFS.h" 10: #include "../machine/mch_iopage.h" 11: 12: 13: /* 14: * Fetch and set user byte routines: 15: * fubyte(addr): fetch user data space byte 16: * fuibyte(addr): fetch user instruction space byte 17: * subyte(addr, byte): set user data space byte 18: * suibyte(addr, byte): set user instruction space byte 19: * caddr_t addr; 20: * u_char byte; 21: * 22: * The fetch routines return the requested byte or -1 on fault. The set 23: * routines return 0 on success, -1 on failure. The data space routines are 24: * really the corresponding instruction space routines if NONSEPARATE is 25: * defined. 26: */ 27: ENTRY(fubyte) 28: #ifndef NONSEPARATE 29: mov nofault,-(sp) / set fault trap 30: mov $fsfault,nofault 31: mov 4(sp),r1 32: bic $1,r1 / r1 = addr&~1 33: mfpd (r1) / tmp = user data word at (addr&~1) 34: mov (sp)+,r0 35: cmp r1,4(sp) / if (addr&1) 36: beq 1f / tmp >>= 8 37: swab r0 38: 1: 39: bic $!377,r0 / return((u_char)tmp) 40: mov (sp)+,nofault / restore fault trap, and return 41: rts pc 42: #endif !NONSEPARATE 43: 44: ENTRY(fuibyte) 45: mov nofault,-(sp) / set fault trap 46: mov $fsfault,nofault 47: mov 4(sp),r1 48: bic $1,r1 / r1 = addr&~1 49: mfpi (r1) / tmp = user instruction word at 50: mov (sp)+,r0 / (addr&~1) 51: cmp r1,4(sp) / if (addr&1) 52: beq 1f / tmp >>= 8 53: swab r0 54: 1: 55: bic $!377,r0 / return((u_char)tmp) 56: mov (sp)+,nofault / restore fault trap, and return 57: rts pc 58: 59: ENTRY(subyte) 60: #ifndef NONSEPARATE 61: mov nofault,-(sp) / set fault trap 62: mov $fsfault,nofault 63: mov 4(sp),r1 64: bic $1,r1 / r1 = addr&~1 65: mfpd (r1) / tmp = user data word at (addr&~1) 66: cmp r1,6(sp) / if (addr&1) 67: beq 1f 68: movb 10(sp),1(sp) / *((char *)tmp + 1) = byte 69: br 2f 70: 1: / else 71: movb 10(sp),(sp) / *((char *)tmp) = byte 72: 2: 73: mtpd (r1) / user data word (addr&~1) = tmp 74: clr r0 / return success 75: mov (sp)+,nofault / restore fault trap, and return 76: rts pc 77: #endif !NONSEPARATE 78: 79: ENTRY(suibyte) 80: mov nofault,-(sp) / set fault trap 81: mov $fsfault,nofault 82: mov 4(sp),r1 83: bic $1,r1 / r1 = addr&~1 84: mfpi (r1) / tmp = user instruction word at 85: cmp r1,6(sp) / (addr&~1) 86: beq 1f / if (addr&1) 87: movb 10(sp),1(sp) / *((char *)tmp + 1) = byte 88: br 2f 89: 1: / else 90: movb 10(sp),(sp) / *((char *)tmp) = byte 91: 2: 92: mtpi (r1) / user instruction word (addr&~1) = tmp 93: clr r0 / return success 94: mov (sp)+,nofault / restore fault trap, and return 95: rts pc 96: 97: 98: /* 99: * Fetch and set user word routines: 100: * fuiword(addr): fetch user instruction space word 101: * fuword(addr): fetch user data space word 102: * suiword(addr, word): set user instruction space word 103: * suword(addr, word): set user data space word 104: * caddr_t addr; 105: * u_short word; 106: * 107: * The fetch routines return the requested word or -1 on fault. The set 108: * routines return 0 on success, -1 on failure. Addr must be even. The data 109: * space routines are really the corresponding instruction space routines if 110: * NONSEPARATE is defined. 111: */ 112: ENTRY(fuword) 113: #ifndef NONSEPARATE 114: mov nofault,-(sp) / set fault trap 115: mov $fsfault,nofault 116: mov 4(sp),r1 / r1 = addr 117: mfpd (r1) / r0 = user data word at addr 118: mov (sp)+,r0 119: mov (sp)+,nofault / restore fault trap, and return 120: rts pc 121: #endif !NONSEPARATE 122: 123: ENTRY(fuiword) 124: mov nofault,-(sp) / set fault trap 125: mov $fsfault,nofault 126: mov 4(sp),r1 / r1 = addr 127: mfpi (r1) / r0 = user instruction word at addr 128: mov (sp)+,r0 129: mov (sp)+,nofault / restore fault trap, and return 130: rts pc 131: 132: ENTRY(suword) 133: #ifndef NONSEPARATE 134: mov nofault,-(sp) / set fault trap 135: mov $fsfault,nofault 136: mov 4(sp),r1 / r1 = addr 137: mov 6(sp),-(sp) / user data word at addr = word 138: mtpd (r1) 139: clr r0 / resturn success 140: mov (sp)+,nofault / restore fault trap, and return 141: rts pc 142: #endif !NONSEPARATE 143: 144: ENTRY(suiword) 145: mov nofault,-(sp) / set fault trap 146: mov $fsfault,nofault 147: mov 4(sp),r1 / r1 = adddr 148: mov 6(sp),-(sp) / user instruction word at addr = word 149: mtpi (r1) 150: clr r0 / return success 151: mov (sp)+,nofault / restore fault trap, and return 152: rts pc 153: 154: 155: /* 156: * Common fault trap for fetch/set user byte/word routines. Returns -1 to 157: * indicate fault. Stack contains saved fault trap followed by return 158: * address. 159: */ 160: fsfault: 161: mov (sp)+,nofault / restore fault trap, 162: mov $-1,r0 / return failure (-1) 163: rts pc 164: 165: 166: /* 167: * copyin(fromaddr, toaddr, length) 168: * caddr_t fromaddr, toaddr; 169: * u_int length; 170: * 171: * copyiin(fromaddr, toaddr, length) 172: * caddr_t fromaddr, toaddr; 173: * u_int length; 174: * 175: * Copy length/2 words from user space fromaddr to kernel space address 176: * toaddr. Fromaddr and toaddr must be even. Returns zero on success, 177: * EFAULT on failure. Copyin copies from data space, copyiin from 178: * instruction space. 179: */ 180: ENTRY(copyin) 181: #ifndef NONSEPARATE 182: jsr pc,copysetup / r1 = fromaddr, r2 = toaddr, 183: 1: / r0 = length/2 184: mfpd (r1)+ / do 185: mov (sp)+,(r2)+ / *toaddr++ = *fromaddr++ 186: sob r0,1b / while (--length) 187: br copycleanup 188: #endif !NONSEPARATE 189: 190: ENTRY(copyiin) 191: jsr pc,copysetup / r1 = fromaddr, r2 = toaddr, 192: 1: / r0 = length/2 193: mfpi (r1)+ / do 194: mov (sp)+,(r2)+ / *toaddr++ = *fromaddr++ 195: sob r0,1b / while (--length) 196: br copycleanup 197: 198: 199: /* 200: * copyout(fromaddr, toaddr, length) 201: * caddr_t fromaddr, toaddr; 202: * u_int length; 203: * 204: * copyiout(fromaddr, toaddr, length) 205: * caddr_t fromaddr, toaddr; 206: * u_int length; 207: * 208: * Copy length/2 words from kernel space fromaddr to user space address 209: * toaddr. Fromaddr and toaddr must be even. Returns zero on success, 210: * EFAULT on failure. Copyout copies to data space, copyiout to 211: * instruction space. 212: */ 213: ENTRY(copyout) 214: #ifndef NONSEPARATE 215: jsr pc,copysetup / r1 = fromaddr, r2 = toaddr, 216: 1: / r0 = length/2 217: mov (r1)+,-(sp) / do 218: mtpd (r2)+ / *toaddr++ = *fromaddr++ 219: sob r0,1b / while (--length) 220: br copycleanup 221: #endif !NONSEPARATE 222: 223: ENTRY(copyiout) 224: jsr pc,copysetup / r1 = fromaddr, r2 = toaddr, 225: 1: / r0 = length/2 226: mov (r1)+,-(sp) / do 227: mtpi (r2)+ / *toaddr++ = *fromaddr++ 228: sob r0,1b / while (--length) 229: br copycleanup 230: 231: 232: /* 233: * Common set up code for the copy(in|out) routines. Performs zero length 234: * check, set up fault trap, and loads fromaddr, toaddr and length into the 235: * registers r1, r2 and r0 respectively. Leaves old values of r2 and 236: * nofault on stack. 237: */ 238: copysetup: 239: mov (sp)+,r0 / snag return address 240: mov r2,-(sp) / reserve r2 for our use, 241: mov nofault,-(sp) / save nofault so we can set our own 242: mov r0,-(sp) / trap and push return address back 243: mov $copyfault,nofault 244: mov 14(sp),r0 / r0 = (unsigned)length/2 245: beq 1f / (exit early if length equals zero) 246: asr r0 247: bic $100000,r0 248: mov 10(sp),r1 / r1 = fromaddr 249: mov 12(sp),r2 / r2 = toaddr 250: rts pc 251: 252: 1: 253: tst (sp)+ / short circuit the copy for zero 254: br copycleanup / length returning "success" ... 255: 256: copyfault: 257: mov $EFAULT,r0 / we faulted out, return EFAULT 258: /*FALLTHROUGH*/ 259: 260: /* 261: * Common clean up code for the copy(in|out) routines. When copy routines 262: * finish successfully r0 has already been decremented to zero which is 263: * exactly what we want to return for success ... Tricky, hhmmm? 264: */ 265: copycleanup: 266: mov (sp)+,nofault / restore fault trap, 267: mov (sp)+,r2 / and reserved registers 268: rts pc 269: 270: 271: #ifdef INET 272: /* 273: * Kernel/Network copying routines. 274: * 275: * NOTE: 276: * The m[ft]sd functions operate at high ipl. This is done mostly 277: * because it's simpler to do a ``mov $10340,PS'' than ``bic $30000,PS; 278: * bis $10000,PS''. But these functions will never take up enough time 279: * to cause anyone any problems. 280: * 281: * WARNING: 282: * All functions assume that the segments in supervisor space 283: * containing the source or target variables are never remapped. 284: * 285: * void 286: * mtsd(addr, word) 287: * caddr_t addr; destination address in supervisor space 288: * int word word to store 289: * 290: * Move To Supervisor Data, simplified interface for the kernel to store 291: * single words in the supervisor data space. 292: */ 293: ENTRY(mtsd) 294: mov 2(sp),r0 / get the destination address 295: mov PS,-(sp) / save psw 296: mov $10340,PS / previous supervisor 297: mov 6(sp),-(sp) / grab word 298: mtpd (r0) / and store it in supervisor space 299: mov (sp)+,PS / restore psw 300: rts pc / return 301: 302: /* 303: * int 304: * mfsd(addr) 305: * caddr_t addr; source address in supervisor space 306: * 307: * Move From Supervisor Data, simplified interface for the kernel to get 308: * single words from the supervisor data space. 309: */ 310: ENTRY(mfsd) 311: mov 2(sp),r0 / get the address of the data 312: mov PS,-(sp) / save psw 313: mov $10340,PS / previous supervisor 314: mfpd (r0) / get the word 315: mov (sp)+,r0 / return value 316: mov (sp)+,PS / restore psw 317: rts pc / return 318: #endif 319: 320: 321: /* 322: * error = vcopyin(fromaddr, toaddr, length) 323: * int error; 324: * caddr_t fromaddr, toaddr; 325: * u_int length; 326: * 327: * Copy length bytes from user address space fromaddr to kernel space toaddr. 328: * Returns zero on success, EFAULT on failure. Vcopyin is only called when 329: * fromaddr, toaddr or length is odd and the length doesn't justify an 330: * fmove. 331: */ 332: ENTRY(vcopyin) 333: mov r2,-(sp) / allocate a couple registers 334: mov r3,-(sp) 335: mov nofault,-(sp) 336: mov $5f,nofault / set up error trap 337: mov 10(sp),r1 / r1 = fromaddr (user address) 338: mov 12(sp),r2 / r2 = toaddr (kernel address) 339: mov 14(sp),r0 / r0 = length 340: beq 4f / (exit early if 0) 341: bit $1,r1 / fromaddr odd? 342: beq 1f 343: dec r1 / yes, grab the even word and snarf 344: mfpd (r1)+ / the high byte to start us off 345: swab (sp) 346: movb (sp)+,(r2)+ 347: dec r0 348: 1: 349: mov r0,r3 / save trailing byte indicator and 350: asr r0 / convert length remaining to units of 351: beq 3f / words 352: 2: 353: mfpd (r1)+ / grab next word from user space 354: movb (sp),(r2)+ / move the first byte 355: swab (sp) / and the second ... 356: movb (sp)+,(r2)+ 357: sob r0,2b 358: 3: / r0 = 0 359: asr r3 / need to copy in trailing byte? 360: bcc 4f / nope, all done 361: mfpd (r1) / grab last word and take the low 362: movb (sp)+,(r2) / byte 363: 4: 364: mov (sp)+,nofault / restore error trap 365: mov (sp)+,r3 / restore registers 366: mov (sp)+,r2 367: rts pc / and return 368: 5: 369: mov $EFAULT,r0 / we got a memory fault give them the 370: br 4b / error 371: 372: 373: /* 374: * error = vcopyout(fromaddr, toaddr, length) 375: * int error; 376: * caddr_t fromaddr, toaddr; 377: * u_int length; 378: * 379: * Copy length bytes from kernel address space fromaddr to user space toaddr. 380: * Returns zero on success, EFAULT on failure. Vcopyout is only called when 381: * fromaddr, toaddr or length is odd and the length doesn't justify an fmove. 382: */ 383: ENTRY(vcopyout) 384: mov r2,-(sp) / allocate a couple extra registers 385: mov r3,-(sp) 386: mov nofault,-(sp) 387: mov $5f,nofault / set up error trap 388: mov 10(sp),r1 / r1 = fromaddr (kernel space) 389: mov 12(sp),r2 / r2 = toaddr (user address) 390: mov 14(sp),r0 / r0 = length 391: beq 4f / (exit early if 0) 392: bit $1,r2 / toaddr odd? 393: beq 1f 394: dec r2 / yes, grab even word so we can stuff 395: mfpd (r2) / our first byte into the high byte 396: movb (r1)+,1(sp) / of that word 397: mtpd (r2)+ 398: dec r0 399: 1: 400: mov r0,r3 / save trailing byte indicator and 401: asr r0 / convert length remaining to units of 402: beq 3f / words 403: 2: 404: movb (r1)+,-(sp) / form word to copy out on the stack 405: movb (r1)+,1(sp) 406: mtpd (r2)+ / and send it on its way 407: sob r0,2b 408: 3: / r0 = 0 409: asr r3 / need to copy out trailing byte? 410: bcc 4f / nope, all done 411: mfpd (r2) / have to stuff our last byte out so 412: movb (r1),(sp) / stick it into the lower byte and 413: mtpd (r2) / rewrite it 414: 4: 415: mov (sp)+,nofault / restore previous error trap 416: mov (sp)+,r3 / restore registers 417: mov (sp)+,r2 418: rts pc / and return 419: 5: 420: mov $EFAULT,r0 / user memory fault ... return 421: br 4b / EFAULT 422: 423: 424: /* 425: * error = copyinstr(fromaddr, toaddr, maxlength, &lencopied) 426: * int error; 427: * caddr_t fromaddr, toaddr; 428: * u_int maxlength, *lencopied; 429: * 430: * Copy a null terminated string from the user address space into the kernel 431: * address space. Returns zero on success, EFAULT on user memory management 432: * trap, ENOENT if maxlength exceeded. If lencopied is non-zero, *lencopied 433: * gets the length of the copy (including the null terminating byte). 434: */ 435: ENTRY(copyinstr) 436: mov r2,-(sp) / allocate a couple extra registers 437: mov r3,-(sp) 438: mov nofault,-(sp) 439: mov $7f,nofault / set up error trap 440: mov 10(sp),r1 / r1 = fromaddr (user address) 441: mov 12(sp),r2 / r2 = toaddr (kernel address) 442: mov 14(sp),r0 / r0 = maxlength (remaining space) 443: beq 3f / (exit early with ENOENT if 0) 444: bit $1,r1 / fromaddr odd? 445: beq 1f 446: dec r1 / yes, grab the even word to start 447: mfpd (r1)+ / us off 448: mov (sp)+,r3 449: br 2f / and enter the loop halfway in ... 450: 1: 451: mfpd (r1)+ / grab next word from user space 452: mov (sp)+,r3 453: movb r3,(r2)+ / move the first byte 454: beq 4f 455: dec r0 456: beq 3f 457: 2: 458: swab r3 / and the second ... 459: movb r3,(r2)+ 460: beq 4f 461: sob r0,1b 462: 3: 463: mov $ENOENT,r0 / ran out of room - indicate failure 464: br 5f / and exit ... 465: 4: 466: clr r0 / success! 467: 5: 468: tst 16(sp) / does the caller want the copy length? 469: beq 6f 470: sub 12(sp),r2 / yes, figure out how much we copied: 471: mov r2,*16(sp) / *lencopied = r2 {toaddr'} - toaddr 472: 6: 473: mov (sp)+,nofault / restore error trap 474: mov (sp)+,r3 / restore registers 475: mov (sp)+,r2 / and return 476: rts pc 477: 7: 478: mov $EFAULT,r0 / we got a memory fault give them the 479: br 5b / error 480: 481: 482: /* 483: * error = copyoutstr(fromaddr, toaddr, maxlength, lencopied) 484: * int error; 485: * caddr_t fromaddr, toaddr; 486: * u_int maxlength, *lencopied; 487: * 488: * Copy a null terminated string from the kernel address space to the user 489: * address space. Returns zero on success, EFAULT on user memory management 490: * trap, ENOENT if maxlength exceeded. If lencopied is non-zero, *lencopied 491: * gets the length of the copy (including the null terminating byte). Note 492: * that *lencopied will not by valid on EFAULT. 493: */ 494: 495: ENTRY(copyoutstr) 496: mov r2,-(sp) / allocate a couple extra registers 497: mov r3,-(sp) 498: mov nofault,-(sp) 499: mov $7f,nofault / set up error trap 500: 501: /* 502: * First find out how much we're going to be copying: 503: * min(strlen(fromaddr), maxlength). 504: */ 505: mov 10(sp),r0 / r0 = fromaddr (kernel address) 506: mov 14(sp),r1 / r1 = maxlength (remaining space) 507: beq 6f / (exit early with ENOENT if 0) 508: 1: 509: tstb (r0)+ / found null? 510: beq 2f 511: sob r1,1b / run out of room? 512: mov 14(sp),r0 / ran out of room: r0 = maxlength 513: br 3f 514: 2: 515: sub 10(sp),r0 / found null: r0 = strlen(fromaddr) 516: 3: 517: tst 16(sp) / does the caller want the copy length? 518: beq 4f / yes, 519: mov r0,*16(sp) / lencopied = r0 (invalid on EFAULT) 520: 4: 521: mov 10(sp),r1 / r1 = fromaddr (kernel space) 522: mov 12(sp),r2 / r2 = toaddr (user address) 523: bit $1,r2 / toaddr odd? 524: beq 5f 525: dec r2 / yes, grab even word so we can stuff 526: mfpd (r2) / our first byte into the high byte 527: movb (r1)+,1(sp) / of that word 528: mtpd (r2)+ 529: dec r0 530: 5: 531: mov r0,r3 / save trailing byte indicator and 532: asr r0 / convert space remaining to units of 533: beq 2f / words 534: 1: 535: movb (r1)+,-(sp) / form word to copy out on the stack 536: movb (r1)+,1(sp) 537: mtpd (r2)+ / and send it on its way 538: sob r0,1b 539: 2: 540: asr r3 / need to copy out trailing byte? 541: bcc 3f / nope, all done 542: mfpd (r2) / have to stuff our last byte out so 543: movb (r1)+,(sp) / stick it into the lower byte and 544: mtpd (r2) / rewrite it 545: 3: 546: movb -(r1),r0 / did we copy the null out? 547: beq 5f 548: 4: 549: mov $ENOENT,r0 / no, so indicate ENOENT 550: 5: 551: mov (sp)+,nofault / restore previous error trap 552: mov (sp)+,r3 / restore registers 553: mov (sp)+,r2 554: rts pc / and return 555: 556: /* 557: * Rapacious silliness here - someone has passed us maxlength == 0 ... 558: */ 559: 6: 560: tst 16(sp) / do they want to know about it? 561: beq 4b / (guess not ...) 562: clr *16(sp) / *lencopied = 0 563: br 4b / return ENOENT 564: 7: 565: mov $EFAULT,r0 / user memory fault ... return 566: br 5b / EFAULT