|
|
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: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. ! 26: * ! 27: * File: machdep/i386/fault_copy.c ! 28: * Author: Bruce Martin, NeXT Computer, Inc. ! 29: * ! 30: * This file contains machine dependent code for kernel user copy ! 31: * on NeXT i386-based products. Currently tuned for the i486. ! 32: * ! 33: * HISTORY ! 34: * Oct-1-92 Bruce Martin ([email protected]) ! 35: * Created. ! 36: */ ! 37: ! 38: #import <mach/mach_types.h> ! 39: #import <sys/errno.h> ! 40: ! 41: #define MIN_TO_ALIGN 16 ! 42: #define UNROLL 4 ! 43: ! 44: /* ! 45: * Bytes to be moved by an unrolled loop ! 46: */ ! 47: #define LOOP_STRIDE(type) (UNROLL * sizeof(type)) ! 48: ! 49: /* ! 50: * Len modulo LOOP_STRIDE ! 51: */ ! 52: #define MODULO_LOOP_UNROLL(len, type) \ ! 53: ((len) & (LOOP_STRIDE(type) - 1) & ~(sizeof(type) - 1)) ! 54: ! 55: /* ! 56: * Convert a void * into a unsigned int so arithmetic can be done ! 57: * (Technically, the gnu C compiler is tolerant of arithmetic ! 58: * on void *, but ansi isn't; so we do this.) ! 59: */ ! 60: #define UNS(voidp) ((unsigned int)(voidp)) ! 61: ! 62: /* ! 63: * Number of bytes addr is past an integer alignment ! 64: */ ! 65: #define BYTES_PAST_INT_ALIGNMENT(voidp) (UNS(voidp) & (sizeof(int) - 1)) ! 66: ! 67: ! 68: /* ! 69: * Convert a 'void * + offset' into a char, short, or int reference ! 70: * based at that address. ! 71: */ ! 72: #define CHAR(voidp, offset) (*(char *)(UNS(voidp) + (offset))) ! 73: #define SHORT(voidp, offset) (*(short *)(UNS(voidp) + (offset))) ! 74: #define INT(voidp, offset) (*(int *)(UNS(voidp) + (offset))) ! 75: ! 76: #if defined(NX_CURRENT_COMPILER_RELEASE) && (NX_CURRENT_COMPILER_RELEASE < 320) ! 77: #define SIREG "e" ! 78: #else ! 79: #define SIREG "S" ! 80: #endif ! 81: ! 82: ! 83: ! 84: /* ! 85: * Maintain the recover field in the thread_t structure ! 86: */ ! 87: static inline void ! 88: set_recover(int (*vector)()) ! 89: { ! 90: current_thread()->recover = (vm_offset_t)vector; ! 91: return; ! 92: } ! 93: ! 94: static inline void ! 95: clear_recover() ! 96: { ! 97: current_thread()->recover = 0; ! 98: } ! 99: ! 100: ! 101: ! 102: /* ! 103: * Inline assembler macros used to build the copy routines ! 104: * ! 105: * The first set of routines move a single character or word. ! 106: */ ! 107: static inline void ! 108: _char_move_out(char *dst, char val) ! 109: { ! 110: asm volatile ( ! 111: "movb %0, %%fs:%1" ! 112: : /* no outputs */ ! 113: : "q" (val), "m" (*dst)); ! 114: } ! 115: ! 116: static inline void ! 117: _short_move_out(short *dst, short val) ! 118: { ! 119: asm volatile ( ! 120: "movw %0, %%fs:%1" ! 121: : /* no outputs */ ! 122: : "q" (val), "m" (*dst)); ! 123: } ! 124: ! 125: static inline void ! 126: _word_move_out(int *dst, int val) ! 127: { ! 128: asm volatile ( ! 129: "movl %0, %%fs:%1" ! 130: : /* no outputs */ ! 131: : "r" (val), "m" (*dst)); ! 132: } ! 133: ! 134: static inline char ! 135: _char_move_in(char *src) ! 136: { ! 137: char val; ! 138: asm volatile ( ! 139: "movb %%fs:(%1), %0" ! 140: : "=q" (val) ! 141: : "r" (src)); ! 142: return val; ! 143: } ! 144: ! 145: static inline int ! 146: _word_move_in(int *src) ! 147: { ! 148: int val; ! 149: asm volatile ( ! 150: "movl %%fs:(%1), %0" ! 151: : "=r" (val) ! 152: : "r" (src)); ! 153: return val; ! 154: } ! 155: ! 156: ! 157: ! 158: /* ! 159: * This set of routines move multiple words or characters ! 160: */ ! 161: static inline void ! 162: _fwd_char_copy(void *dst, const void *src, int len) ! 163: { ! 164: asm("rep; movsb" ! 165: : /* no outputs */ ! 166: : "&c" (len), "D" (dst), SIREG (src) ! 167: : "ecx", "esi", "edi"); ! 168: } ! 169: ! 170: static inline void ! 171: _fwd_char_copy_in(void *dst, const void *src, int len) ! 172: { ! 173: asm("rep; movsb %%fs:(%%esi), (%%edi)" ! 174: : /* no outputs */ ! 175: : "&c" (len), "D" (dst), SIREG (src) ! 176: : "ecx", "esi", "edi"); ! 177: } ! 178: ! 179: /* NOTE: we can't use rep;movsb because of segment override restrictions */ ! 180: static inline void ! 181: _fwd_char_copy_out(void *dst, const void *src, int len) ! 182: { ! 183: if (len & 0x1) { ! 184: _char_move_out(dst, CHAR(src, 0)); ! 185: UNS(dst) += sizeof(char); ! 186: UNS(src) += sizeof(char); ! 187: } ! 188: if (len & 0x2) { ! 189: _short_move_out(dst, SHORT(src, 0)); ! 190: UNS(dst) += sizeof(short); ! 191: UNS(src) += sizeof(short); ! 192: } ! 193: len >>= 2; ! 194: while (len--) { ! 195: _word_move_out(dst, INT(src, 0)); ! 196: UNS(dst) += sizeof(int); ! 197: UNS(src) += sizeof(int); ! 198: } ! 199: } ! 200: ! 201: ! 202: static inline void ! 203: _bkwd_char_copy(void *dst, const void *src, int len) ! 204: { ! 205: /* NOTE: assumes DF flag is set */ ! 206: UNS(src)--; ! 207: UNS(dst)--; ! 208: asm("rep; movsb" ! 209: : /* no outputs */ ! 210: : "&c" (len), "D" (dst), SIREG (src) ! 211: : "ecx", "esi", "edi"); ! 212: } ! 213: ! 214: ! 215: static inline void ! 216: _fwd_int_copy(void *dst, const void *src, int len) ! 217: { ! 218: asm("rep; movsl" ! 219: : /* no outputs */ ! 220: : "&c" (len>>2), "D" (dst), SIREG (src) ! 221: : "ecx", "esi", "edi"); ! 222: } ! 223: ! 224: static inline void ! 225: _fwd_int_copy_in(void *dst, const void *src, int len) ! 226: { ! 227: asm("rep; movsl %%fs:(%%esi), (%%edi)" ! 228: : /* no outputs */ ! 229: : "&c" (len>>2), "D" (dst), SIREG (src) ! 230: : "ecx", "esi", "edi"); ! 231: } ! 232: ! 233: /* NOTE: can't use rep;movsl because of segment override restrictions. */ ! 234: static inline void ! 235: _fwd_int_copy_out(void *dst, const void *src, int len) ! 236: { ! 237: int alignment; ! 238: alignment = MODULO_LOOP_UNROLL(len, int); ! 239: UNS(src) += alignment - LOOP_STRIDE(int); ! 240: UNS(dst) += alignment - LOOP_STRIDE(int); ! 241: switch (alignment) { ! 242: do { ! 243: UNS(src) += LOOP_STRIDE(int); ! 244: UNS(dst) += LOOP_STRIDE(int); ! 245: _word_move_out(&((int *)dst)[0], INT(src, 0)); ! 246: case 12: _word_move_out(&((int *)dst)[1], INT(src, 4)); ! 247: case 8: _word_move_out(&((int *)dst)[2], INT(src, 8)); ! 248: case 4: _word_move_out(&((int *)dst)[3], INT(src, 12)); ! 249: case 0: ! 250: /* ! 251: INT(dst, 0) = INT(src, 0); ! 252: case 12: INT(dst, 4) = INT(src, 4); ! 253: case 8: INT(dst, 8) = INT(src, 8); ! 254: case 4: INT(dst, 12) = INT(src, 12); ! 255: case 0: ! 256: */ ! 257: len -= LOOP_STRIDE(int); ! 258: } while (len >= 0); ! 259: } ! 260: } ! 261: ! 262: static inline void ! 263: _bkwd_int_copy(void *dst, const void *src, int len) ! 264: { ! 265: /* NOTE: assumes DF flag is set */ ! 266: UNS(dst) -= sizeof(int); ! 267: UNS(src) -= sizeof(int); ! 268: asm("rep; movsl" ! 269: : /* no outputs */ ! 270: : "&c" (len>>2), "D" (dst), SIREG (src) ! 271: : "ecx", "esi", "edi"); ! 272: } ! 273: ! 274: ! 275: ! 276: ! 277: ! 278: ! 279: /* ! 280: * Copy count bytes from %fs:(src) to (dst) ! 281: */ ! 282: inline ! 283: int copyin(char *src, char *dst, vm_size_t count) ! 284: { ! 285: int len = count; ! 286: int need_to_move; ! 287: ! 288: set_recover(&&do_fault); ! 289: ! 290: /* Always do a forward copy */ ! 291: ! 292: if (len < MIN_TO_ALIGN) { ! 293: _fwd_char_copy_in(dst, src, len); ! 294: return 0; ! 295: } ! 296: ! 297: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) { ! 298: need_to_move = sizeof(int) - need_to_move; ! 299: _fwd_char_copy_in(dst, src, need_to_move); ! 300: len -= need_to_move; ! 301: UNS(dst) += need_to_move; ! 302: UNS(src) += need_to_move; ! 303: } ! 304: ! 305: _fwd_int_copy_in(dst, src, len); ! 306: ! 307: if (need_to_move = (len & 3)) { ! 308: UNS(src) += (len & ~3); ! 309: UNS(dst) += (len & ~3); ! 310: switch(need_to_move) { ! 311: case 3: dst[2] = _char_move_in(&src[2]); ! 312: case 2: dst[1] = _char_move_in(&src[1]); ! 313: case 1: dst[0] = _char_move_in(&src[0]); ! 314: } ! 315: } ! 316: clear_recover(); ! 317: return 0; ! 318: ! 319: do_fault: ! 320: clear_recover(); ! 321: return EFAULT; ! 322: } ! 323: ! 324: int copyinmsg(char *src, char *dst, vm_size_t count) ! 325: { ! 326: return copyin(src, dst, count); ! 327: } ! 328: ! 329: /* ! 330: * Copy count bytes from (src) to (dst) ! 331: */ ! 332: int copywithin(char *src, char *dst, vm_size_t count) ! 333: { ! 334: int len = count; ! 335: int need_to_move; ! 336: ! 337: set_recover(&&do_fault); ! 338: ! 339: /* Always do a forward copy */ ! 340: ! 341: if (len < MIN_TO_ALIGN) { ! 342: _fwd_char_copy(dst, src, len); ! 343: return 0; ! 344: } ! 345: ! 346: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) { ! 347: need_to_move = sizeof(int) - need_to_move; ! 348: _fwd_char_copy(dst, src, need_to_move); ! 349: len -= need_to_move; ! 350: UNS(dst) += need_to_move; ! 351: UNS(src) += need_to_move; ! 352: } ! 353: ! 354: _fwd_int_copy(dst, src, len); ! 355: ! 356: if (need_to_move = (len & 3)) { ! 357: UNS(src) += (len & ~3); ! 358: UNS(dst) += (len & ~3); ! 359: switch(need_to_move) { ! 360: case 3: dst[2] = src[2]; ! 361: case 2: dst[1] = src[1]; ! 362: case 1: dst[0] = src[0]; ! 363: } ! 364: } ! 365: clear_recover(); ! 366: return 0; ! 367: ! 368: do_fault: ! 369: clear_recover(); ! 370: return EFAULT; ! 371: } ! 372: ! 373: ! 374: /* ! 375: * Copy count bytes from (src) to %fs:(dst) ! 376: */ ! 377: inline ! 378: int copyout(char *src, char *dst, vm_size_t count) ! 379: { ! 380: int len = count; ! 381: int need_to_move; ! 382: ! 383: set_recover(&&do_fault); ! 384: ! 385: /* Always do a forward copy */ ! 386: ! 387: if (len < MIN_TO_ALIGN) { ! 388: _fwd_char_copy_out(dst, src, len); ! 389: return 0; ! 390: } ! 391: ! 392: if (need_to_move = BYTES_PAST_INT_ALIGNMENT(src)) { ! 393: need_to_move = sizeof(int) - need_to_move; ! 394: _fwd_char_copy_out(dst, src, need_to_move); ! 395: len -= need_to_move; ! 396: UNS(dst) += need_to_move; ! 397: UNS(src) += need_to_move; ! 398: } ! 399: ! 400: _fwd_int_copy_out(dst, src, len); ! 401: ! 402: if (need_to_move = (len & 3)) { ! 403: UNS(src) += (len & ~3); ! 404: UNS(dst) += (len & ~3); ! 405: switch(need_to_move) { ! 406: case 3: _char_move_out(&dst[2], src[2]); ! 407: case 2: _char_move_out(&dst[1], src[1]); ! 408: case 1: _char_move_out(&dst[0], src[0]); ! 409: } ! 410: } ! 411: clear_recover(); ! 412: return 0; ! 413: ! 414: do_fault: ! 415: clear_recover(); ! 416: return EFAULT; ! 417: } ! 418: ! 419: int copyoutmsg(char *src, char *dst, vm_size_t count) ! 420: { ! 421: return copyout(src, dst, count); ! 422: } ! 423: ! 424: ! 425: /* ! 426: * copy up to max bytes from src to dst. Return number of bytes copied in len. ! 427: */ ! 428: int copystr(const char *src, char *dst, int max, int *len) ! 429: { ! 430: int i = max; ! 431: ! 432: set_recover(&&do_fault); ! 433: while (i-- > 0) { ! 434: if (!(*dst++ = *src++)) ! 435: break; ! 436: } ! 437: ! 438: if (len) ! 439: *len = max - i; ! 440: clear_recover(); ! 441: return 0; ! 442: ! 443: do_fault: ! 444: clear_recover(); ! 445: return EFAULT; ! 446: } ! 447: ! 448: ! 449: /* ! 450: * Same as copystr, but moves bytes from %fs:src to dst ! 451: */ ! 452: int copyinstr(char *src, char *dst, int max, int *len) ! 453: { ! 454: int i = max; ! 455: ! 456: set_recover(&&do_fault); ! 457: while (i-- > 0) { ! 458: char c; ! 459: c = dst[0] = _char_move_in(src); ! 460: dst++; ! 461: src++; ! 462: if (!c) ! 463: break; ! 464: } ! 465: ! 466: if (len) ! 467: *len = max - i; ! 468: clear_recover(); ! 469: return 0; ! 470: ! 471: do_fault: ! 472: clear_recover(); ! 473: return EFAULT; ! 474: } ! 475: ! 476: ! 477: /* ! 478: * Same as copystr, but moves bytes from src to %fs:dst ! 479: */ ! 480: int copyoutstr(char *src, char *dst, int max, int *len) ! 481: { ! 482: int i = max; ! 483: ! 484: set_recover(&&do_fault); ! 485: while (i-- > 0) { ! 486: char c; ! 487: c = *src; ! 488: _char_move_out(dst, c); ! 489: dst++; ! 490: src++; ! 491: if (!c) ! 492: break; ! 493: } ! 494: ! 495: if (len) ! 496: *len = max - i; ! 497: clear_recover(); ! 498: return 0; ! 499: ! 500: do_fault: ! 501: clear_recover(); ! 502: return EFAULT; ! 503: } ! 504: ! 505: ! 506: ! 507: ! 508: int fuword(int *addr) ! 509: { ! 510: int val; ! 511: set_recover(&&do_fault); ! 512: val = _word_move_in(addr); ! 513: clear_recover(); ! 514: return val; ! 515: ! 516: do_fault: ! 517: clear_recover(); ! 518: return -1; ! 519: } ! 520: ! 521: ! 522: char fubyte(char *addr) ! 523: { ! 524: int val; ! 525: ! 526: set_recover(&&do_fault); ! 527: val = _char_move_in(addr); ! 528: clear_recover(); ! 529: return val; ! 530: ! 531: do_fault: ! 532: clear_recover(); ! 533: return -1; ! 534: } ! 535: ! 536: ! 537: char fuibyte(char *addr) ! 538: { ! 539: int val; ! 540: ! 541: set_recover(&&do_fault); ! 542: val = _char_move_in(addr); ! 543: clear_recover(); ! 544: return val; ! 545: ! 546: do_fault: ! 547: clear_recover(); ! 548: return -1; ! 549: } ! 550: ! 551: ! 552: ! 553: int suword(int *addr, int val) ! 554: { ! 555: set_recover(&&do_fault); ! 556: _word_move_out(addr, val); ! 557: clear_recover(); ! 558: return 0; ! 559: ! 560: do_fault: ! 561: clear_recover(); ! 562: return -1; ! 563: } ! 564: ! 565: ! 566: int subyte(char *addr, char val) ! 567: { ! 568: set_recover(&&do_fault); ! 569: _char_move_out(addr, val); ! 570: clear_recover(); ! 571: return 0; ! 572: ! 573: do_fault: ! 574: clear_recover(); ! 575: return -1; ! 576: } ! 577: ! 578: ! 579: int ! 580: suibyte(char *addr, char val) ! 581: { ! 582: set_recover(&&do_fault); ! 583: _char_move_out(addr, val); ! 584: clear_recover(); ! 585: return 0; ! 586: ! 587: do_fault: ! 588: clear_recover(); ! 589: return -1; ! 590: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.