Annotation of kernel/machdep/i386/fault_copy.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.