|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1997 Apple Computer, Inc. All rights reserved. ! 27: * Copyright (c) 1994 NeXT Computer, Inc. All rights reserved. ! 28: * ! 29: * machdep/ppc/fault_copy.c ! 30: * ! 31: * Machine dependent code for kernel user copy ! 32: * ! 33: * History : ! 34: * 22-Jul-1998 Umesh Vaishampayan ([email protected]) ! 35: * Added safe_bzero(). ! 36: * ! 37: * 30-Mar-1998 Umesh Vaishampayan ([email protected]) ! 38: * Made the copy routines more robust. ! 39: * ! 40: * 22-Sep-1997 Umesh Vaishampayan ([email protected]) ! 41: * Fixed error return from ENOENT to ENAMETOOLONG. ! 42: * ! 43: * March, 1997 Umesh Vaishampayan [[email protected]] ! 44: * Created from sparc. ! 45: * ! 46: */ ! 47: ! 48: #include <diagnostic.h> ! 49: #include <mach/mach_types.h> ! 50: #include <sys/param.h> ! 51: #include <sys/errno.h> ! 52: #include <machine/setjmp.h> ! 53: #include <machine/label_t.h> ! 54: ! 55: #undef NBSEG ! 56: #define NBSEG 0x10000000 ! 57: #undef SEGMASK ! 58: #define SEGMASK (NBSEG-1) ! 59: #define PGOFFSET(x) ((unsigned)x & (NBPG-1)) ! 60: #undef SEGOFFSET ! 61: #define SEGOFFSET(x) ((unsigned)(x) & SEGMASK) ! 62: ! 63: ! 64: caddr_t cioseg(space_t space, caddr_t addr); ! 65: ! 66: int ! 67: safe_bcopy(caddr_t src, caddr_t dst, int len) ! 68: { ! 69: int error = 0; ! 70: label_t jmpbuf; ! 71: vm_offset_t tmpbuf = current_thread()->recover; ! 72: ! 73: #if DIAGNOSTIC ! 74: if(tmpbuf) ! 75: kprintf("safe_bcopy() ****** NESTED SETJUMP ******\n"); ! 76: #endif /* DIAGNOSTIC */ ! 77: ! 78: if (setjmp(&jmpbuf)) { ! 79: error = EFAULT; ! 80: } else { ! 81: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 82: bcopy(src, dst, len); ! 83: } ! 84: current_thread()->recover = (vm_offset_t)tmpbuf; ! 85: ! 86: return(error); ! 87: } ! 88: ! 89: int ! 90: safe_bzero(void *dst, unsigned long ulen) ! 91: { ! 92: int error = 0; ! 93: label_t jmpbuf; ! 94: vm_offset_t tmpbuf = current_thread()->recover; ! 95: ! 96: #if DIAGNOSTIC ! 97: if (tmpbuf) ! 98: kprintf("safe_bzero() ****** NESTED SETJUMP ******\n"); ! 99: #endif /* DIAGNOSTIC */ ! 100: ! 101: if (setjmp(&jmpbuf)) { ! 102: error = EFAULT; ! 103: } else { ! 104: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 105: bzero(dst, ulen); ! 106: } ! 107: current_thread()->recover = (vm_offset_t)tmpbuf; ! 108: ! 109: return(error); ! 110: } ! 111: ! 112: ! 113: int ! 114: lbcopytoz(from, to, maxlen) ! 115: register caddr_t from, to; ! 116: unsigned maxlen; ! 117: { ! 118: register unsigned l; ! 119: ! 120: for (l = 0; l < maxlen; l++) { ! 121: if (*from == '\0') ! 122: return l; ! 123: *to++ = *from++; ! 124: } ! 125: return maxlen; ! 126: } ! 127: ! 128: /* ! 129: * copy a null terminated string from the user address space into ! 130: * the kernel address space. ! 131: * - if the user is denied read access, return EFAULT ! 132: * - if the end of string isn't found before ! 133: * maxlen bytes are copied, return ENAMETOOLONG, ! 134: * indicating an incomplete copy. ! 135: * - otherwise, return 0, indicating success. ! 136: * the number of bytes copied is always returned in lencopied. ! 137: */ ! 138: int ! 139: copyinstr(from, to, maxlen, lencopied) ! 140: caddr_t from, to; ! 141: unsigned maxlen, *lencopied; ! 142: { ! 143: unsigned segroom, room = maxlen; ! 144: caddr_t oto = to; ! 145: caddr_t mapped_from; ! 146: unsigned l; ! 147: int error = 0; ! 148: label_t jmpbuf; ! 149: vm_offset_t tmpbuf = current_thread()->recover; ! 150: ! 151: #if DIAGNOSTIC ! 152: if(tmpbuf) ! 153: kprintf("copyinstr() ****** NESTED SETJUMP ******\n"); ! 154: #endif /* DIAGNOSTIC */ ! 155: ! 156: if (setjmp(&jmpbuf)) { ! 157: error = EFAULT; ! 158: } else { ! 159: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 160: do { ! 161: /* calc # of bytes to transfer from this seg. */ ! 162: segroom = MIN(room, NBSEG - SEGOFFSET(from)); ! 163: ! 164: mapped_from = cioseg(current_task()->map->pmap->space,from); ! 165: /* this *does not* copy a terminating null */ ! 166: l = lbcopytoz(mapped_from, to, segroom); ! 167: ! 168: room -= l; ! 169: from += l; ! 170: to += l; ! 171: } while (l == segroom && room > 0); ! 172: } ! 173: ! 174: if (room == 0) ! 175: error = ENAMETOOLONG; ! 176: ! 177: if (error == 0) ! 178: *to++ = '\0'; // NULL terminate ! 179: ! 180: current_thread()->recover = (vm_offset_t)tmpbuf; ! 181: ! 182: if (lencopied) ! 183: *lencopied = to - oto; ! 184: ! 185: return error; ! 186: } ! 187: ! 188: /* ! 189: * Copy count bytes from (src) to (dst) ! 190: */ ! 191: int ! 192: copywithin(src, dst, count) ! 193: caddr_t src,dst; ! 194: unsigned count; ! 195: { ! 196: int error = 0; ! 197: label_t jmpbuf; ! 198: vm_offset_t tmpbuf = current_thread()->recover; ! 199: ! 200: if (setjmp(&jmpbuf)) { ! 201: error = EFAULT; ! 202: } ! 203: else { ! 204: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 205: bcopy(src,dst,count); ! 206: } ! 207: ! 208: current_thread()->recover = (vm_offset_t)tmpbuf; ! 209: return (error); ! 210: } ! 211: ! 212: caddr_t view_user_address(caddr_t addr); ! 213: int kdp_map_segment(unsigned int segment); ! 214: ! 215: /* ! 216: * Copy count bytes from (src) to (dst) where one is user space ! 217: */ ! 218: int ! 219: copy_for_kdp_user(src, dst, count, dir) ! 220: caddr_t src,dst; ! 221: unsigned count; ! 222: int dir; ! 223: { ! 224: caddr_t msrc, mdst, ptr; ! 225: unsigned mcount; ! 226: int seg; ! 227: int rtn_value; ! 228: ! 229: #define SEG_NUM(x) ((((unsigned int)(x))>>28)&0xF) ! 230: #define SEG_ADDR(x, y) ((((unsigned int)(x)) << 28) | (((unsigned int)(y)) & 0x0FFFFFFF)) ! 231: ! 232: rtn_value = 0; ! 233: while (count > 0) { ! 234: if (dir) { ! 235: ptr = dst; ! 236: seg = kdp_map_segment(SEG_NUM(ptr)); ! 237: if (seg < 0) { ! 238: return 1; ! 239: } ! 240: mdst = view_user_address(SEG_ADDR(seg, ptr)); ! 241: msrc = src; ! 242: } else { ! 243: ptr = src; ! 244: mdst = dst; ! 245: seg = kdp_map_segment(SEG_NUM(ptr)); ! 246: if (seg < 0) { ! 247: return 1; ! 248: } ! 249: msrc = view_user_address(SEG_ADDR(seg, ptr)); ! 250: } ! 251: if (SEG_NUM(ptr) != SEG_NUM(ptr+count-1)) { ! 252: mcount = 0x10000000 - SEG_ADDR(0, ptr); ! 253: count -= mcount; ! 254: src += mcount; ! 255: dst += mcount; ! 256: } else { ! 257: mcount = count; ! 258: count = 0; ! 259: } ! 260: rtn_value |= safe_bcopy(msrc,mdst,mcount); ! 261: } ! 262: return rtn_value; ! 263: } ! 264: ! 265: /* ! 266: * Copy count bytes from (src) to (dst) ! 267: */ ! 268: int ! 269: copy_for_kdp(src, dst, count, dir) ! 270: vm_offset_t src,dst; ! 271: unsigned count; ! 272: int dir; ! 273: { ! 274: int rtn_value = 0; ! 275: ! 276: if (dir) { ! 277: if (dst > VM_MAX_KERNEL_ADDRESS) { ! 278: rtn_value = copy_for_kdp_user(src, dst, count, 1); ! 279: } else if (dst >= VM_MIN_KERNEL_ADDRESS) { ! 280: rtn_value = safe_bcopy(src, dst, count); ! 281: kdp_flush_icache(dst, count); ! 282: } ! 283: } else { ! 284: if (src > VM_MAX_KERNEL_ADDRESS) { ! 285: rtn_value = copy_for_kdp_user(src, dst, count, 0); ! 286: } else { ! 287: rtn_value = safe_bcopy(src, dst, count); ! 288: } ! 289: } ! 290: return rtn_value; ! 291: } ! 292: ! 293: /* ! 294: * copy a null terminated string from one point to another in ! 295: * the kernel address space. ! 296: * - no access checks are performed. ! 297: * - if the end of string isn't found before ! 298: * maxlen bytes are copied, return ENAMETOOLONG, ! 299: * indicating an incomplete copy. ! 300: * - otherwise, return 0, indicating success. ! 301: * the number of bytes copied is always returned in lencopied. ! 302: */ ! 303: int ! 304: copystr(from, to, maxlen, lencopied) ! 305: register caddr_t from, to; ! 306: unsigned maxlen, *lencopied; ! 307: { ! 308: register unsigned l; ! 309: int error = 0; ! 310: label_t jmpbuf; ! 311: vm_offset_t tmpbuf = current_thread()->recover; ! 312: ! 313: #if DIAGNOSTIC ! 314: if(tmpbuf) ! 315: kprintf("copystr() ****** NESTED SETJUMP ******\n"); ! 316: #endif /* DIAGNOSTIC */ ! 317: ! 318: if (setjmp(&jmpbuf)) { ! 319: error = EFAULT; ! 320: } else { ! 321: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 322: for (l = 0; l < maxlen; l++) ! 323: if ((*to++ = *from++) == '\0') { ! 324: if (lencopied) ! 325: *lencopied = l + 1; ! 326: error = 0; ! 327: goto out; ! 328: } ! 329: if (lencopied) ! 330: *lencopied = maxlen; ! 331: error = ENAMETOOLONG; ! 332: } ! 333: out: ! 334: current_thread()->recover = (vm_offset_t)tmpbuf; ! 335: return (error); ! 336: } ! 337: ! 338: /* ! 339: * copy a null terminated string from the kernel address space into ! 340: * the user address space. ! 341: * - if the user is denied write access, return EFAULT. ! 342: * - if the end of string isn't found before ! 343: * maxlen bytes are copied, return ENAMETOOLONG, ! 344: * indicating an incomplete copy. ! 345: * - otherwise, return 0, indicating success. ! 346: * the number of bytes copied is always returned in lencopied. ! 347: */ ! 348: int ! 349: copyoutstr(from, to, maxlen, lencopied) ! 350: caddr_t from, to; ! 351: unsigned maxlen, *lencopied; ! 352: { ! 353: unsigned segroom, room = maxlen; ! 354: caddr_t oto = to; ! 355: caddr_t mapped_to; ! 356: unsigned l; ! 357: int error = 0; ! 358: label_t jmpbuf; ! 359: vm_offset_t tmpbuf = current_thread()->recover; ! 360: ! 361: #if DIAGNOSTIC ! 362: if(tmpbuf) ! 363: kprintf("copyoutstr() ****** NESTED SETJUMP ******\n"); ! 364: #endif /* DIAGNOSTIC */ ! 365: ! 366: if (setjmp(&jmpbuf)) { ! 367: error = EFAULT; ! 368: } else { ! 369: current_thread()->recover = (vm_offset_t)&jmpbuf; ! 370: do { ! 371: /* calc # of bytes to transfer from this seg. */ ! 372: segroom = MIN(room, NBSEG - SEGOFFSET(to)); ! 373: ! 374: mapped_to = cioseg(current_task()->map->pmap->space,to); ! 375: ! 376: /* this *does not* copy a terminating null */ ! 377: l = lbcopytoz(from, mapped_to, segroom); ! 378: ! 379: room -= l; ! 380: from += l; ! 381: to += l; ! 382: mapped_to += l; // for NULL whenever ! 383: } while (l == segroom && room > 0); ! 384: ! 385: /* set terminating NULL */ ! 386: *mapped_to = '\0'; ! 387: to++; ! 388: } ! 389: ! 390: if (room == 0) ! 391: error = ENAMETOOLONG; ! 392: ! 393: if (lencopied) ! 394: *lencopied = to - oto; ! 395: ! 396: current_thread()->recover = (vm_offset_t)tmpbuf; ! 397: return error; ! 398: } ! 399: ! 400: #undef PGOFFSET ! 401: ! 402: int ! 403: copyin(void *src, void *dst, size_t len) ! 404: { ! 405: thread_t self = current_thread(); ! 406: vm_offset_t tmpbuf = self->recover; ! 407: label_t jmpbuf; ! 408: int error = 0; ! 409: void *tsrc; ! 410: size_t tlen; ! 411: ! 412: #if DIAGNOSTIC ! 413: if(tmpbuf) ! 414: kprintf("copyin() ****** NESTED SETJUMP ******\n"); ! 415: #endif /* DIAGNOSTIC */ ! 416: ! 417: if (setjmp(&jmpbuf)) { ! 418: error = EFAULT; ! 419: } ! 420: else { ! 421: self->recover = (vm_offset_t)&jmpbuf; ! 422: while (len > 0) { ! 423: tlen = ((SEGOFFSET(src) + len) > NBSEG) ? ! 424: NBSEG - SEGOFFSET(src) : len; ! 425: tsrc = cioseg(self->task->map->pmap->space, src); ! 426: bcopy(tsrc, dst, tlen); ! 427: src += tlen; ! 428: dst += tlen; ! 429: len -= tlen; ! 430: } ! 431: } ! 432: self->recover = (vm_offset_t)tmpbuf; ! 433: return(error); ! 434: } ! 435: ! 436: int ! 437: copyout(void *src, void *dst, size_t len) ! 438: { ! 439: thread_t self = current_thread(); ! 440: vm_offset_t tmpbuf = self->recover; ! 441: label_t jmpbuf; ! 442: int error = 0; ! 443: void *tdst; ! 444: size_t tlen; ! 445: ! 446: #if DIAGNOSTIC ! 447: if(tmpbuf) ! 448: kprintf("copyout() ****** NESTED SETJUMP ******\n"); ! 449: #endif /* DIAGNOSTIC */ ! 450: ! 451: if (setjmp(&jmpbuf)) { ! 452: error = EFAULT; ! 453: } ! 454: else { ! 455: self->recover = (vm_offset_t)&jmpbuf; ! 456: while (len > 0) { ! 457: tlen = ((SEGOFFSET(dst) + len) > NBSEG) ? ! 458: NBSEG - SEGOFFSET(dst) : len; ! 459: tdst = cioseg(self->task->map->pmap->space, dst); ! 460: bcopy(src, tdst, tlen); ! 461: src += tlen; ! 462: dst += tlen; ! 463: len -= tlen; ! 464: } ! 465: } ! 466: self->recover = (vm_offset_t)tmpbuf; ! 467: return(error); ! 468: } ! 469: ! 470: int ! 471: copyinmsg(caddr_t src, caddr_t dst, int len) ! 472: { ! 473: return(copyin(src,dst,len)); ! 474: } ! 475: ! 476: int ! 477: copyoutmsg(caddr_t src, caddr_t dst, int len) ! 478: { ! 479: return(copyout(src, dst, len)); ! 480: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.