Annotation of driverkit/libDriver/Kernel/IOMemoryDescriptor.m, 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:  * IOMemoryDescriptor.m
                     26:  * Copyright 1997-98 Apple Computer Inc. All Rights Reserved.
                     27:  *
                     28:  * IOMemoryDescriptor describes the client memory needed to perform an I/O
                     29:  * request. It contains a single IOMemoryContainer that describes one or
                     30:  * more ranges of memory.  IOMemoryDescriptor is used directly for simple
                     31:  * (non-RAID) transfers, and is the underlying object used for striped or
                     32:  * mirrored requests. Logical and Physical memory cannot be mixed in a single
                     33:  * IOMemoryDescriptor. Several IOMemoryDescriptors may reference a single
                     34:  * IOMemoryContainer (by using the replicate method).
                     35:  */
                     36: #import <driverkit/IOMemoryDescriptor.h>
                     37: #import <mach/vm_param.h>
                     38: #import <limits.h>
                     39: 
                     40: /*
                     41:  * Compute the start of the next physical page
                     42:  */
                     43: #define next_page(x)   (trunc_page(((unsigned int) x) + page_size))
                     44: 
                     45: @interface IOMemoryDescriptor(Private)
                     46: /**
                     47:  * Initialize an IOMemoryDescriptor object.
                     48:  */
                     49: - (id)                 initWithIOMemoryContainer
                     50:                                : (IOMemoryContainer *) ioMemoryContainer;
                     51: /**
                     52:  * Free the descriptor and it's container.
                     53:  */
                     54: - (id)                 free;
                     55: /*
                     56:  * validate is called when the state needs to be validated.
                     57:  */
                     58: - (void)               validate;
                     59: /*
                     60:  * Retrieve the current logical range (returns a zero-length range on failure).
                     61:  */
                     62: - (void)               getCurrentLogicalRange;
                     63: 
                     64: /*
                     65:  * Retrieve the current physical range. This can fail if the O.S. returns
                     66:  * an error status.
                     67:  */
                     68: - (IOReturn)           getCurrentPhysicalRange;
                     69: 
                     70: /*
                     71:  * Force the state to the end of the entire container (for reposition
                     72:  * errors).
                     73:  */
                     74: - (void)               setPositionAtEnd;
                     75: @end /* IOMemoryContainer(Private) */
                     76: 
                     77: @implementation IOMemoryDescriptor(Private)
                     78: /**
                     79:  * Create an empty IOMemoryDescriptor object.
                     80:  */
                     81: - (id)                 initWithIOMemoryContainer
                     82:                                : (IOMemoryContainer *) thisIOMemoryContainer
                     83: {
                     84:        ioMemoryContainer       = thisIOMemoryContainer;
                     85:        state.currentOffset     = 0;
                     86:        retainCount             = 1;
                     87:        valid                   = FALSE;        /* Resets other values      */
                     88:        [self setMaxSegmentCount : UINT_MAX];
                     89:        return (self);
                     90: }
                     91: 
                     92: /**
                     93:  * Dispose of the object. This decrements the IOMemoryContainer's
                     94:  * reference count and frees the IOMemoryContainer if this IOMemoryDescriptor
                     95:  * is the last referencer.
                     96:  */
                     97: -                              free
                     98: {
                     99:        [ioMemoryContainer release];
                    100:        return ([super free]);
                    101: }
                    102: 
                    103: /**
                    104:  * Extract the next logical range from the IOMemoryContainer.
                    105:  * If this fails because rangeIndex exceeds the container max,
                    106:  * a zero-length range will be returned.
                    107:  */
                    108: - (void)               getCurrentLogicalRange
                    109: {
                    110:     if ([ioMemoryContainer logicalRange: &state.ioRange
                    111:                                   index: state.rangeIndex] != IO_R_SUCCESS) {
                    112:            state.ioRange.start         = 0xDEADBEEF;
                    113:            state.ioRange.size          = 0xFFFFFFFF;
                    114:        }
                    115:        state.logicalOffset             = 0;
                    116:        state.physicalOffset            = 0;
                    117: }
                    118: 
                    119: /**
                    120:  * Return the physical address that corresponds to the current logical
                    121:  * address. The state is valid at this point. This method sets the
                    122:  * physicalPageLength to the maximumn number of bytes that can be
                    123:  * transferred in this page.
                    124:  */
                    125: - (IOReturn)           getCurrentPhysicalRange
                    126: {
                    127:        IOReturn                ioReturn;
                    128:        unsigned int            nextPageAddress;
                    129:        
                    130:        state.physicalOffset = 0;       /* At page start        */
                    131:        ioReturn        = IOPhysicalFromVirtual(
                    132:                                [ioMemoryContainer client],
                    133:                                state.ioRange.start + state.logicalOffset,
                    134:                                (vm_offset_t *) &state.physical.address
                    135:                        );
                    136:        if (ioReturn != IO_R_SUCCESS) {
                    137:                     state.physical.address     = 0;
                    138:             state.physical.length      = 0;
                    139:        }
                    140:        else {
                    141:            /*
                    142:             * The amount we can transfer is the number of bytes
                    143:             * from the current start index to the next page
                    144:             * (limited by scsiReq->maxTransfer). Mach lacks
                    145:             * a method for determining the page size. We'll
                    146:             * use 4096 for convenience (the only cost is extra
                    147:             * cycles through the for loop).
                    148:             */
                    149:             nextPageAddress = next_page(state.physical.address);
                    150:             state.physical.length =
                    151:                        nextPageAddress - ((unsigned int) state.physical.address);
                    152:        }
                    153:        return (ioReturn);
                    154: }
                    155: 
                    156: /**
                    157:  * Validate the state so that all state values agree with
                    158:  * the currentOffset.
                    159:  */
                    160: - (void)               validate
                    161: {
                    162:        unsigned int    totalByteCount = [ioMemoryContainer totalByteCount];
                    163:        unsigned int    totalRangeCount = [ioMemoryContainer rangeCount];
                    164: 
                    165:        if (state.currentOffset >= totalByteCount) {
                    166:            [self setPositionAtEnd];
                    167:        }
                    168:        else {
                    169:            unsigned int        offsetAtRangeStart = 0;
                    170:            unsigned int        offsetAtRangeEnd;
                    171:            for (state.rangeIndex = 0;
                    172:                        state.rangeIndex < totalRangeCount;
                    173:                        state.rangeIndex++) {
                    174: 
                    175:                 /* Check for an invalid range or other problems */
                    176:                [self getCurrentLogicalRange];
                    177:                if (0xDEADBEEF == state.ioRange.start
                    178:                &&  0xFFFFFFFF == state.ioRange.size) {
                    179:                    IOPanic("IOMemoryDescriptor: "
                    180:                             "validate fell of the end of the world\n");
                    181:                }
                    182:                offsetAtRangeEnd = offsetAtRangeStart + state.ioRange.size;
                    183:                if (offsetAtRangeEnd > state.currentOffset) {
                    184:                    state.logicalOffset =
                    185:                        state.currentOffset - offsetAtRangeStart;
                    186:                    break;                      /* Normal exit          */
                    187:                }
                    188:                offsetAtRangeStart = offsetAtRangeEnd;
                    189:            }
                    190:            if (state.rangeIndex >= totalRangeCount) {
                    191:                [self setPositionAtEnd];        /* Bug: can't happen    */
                    192:            }
                    193:        }
                    194:        state.physicalOffset = 0;               /* Invalidate physical  */
                    195:        valid = TRUE;
                    196: }
                    197: 
                    198: /*
                    199:  * Force the state to the end of the entire container (for reposition
                    200:  * errors).
                    201:  */
                    202: - (void)               setPositionAtEnd
                    203: {
                    204:        state.rangeIndex = [ioMemoryContainer rangeCount] - 1;
                    205:        [self getCurrentLogicalRange];
                    206:        state.logicalOffset = state.ioRange.size;
                    207: }
                    208: 
                    209: @end /* IOMemoryDescriptor(Private) */
                    210: 
                    211: @implementation IOMemoryDescriptor
                    212: 
                    213: /**
                    214:  * Initialize an IOMemoryDescriptor object for a logical scatter-gather list.
                    215:  * The scatter-gather list is provided in DriverKit IORange format. If byReference
                    216:  * is TRUE, the associated IOMemoryContainer will hold a reference to the range
                    217:  * vector (which must remain addressable during the lifetime of the object). If
                    218:  * FALSE, the range vector will be copied into the IOMemoryContainer object.
                    219:  */
                    220: - (id)                 initWithIORange
                    221:                        : (const IORange *) ioRange
                    222:        count           : (unsigned int) count
                    223:        byReference     : (BOOL) byReference
                    224: {
                    225:        IOMemoryContainer       *thisIOMemoryContainer =
                    226:                [[IOMemoryContainer alloc] initWithIORange
                    227:                                        : ioRange
                    228:                        count           : count
                    229:                        byReference     : byReference
                    230:                    ];
                    231:        [self initWithIOMemoryContainer : thisIOMemoryContainer];
                    232:        return (self);
                    233: 
                    234: }
                    235: 
                    236: /**
                    237:  * Initialize an IOMemoryDescriptor object for a single logical range.
                    238:  */
                    239: - (id)                 initWithAddress
                    240:                        : (void *) address
                    241:        length          : (unsigned int) length
                    242: {
                    243:        IOMemoryContainer       *thisIOMemoryContainer =
                    244:                [[IOMemoryContainer alloc] initWithAddress
                    245:                                        : address
                    246:                        length          : length
                    247:                    ];
                    248:        [self initWithIOMemoryContainer : thisIOMemoryContainer];
                    249:        return (self);
                    250: }
                    251: 
                    252: 
                    253: - (id)                 initWithIOV
                    254:                        : (const struct iovec *) iov
                    255:        count           : (unsigned int) count
                    256: {
                    257:        IOMemoryContainer       *thisIOMemoryContainer =
                    258:                [[IOMemoryContainer alloc] initWithIOV
                    259:                                        : iov
                    260:                        count           : count
                    261:                    ];
                    262:        [self initWithIOMemoryContainer : thisIOMemoryContainer];
                    263:        return (self);
                    264: }
                    265: 
                    266: /**
                    267:  * Manage the retain/release reference count. See NSObject for details.
                    268:  */
                    269: - (unsigned int)       retainCount
                    270: {
                    271:        return (retainCount);
                    272: }
                    273: 
                    274: - (id)                 retain
                    275: {
                    276:        ++retainCount;
                    277:        return (self);
                    278: }
                    279: 
                    280: - (oneway void)                release
                    281: {
                    282:        if (--retainCount == 0) {
                    283:            [self free];
                    284:        }
                    285: }
                    286: 
                    287: 
                    288: /**
                    289:  * Return a copy of this IOMemoryDescriptor and its IOMemoryContainer.
                    290:  * The IOMemoryContainer's reference count will be incremented.
                    291:  * The current position is not duplicated: the clone will be reset
                    292:  * to position zero.
                    293:  */
                    294: - (id)                 replicate
                    295: {
                    296:        IOMemoryDescriptor      *result;
                    297: 
                    298:        [ioMemoryContainer retain];
                    299:        result = [[self copy] initWithIOMemoryContainer
                    300:                                        : ioMemoryContainer
                    301:                ];
                    302:        if (result) {
                    303:            [result setMaxSegmentCount  : maxSegmentCount];
                    304:            [result setClient           : [self client]];
                    305:        }
                    306:        return (result);
                    307: }
                    308: 
                    309: /**
                    310:  * Accessor methods
                    311:  */
                    312: - (unsigned int)       currentOffset
                    313: {
                    314:        return (state.currentOffset);
                    315: }
                    316: 
                    317: - (unsigned int)       totalByteCount
                    318: {
                    319:        return ([ioMemoryContainer totalByteCount]);
                    320: }
                    321: 
                    322: - (unsigned int)       maxSegmentCount
                    323: {
                    324:        return (maxSegmentCount);
                    325: }
                    326: /*
                    327:  * Retrieve the ioMemoryContainer
                    328:  */
                    329: - (id)                 ioMemoryContainer
                    330: {
                    331:        return (ioMemoryContainer);
                    332: }
                    333: 
                    334: 
                    335: 
                    336: - (void)               setMaxSegmentCount
                    337:                        : (unsigned int) newMaxSegmentCount
                    338: {
                    339:         maxSegmentCount        = (newMaxSegmentCount == 0)
                    340:                        ? [self totalByteCount]
                    341:                        : newMaxSegmentCount;
                    342: }
                    343: 
                    344: - (vm_task_t)          client
                    345: {
                    346:        return ([ioMemoryContainer client]);
                    347: }
                    348: 
                    349: - (void)               setClient
                    350:                        : (vm_task_t) client
                    351: {
                    352:        [ioMemoryContainer setClient : client];
                    353: }
                    354: 
                    355: - (void)               setIOMemoryContainer
                    356:                        : (id) newIOMemoryContainer
                    357: {
                    358:        if (ioMemoryContainer != newIOMemoryContainer) {
                    359:            [ioMemoryContainer release];
                    360:            [newIOMemoryContainer retain]; 
                    361:            ioMemoryContainer   = newIOMemoryContainer;
                    362:        }
                    363:        state.currentOffset     = 0;
                    364:        valid                   = FALSE;        /* Resets other values      */
                    365: }
                    366: 
                    367: /**
                    368:  * This retrieves all positioning information -- it is intended for
                    369:  * processing SCSI Save Data Pointers messages. Callers should treat
                    370:  * IOMemoryDescriptorState as an opaque object.
                    371:  */
                    372: - (void)               state
                    373:                        : (IOMemoryDescriptorState *) statePtr
                    374: {
                    375:        /*
                    376:         * If we're called without a valid state, setState will
                    377:         * fail (as the new state will be invalid). Note that the
                    378:         * state is invalid when the IOMemoryDescriptor is first
                    379:         * created.
                    380:         */
                    381:        if (valid == FALSE) {
                    382:            [self validate];
                    383:        }
                    384:        *statePtr = state;
                    385: }
                    386: 
                    387: 
                    388: /**
                    389:  * Reposition the IOMemoryDescriptor's current access point. (The TECO "dot").
                    390:  * setState should be be called with the results of a previous state
                    391:  * method. It is very fast. The caller must not modify the state.
                    392:  */
                    393: - (void)               setState
                    394:                        : (const IOMemoryDescriptorState *) statePtr
                    395: {
                    396:        state           = *statePtr;
                    397:        valid           = TRUE;
                    398: }
                    399: 
                    400: /**
                    401:  * Set the current access point to the specified byte index. This is an
                    402:  * absolute position within the IOMemoryDescriptor. This will be slow
                    403:  * for complex memory descriptors. setPosition does not check the parameter
                    404:  * for validity -- this is done by the nextPhysicalRange method.
                    405:  */
                    406: - (void)               setPosition
                    407:                        : (unsigned int) newPosition
                    408: {
                    409:        if (state.currentOffset != newPosition) {
                    410:                state.currentOffset     = newPosition;
                    411:                valid                   = FALSE;
                    412:        }
                    413: }
                    414: 
                    415: /**
                    416:  * Set the current access point to the relative position with respect
                    417:  * to the current position. This is equivalent to writing:
                    418:  *    [ioMemoryDescriptor setPosition
                    419:  *             : [ioMemoryDescriptor currentOffset] + offset];
                    420:  * This will be slow for complex memory descriptors. setOffset does not check
                    421:  * the parameter for validity -- this is done by the nextPhysicalRange method.
                    422:  */
                    423: - (void)               setOffset
                    424:                        : (signed int) offset
                    425: {
                    426:        state.currentOffset     += offset;
                    427:        valid                   = FALSE;
                    428: }
                    429: 
                    430: 
                    431: /**
                    432:  * Return one or more logical ranges. Return zero if the transfer is outside
                    433:  * of the defined range (I.e., if all data has been transferred).
                    434:  * @param maxRanges            The maximum number of ranges to retrieve.
                    435:  * @param maxByteCount         The maximum number of bytes to retrieve
                    436:  *                             in the entire sequence. To use the remaining
                    437:  *                             transfer count, specify UINT_MAX (from limits.h).
                    438:  * @param newPosition          The new value of currentOffset (may be NULL)
                    439:  * @param actualRanges         The actual number of ranges retrieved
                    440:  *                             (NULL if not needed)
                    441:  * @param logicalRanges                A vector of logical range elements.
                    442:  * Return the total number of bytes in all ranges. Return zero if the current
                    443:  * offset is beyond the end of the range.
                    444:  */
                    445: - (unsigned int)       getLogicalRanges
                    446:                        : (unsigned int) maxRanges
                    447:        maxByteCount    : (unsigned int) maxByteCount
                    448:        newPosition     : (unsigned int *) newPosition
                    449:        actualRanges    : (unsigned int *) actualRanges
                    450:        logicalRanges   : (IORange *) logicalRanges
                    451: {
                    452:        unsigned int    byteCount;
                    453:        unsigned int    transferCount   = 0;
                    454:        unsigned int    rangeCount;
                    455:        unsigned int    totalByteCount  = [ioMemoryContainer totalByteCount];
                    456: 
                    457:        if (valid == FALSE) {
                    458:            [self validate];
                    459:        }
                    460:        for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
                    461:            byteCount = totalByteCount - state.currentOffset;
                    462:            if (state.logicalOffset >= state.ioRange.size) {
                    463:                ++state.rangeIndex;
                    464:                [self getCurrentLogicalRange];
                    465:            }
                    466:            if (byteCount > (state.ioRange.size - state.logicalOffset)) {
                    467:                byteCount = state.ioRange.size - state.logicalOffset;
                    468:            }
                    469:            if (byteCount > maxSegmentCount) {
                    470:                byteCount = maxSegmentCount;
                    471:            }
                    472:            if (byteCount > maxByteCount) {
                    473:                byteCount = maxByteCount;
                    474:            }
                    475:            if (byteCount == 0) {
                    476:                break;          /* Fell off the end     */
                    477:            }
                    478:            logicalRanges->size         = byteCount;
                    479:            logicalRanges->start        = state.ioRange.start
                    480:                                        + state.logicalOffset;
                    481:            ++logicalRanges;
                    482:            state.logicalOffset         += byteCount;
                    483:            transferCount               += byteCount;
                    484:            state.currentOffset += transferCount;
                    485:        }
                    486:        if (actualRanges != NULL) {
                    487:            *actualRanges               = rangeCount;
                    488:        }
                    489:        if (newPosition != NULL) {
                    490:            *newPosition                = state.currentOffset;
                    491:        }
                    492:        state.physicalOffset            = 0;    /* Invalid physical range    */
                    493:        return (transferCount);
                    494: }
                    495: 
                    496: /**
                    497:  * Return one or more physical ranges. Return zero if the transfer is outside
                    498:  * of the defined range (I.e., if all data has been transferred).
                    499:  * @param maxRanges            The maximum number of ranges to retrieve.
                    500:  * @param maxByteCount         The maximum number of bytes to retrieve
                    501:  *                             in the entire sequence. To use the remaining
                    502:  *                             transfer count, use UINT_MAX (from limits.h).
                    503:  * @param newPosition          The new value of currentOffset (may be NULL)
                    504:  * @param actualRanges         The actual number of ranges retrieved
                    505:  *                             (NULL if not needed)
                    506:  * @param physicalRanges       A vector of physical range elements.
                    507:  * Return the total number of bytes in all ranges. Return zero if the current
                    508:  * offset is beyond the end of the range.
                    509:  */
                    510: - (unsigned int)                       getPhysicalRanges
                    511:                        : (unsigned int) maxRanges
                    512:        maxByteCount    : (unsigned int) maxByteCount
                    513:        newPosition     : (unsigned int *) newPosition
                    514:        actualRanges    : (unsigned int *) actualRanges
                    515:        physicalRanges  : (PhysicalRange *) physicalRanges
                    516: {
                    517:        unsigned int    byteCount;
                    518:        unsigned int    transferCount   = 0;
                    519:        unsigned int    rangeCount;
                    520:        unsigned int    totalByteCount  = [ioMemoryContainer totalByteCount];
                    521: 
                    522:        if (valid == FALSE) {
                    523:            [self validate];
                    524:        }
                    525:        for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
                    526:            byteCount = totalByteCount - state.currentOffset;
                    527:            if (state.logicalOffset >= state.ioRange.size) {
                    528:                ++state.rangeIndex;
                    529:                [self getCurrentLogicalRange];
                    530:            }
                    531:            if (byteCount > (state.ioRange.size - state.logicalOffset)) {
                    532:                byteCount = state.ioRange.size - state.logicalOffset;
                    533:            }
                    534:            if ((byteCount + transferCount) > maxSegmentCount) {
                    535:                byteCount = maxSegmentCount - transferCount;
                    536:            }
                    537:            if ((byteCount + transferCount) > maxByteCount) {
                    538:                byteCount = maxByteCount - transferCount;
                    539:            }
                    540:            if (byteCount == 0) {
                    541:                break;          /* Fell off the end     */
                    542:            }
                    543:            if (state.physicalOffset == 0
                    544:             || state.physicalOffset >= state.physical.length) {
                    545:                if ([self getCurrentPhysicalRange] != IO_R_SUCCESS) {
                    546:                    break;
                    547:                }
                    548:            }
                    549:            if (byteCount > (state.physical.length - state.physicalOffset)) {
                    550:                byteCount = state.physical.length - state.physicalOffset;
                    551:            }
                    552:            physicalRanges->length      = byteCount;
                    553:            physicalRanges->address     = (void *)
                    554:                (((unsigned int) state.physical.address)
                    555:                        + state.physicalOffset);
                    556:            ++physicalRanges;
                    557:            transferCount               += byteCount;
                    558:            state.physicalOffset        += byteCount;
                    559:            state.logicalOffset         += byteCount;
                    560:            state.currentOffset         += byteCount;
                    561:        }
                    562:        if (actualRanges != NULL) {
                    563:            *actualRanges               = rangeCount;
                    564:        }
                    565:        if (newPosition != NULL) {
                    566:            *newPosition                = state.currentOffset;
                    567:        }
                    568:        return (transferCount);
                    569: }
                    570: 
                    571: /**
                    572:  * Copy bytes from the caller's address space to the IOMemoryContainer
                    573:  * client address space. This is an inefficient routine that should only
                    574:  * be used for "corner cases" such as handling unaligned transfers.
                    575:  * The copy begins at the current logical address. The current logical
                    576:  * position will be incremented.
                    577:  * @param buffer       The starting buffer address in the caller's
                    578:  *                     address space.
                    579:  * @param count                The number of bytes to transfer.
                    580:  * @return             The actual number of bytes transferred.
                    581:  */
                    582: - (unsigned int)               writeToClient
                    583:                        : (void *) buffer
                    584:                count   : (unsigned int) count
                    585: {
                    586:        unsigned int    totalByteCount;
                    587:        unsigned int    thisCount;
                    588:        PhysicalRange   range;
                    589:        vm_address_t    clientVirtualAddress;
                    590:        
                    591:        for (totalByteCount = 0; totalByteCount < count;) {
                    592:            thisCount = [self getPhysicalRanges
                    593:                                        : 1     /* Only one range       */
                    594:                    maxByteCount        : count - totalByteCount
                    595:                    newPosition         : NULL
                    596:                    actualRanges        : NULL
                    597:                    physicalRanges      : &range
                    598:                ];
                    599:            if (thisCount == 0) {
                    600:                break;  /* Ran off the end of the user buffer   */
                    601:            }
                    602:            clientVirtualAddress = [self mapPhysicalAddressIntoIOTask : &range];
                    603:            if (clientVirtualAddress == (vm_address_t) NULL) {
                    604:                [self setOffset : -range.length];
                    605:                break;
                    606:            }
                    607:            else {
                    608:                bcopy(buffer, clientVirtualAddress, range.length);
                    609:                ((unsigned char *) buffer) += range.length;
                    610:                totalByteCount += range.length;
                    611:                [self unmapVirtualAddressFromIOTask
                    612:                                        : clientVirtualAddress
                    613:                        length          : range.length
                    614:                    ];
                    615:            }
                    616:        }
                    617:        return (totalByteCount);
                    618: }
                    619: 
                    620: /**
                    621:  * Copy bytes from the IOMemoryContainer client's address space to the
                    622:  * caller's address space. This is an inefficient routine that should only
                    623:  * be used for "corner cases" such as handling unaligned transfers.
                    624:  * The copy begins at the current logical address. The current logical
                    625:  * position will be incremented.
                    626:  * @param buffer       The starting buffer address in the caller's
                    627:  *                     address space.
                    628:  * @param count                The number of bytes to transfer.
                    629:  * @return             The actual number of bytes transferred.
                    630:  */
                    631: - (unsigned int)               readFromClient
                    632:                        : (void *) buffer
                    633:                count   : (unsigned int) count
                    634: {
                    635:        unsigned int    totalByteCount;
                    636:        unsigned int    thisCount;
                    637:        PhysicalRange   range;
                    638:        vm_address_t    clientVirtualAddress;
                    639:        
                    640:        for (totalByteCount = 0; totalByteCount < count;) {
                    641:            thisCount = [self getPhysicalRanges
                    642:                                        : 1     /* Only one range       */
                    643:                    maxByteCount        : count - totalByteCount
                    644:                    newPosition         : NULL
                    645:                    actualRanges        : NULL
                    646:                    physicalRanges      : &range
                    647:                ];
                    648:            if (thisCount == 0) {
                    649:                break;  /* Ran off the end of the user buffer   */
                    650:            }
                    651:            clientVirtualAddress = [self mapPhysicalAddressIntoIOTask : &range];
                    652:            if (clientVirtualAddress == (vm_address_t) NULL) {
                    653:                [self setOffset : -range.length];
                    654:                break;
                    655:            }
                    656:            else {
                    657:                bcopy(clientVirtualAddress, buffer, range.length);
                    658:                ((unsigned char *) buffer) += range.length;
                    659:                totalByteCount += range.length;
                    660:                [self unmapVirtualAddressFromIOTask
                    661:                                        : clientVirtualAddress
                    662:                        length          : range.length
                    663:                    ];
                    664:            }
                    665:        }
                    666:        return (totalByteCount);
                    667: }
                    668: 
                    669: /**
                    670:  * mapPhysicalAddressIntoIOTask is used to map a potentially
                    671:  * unaligned physical address and range into our virtual address
                    672:  * space. It is a direct wrapper for IOMapPhysicalIntoIOTask
                    673:  * that handles unaligned physical addresses.
                    674:  */ 
                    675: - (vm_address_t) mapPhysicalAddressIntoIOTask
                    676:                : (const PhysicalRange *) range
                    677: {
                    678:        vm_address_t    clientVirtualAddress;
                    679:        unsigned int            offset;
                    680:        IOReturn        ioReturn;
                    681: 
                    682:        offset = ((unsigned int) range->address) & page_mask;
                    683:        ioReturn = IOMapPhysicalIntoIOTask(
                    684:                range->address - offset,
                    685:                range->length + offset,
                    686:                &clientVirtualAddress
                    687:            );
                    688:        if (ioReturn != IO_R_SUCCESS) {
                    689:            clientVirtualAddress = (vm_address_t) NULL;
                    690:        }
                    691:        else {
                    692:            /*
                    693:             * Ensure that clientVirtualAddress is on a page
                    694:             * boundary and add in the actual offset.
                    695:             */
                    696:            clientVirtualAddress = (vm_address_t)
                    697:                        (((unsigned int) clientVirtualAddress) & ~page_mask)
                    698:                        + offset;
                    699:        }
                    700:        return (clientVirtualAddress);
                    701: }
                    702:                
                    703: /**
                    704:  * Un-map a range that was mapped by mapPhysicalAddressIntoIOTask.
                    705:  * rangeLength must be identical to the range.length parameter passed
                    706:  * to mapPhysicalAddressIntoIOTask.
                    707:  */
                    708: - (void) unmapVirtualAddressFromIOTask
                    709:                : (vm_address_t) clientVirtualAddress
                    710:        length  : (unsigned int) rangeLength
                    711: {
                    712:        unsigned int            offset;
                    713:        vm_address_t    pageBaseAddress;
                    714: 
                    715:        offset = ((unsigned int) clientVirtualAddress) & page_mask;
                    716:        pageBaseAddress = (vm_address_t)
                    717:                ((unsigned int) clientVirtualAddress) & ~page_mask;
                    718:        (void) IOUnmapPhysicalFromIOTask(
                    719:                pageBaseAddress, rangeLength + offset);
                    720: }
                    721: 
                    722: /**
                    723:  * Make the memory described by this IOMemoryDescriptor resident.
                    724:  * This is called by the virtual memory manager and/or file system before
                    725:  * starting an I/O request. Residency is an all-or-nothing process. The
                    726:  * IOMemoryDescriptor maintains a reference count: the first caller makes the
                    727:  * memory resident; the others just increment the count. This method returns
                    728:  * an error status if any range cannot be made resident and all memory will
                    729:  * be made pageable. This method may only be called by kernel servers.
                    730:  */
                    731: - (IOReturn)                   wireMemory
                    732:                        : (BOOL) forReading
                    733: {
                    734:        return ([ioMemoryContainer wireMemory : forReading]);
                    735: }
                    736: 
                    737: /**
                    738:  * Make the memory described by this underlying IOMemoryDescriptor pageable.
                    739:  * This is called by the virtual memory manager and/or file system after
                    740:  * completing an I/O request.  The IOMemoryDescriptor maintains a reference
                    741:  * count: the last caller frees the memory the others just decrement the count.
                    742:  * This method returns an error status if any range could not be freed,
                    743:  * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range
                    744:  * can't be unwired (but there is no indication as to which range).
                    745:  */
                    746: - (IOReturn)                   unwireMemory
                    747: {
                    748:        return ([ioMemoryContainer unwireMemory]);
                    749: }
                    750: 
                    751: /**
                    752: * Normalize cache coherency (if needed by this particular hardware
                    753: * architecture) before starting a DMA operation. This normalizes all
                    754: * memory described by this IOMemoryContainer.  This is used as follows:
                    755: *      mem = [IOMemoryDescriptor allocLogicalRange
                    756: *                              : address
                    757: *                      length  : length];
                    758: *      [mem makeResident];
                    759: *      [mem checkpoint : ioCheckpointInput];
                    760: *      ... Extract physical ranges and do DMA I/O ...
                    761: *      [mem checkpoint : ioCheckpointComplete];
                    762: *      [mem makePageable];
                    763: *      [mem free];
                    764: * A checkpoint call may specify any combination of ioCheckpointInput,
                    765: * ioCheckpointOutput, or ioCheckpointNoDirection. After DMA completes,
                    766: * drivers must call checkpoint with ioCheckpointComplete as the only
                    767: * parameter. The actual operation of checkpoint is processor-specific.
                    768:  */
                    769: - (IOReturn)                   checkpoint
                    770:                        : (IOMemoryCheckpointOption) option
                    771: {
                    772: /*
                    773:  * *** Hmm: if we have multiple users, the checkpoint probably should be
                    774:  * *** inside the descriptor, not the container
                    775:  */
                    776:        return ([ioMemoryContainer checkpoint : option]);
                    777: }
                    778: 
                    779: @end /* IOMemoryDescriptor : IOObject */

unix.superglobalmegacorp.com

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