Annotation of driverkit/libDriver/Kernel/IOMemoryDescriptor.m, revision 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.