Annotation of driverkit/libDriver/Kernel/IOSimpleMemoryDescriptor.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:  * IOSimpleMemoryDescriptor.m
        !            26:  * Copyright 1997-98 Apple Computer Inc. All Rights Reserved.
        !            27:  *
        !            28:  * IOSimpleMemoryDescriptor provides a limited subset of IOMemoryDescriptor
        !            29:  * functionality for the benefit of low-level drivers (such as the SCSI bus
        !            30:  * interface driver). The IOSimpleMemoryDescriptor supports a single
        !            31:  * input logical range. It cannot be replicated, and does not have a separate
        !            32:  * IOMemoryContainer. It supports the following IOMemoryDescriptor methods:
        !            33:  *     allocSingleRange
        !            34:  *     free
        !            35:  *     currentOffset
        !            36:  *     totalByteCount
        !            37:  *     state
        !            38:  *     setState
        !            39:  *     setPosition
        !            40:  *     setOffset
        !            41:  *     getLogicalRanges
        !            42:  *     getPhysicalRanges
        !            43:  *     checkpoint
        !            44:  * Other methods must not be used. They fail with an IOPanic.
        !            45:  */
        !            46: #ifdef KERNEL
        !            47: #import <driverkit/IOSimpleMemoryDescriptor.h>
        !            48: #import <mach/vm_param.h>
        !            49: 
        !            50: /*
        !            51:  * Compute the start of the next physical page
        !            52:  */
        !            53: #define next_page(x)   (trunc_page(((unsigned int) x) + page_size))
        !            54: 
        !            55: @interface IOSimpleMemoryDescriptor(Private)
        !            56: - (IOReturn)           getCurrentPhysicalRange;
        !            57: - (void)               validate;
        !            58: - (void)               setPositionAtEnd;
        !            59: @end /* IOSimpleMemoryDescriptor(Private) */
        !            60: 
        !            61: @implementation IOSimpleMemoryDescriptor(Private)
        !            62: 
        !            63: /**
        !            64:  * Return the physical address that corresponds to the current logical
        !            65:  * address. The state is valid at this point. This method sets the
        !            66:  * physicalPageLength to the maximumn number of bytes that can be
        !            67:  * transferred in this page.
        !            68:  */
        !            69: - (IOReturn)           getCurrentPhysicalRange
        !            70: {
        !            71:        IOReturn        ioReturn;
        !            72:        unsigned int    nextPageAddress;
        !            73:        
        !            74:        state.physicalOffset = 0;       /* At page start        */
        !            75:        ioReturn        = IOPhysicalFromVirtual(
        !            76:                                client,
        !            77:                                state.ioRange.start + state.currentOffset,
        !            78:                                (vm_offset_t *) &state.physical.address
        !            79:                        );
        !            80:        if (ioReturn != IO_R_SUCCESS) {
        !            81:                     state.physical.address     = 0;
        !            82:             state.physical.length      = 0;
        !            83:        }
        !            84:        else {
        !            85:            /*
        !            86:             * The amount we can transfer is the number of bytes
        !            87:             * from the current start index to the next page
        !            88:             * (limited by scsiReq->maxTransfer). Mach lacks
        !            89:             * a method for determining the page size. We'll
        !            90:             * use 4096 for convenience (the only cost is extra
        !            91:             * cycles through the for loop).
        !            92:             */
        !            93:            nextPageAddress = next_page(state.physical.address);
        !            94:            state.physical.length =
        !            95:                        nextPageAddress - ((unsigned int) state.physical.address);
        !            96:        }
        !            97:        return (ioReturn);
        !            98: }
        !            99: 
        !           100: /**
        !           101:  * Validate the state so that all state values agree with
        !           102:  * the currentOffset.
        !           103:  */
        !           104: - (void)               validate
        !           105: {
        !           106:        if (state.currentOffset >= [self totalByteCount]) {
        !           107:            [self setPositionAtEnd];
        !           108:        }
        !           109:        state.physicalOffset = 0;
        !           110:        valid = TRUE;
        !           111: }
        !           112: 
        !           113: /*
        !           114:  * Force the state to the end of the entire container (for reposition
        !           115:  * errors).
        !           116:  */
        !           117: - (void)               setPositionAtEnd
        !           118: {
        !           119:        state.currentOffset = state.ioRange.size;
        !           120: }
        !           121: 
        !           122: @end /* IOSimpleMemoryDescriptor(Private) */
        !           123: 
        !           124: @implementation IOSimpleMemoryDescriptor
        !           125: 
        !           126: /**
        !           127:  * Destroy any existing data, replacing it with the specified data.
        !           128:  */
        !           129: - (id)                 initWithAddress
        !           130:                        : (void *) address
        !           131:        length          : (unsigned int) length
        !           132: {
        !           133:        retainCount             = 1;
        !           134:        ioMemoryContainer       = NULL;
        !           135:        state.currentOffset     = 0;
        !           136:        state.rangeIndex        = (length == 0) ? 0 : 1;
        !           137:        state.ioRange.start     = (unsigned int) address;
        !           138:        state.ioRange.size      = length;
        !           139:        state.logicalOffset     = 0xDEADBEEF; /* Unused */
        !           140:        state.physicalOffset    = 0;    /* Invalidate   */
        !           141:        valid                   = TRUE;
        !           142:        options                 = 0;
        !           143:        maxSegmentCount         = length;
        !           144:        client                  = IOVmTaskSelf();
        !           145:        return (self);
        !           146: }
        !           147: 
        !           148: - (id)                 initWithIORange
        !           149:                        : (const IORange *) ioRange
        !           150:        count           : (unsigned int) count
        !           151:        byReference     : (BOOL) byReference
        !           152: {
        !           153:        switch (count) {
        !           154:        case 0:
        !           155:            [self initWithAddress: (void *) NULL length: 0];
        !           156:            break;
        !           157:        case 1:
        !           158:            [self initWithAddress: (void *) ioRange->start
        !           159:                           length: ioRange->size];
        !           160:            break;
        !           161:        default:
        !           162:            IOPanic("IOSimpleMemoryDescriptor : "
        !           163:                    "initWithIORange (only one range allowed)");
        !           164:            return [self free];
        !           165:        }
        !           166:        return (self);
        !           167: }
        !           168: 
        !           169: - (id)                 initWithIOV
        !           170:                        : (const struct iovec *) iov
        !           171:        count           : (unsigned int) iovCount
        !           172: {
        !           173:        switch (iovCount) {
        !           174:            [self initWithAddress: (void *) NULL length: 0];
        !           175:            break;
        !           176:        case 1:
        !           177:            [self initWithAddress: (void *) iov->iov_base
        !           178:                           length: iov->iov_len];
        !           179:            break;
        !           180:        default:
        !           181:            IOPanic("IOSimpleMemoryDescriptor : "
        !           182:                    "initWithIOV (only one range allowed)");
        !           183:            return [self free];
        !           184:        }
        !           185:        return (self);
        !           186: }
        !           187: 
        !           188: /**
        !           189:  * Return a copy of this IOMemoryDescriptor and its IOMemoryContainer.
        !           190:  * The IOMemoryContainer's reference count will be incremented.
        !           191:  * The current position is not duplicated.
        !           192:  */
        !           193: - (id)                 replicate
        !           194: {
        !           195:        IOPanic("IOSimpleMemoryDescriptor : replicate invalid");
        !           196:        return (NULL);
        !           197: }
        !           198: 
        !           199: /**
        !           200:  * Accessor methods
        !           201:  */
        !           202: - (unsigned int)       rangeCount
        !           203: {
        !           204:        return (state.rangeIndex);
        !           205: }
        !           206: 
        !           207: - (unsigned int)       totalByteCount
        !           208: {
        !           209:        return (state.ioRange.size);
        !           210: }
        !           211: 
        !           212: /*
        !           213:  * Kernel-specific methods. By default, non-kernel objects contain a NULL
        !           214:  * vm_task_t value. Kernel tasks will set the client to the task that
        !           215:  * provided this memory.
        !           216:  */
        !           217: 
        !           218: - (vm_task_t)          client
        !           219: {
        !           220:        return (client);
        !           221: }
        !           222: 
        !           223: - (void)               setClient
        !           224:                        : (vm_task_t) thisClient
        !           225: {
        !           226:        client = thisClient;
        !           227: }
        !           228: 
        !           229: 
        !           230: /**
        !           231:  * Return one or more logical ranges. Return zero if the transfer is outside
        !           232:  * of the defined range (I.e., if all data has been transferred).
        !           233:  * @param maxRanges            The maximum number of ranges to retrieve.
        !           234:  * @param maxByteCount         The maximum number of bytes to retrieve
        !           235:  *                             in the entire sequence. To use the remaining
        !           236:  *                             transfer count, specify UINT_MAX (from limits.h).
        !           237:  * @param newPosition          The new value of currentOffset (may be NULL)
        !           238:  * @param actualRanges         The actual number of ranges retrieved
        !           239:  *                             (NULL if not needed)
        !           240:  * @param logicalRanges                A vector of logical range elements.
        !           241:  * Return the total number of bytes in all ranges. Return zero if the current
        !           242:  * offset is beyond the end of the range.
        !           243:  */
        !           244: - (unsigned int)       getLogicalRanges
        !           245:                        : (unsigned int) maxRanges
        !           246:        maxByteCount    : (unsigned int) maxByteCount
        !           247:        newPosition     : (unsigned int *) newPosition
        !           248:        actualRanges    : (unsigned int *) actualRanges
        !           249:        logicalRanges   : (IORange *) logicalRanges
        !           250: {
        !           251:        unsigned int    transferCount   = 0;
        !           252:        unsigned int    byteCount;
        !           253:        unsigned int    rangeCount;
        !           254: 
        !           255:        if (valid == FALSE) {
        !           256:            [self validate];
        !           257:        }
        !           258:        for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
        !           259:            byteCount = state.ioRange.size - state.currentOffset;
        !           260:            if (byteCount > maxSegmentCount) {
        !           261:                byteCount = maxSegmentCount;
        !           262:            }
        !           263:            if (byteCount + transferCount > maxByteCount) {
        !           264:                byteCount = maxByteCount - transferCount;
        !           265:            }
        !           266:            if (byteCount == 0) {
        !           267:                break;
        !           268:            }
        !           269:            logicalRanges->size         = byteCount;
        !           270:            logicalRanges->start        =
        !           271:                        (state.ioRange.start + state.currentOffset);
        !           272:            logicalRanges++;
        !           273:            transferCount               += byteCount;
        !           274:            state.currentOffset += byteCount;
        !           275:        }
        !           276:        if (actualRanges != NULL) {
        !           277:            *actualRanges               = rangeCount;
        !           278:        }
        !           279:        if (newPosition != NULL) {
        !           280:            *newPosition                = state.currentOffset;
        !           281:        }
        !           282:        state.physicalOffset            = 0;    /* Invalid physical range    */
        !           283:        return (transferCount);
        !           284: }
        !           285: 
        !           286: /**
        !           287:  * Return one or more physical ranges. Return zero if the transfer is outside
        !           288:  * of the defined range (I.e., if all data has been transferred).
        !           289:  * @param maxRanges            The maximum number of ranges to retrieve.
        !           290:  * @param maxByteCount         The maximum number of bytes to retrieve
        !           291:  *                             in the entire sequence. To use the remaining
        !           292:  *                             transfer count, specify UINT_MAX (from limits.h).
        !           293:  * @param newPosition          The new value of currentOffset (may be NULL)
        !           294:  * @param actualRanges         The actual number of ranges retrieved
        !           295:  *                             (NULL if not needed)
        !           296:  * @param physicalRanges       A vector of physical range elements.
        !           297:  * Return the total number of bytes in all ranges. Return zero if the current
        !           298:  * offset is beyond the end of the range.
        !           299:  */
        !           300: - (unsigned int)       getPhysicalRanges
        !           301:                        : (unsigned int) maxRanges
        !           302:        maxByteCount    : (unsigned int) maxByteCount
        !           303:        newPosition     : (unsigned int *) newPosition
        !           304:        actualRanges    : (unsigned int *) actualRanges
        !           305:        physicalRanges  : (PhysicalRange *) physicalRanges
        !           306: {
        !           307:        unsigned int    transferCount   = 0;
        !           308:        unsigned int    byteCount;
        !           309:        unsigned int    rangeCount;
        !           310: 
        !           311:        if (valid == FALSE) {
        !           312:            [self validate];
        !           313:        }
        !           314:        for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) {
        !           315:            byteCount = state.ioRange.size - state.currentOffset;
        !           316:            if (byteCount > maxSegmentCount) {
        !           317:                byteCount = maxSegmentCount;
        !           318:            }
        !           319:            if (byteCount + transferCount > maxByteCount) {
        !           320:                byteCount = maxByteCount - transferCount;
        !           321:            }
        !           322:            if (byteCount == 0) {
        !           323:                break;
        !           324:            }
        !           325:            if (state.physicalOffset == 0
        !           326:             || state.physicalOffset >= state.physical.length) {
        !           327:                if ([self getCurrentPhysicalRange] != IO_R_SUCCESS) {
        !           328:                    break;
        !           329:                }
        !           330:            }
        !           331:            if (byteCount > (state.physical.length - state.physicalOffset)) {
        !           332:                byteCount = state.physical.length - state.physicalOffset;
        !           333:            }
        !           334:            physicalRanges->length      = byteCount;
        !           335:            physicalRanges->address     = (void *)
        !           336:                (((unsigned int) state.physical.address)
        !           337:                        + state.physicalOffset);
        !           338:            physicalRanges++;
        !           339:            transferCount               += byteCount;
        !           340:            state.currentOffset += byteCount;
        !           341:            state.physicalOffset        += byteCount;
        !           342:        }
        !           343:        if (actualRanges != NULL) {
        !           344:            *actualRanges               = rangeCount;
        !           345:        }
        !           346:        if (newPosition != NULL) {
        !           347:            *newPosition                = state.currentOffset;
        !           348:        }
        !           349:        return (transferCount);
        !           350: }
        !           351: 
        !           352: /**
        !           353:  * Make the memory described by this IOMemoryDescriptor resident.
        !           354:  * This is called by the virtual memory manager and/or file system before
        !           355:  * starting an I/O request. Residency is an all-or-nothing process. The
        !           356:  * IOMemoryDescriptor maintains a reference count: the first caller makes the
        !           357:  * memory resident; the others just increment the count. This method returns
        !           358:  * an error status if any range cannot be made resident and all memory will
        !           359:  * be made pageable. This method may only be called by kernel servers.
        !           360:  */
        !           361: - (IOReturn)           wireMemory
        !           362:                        : (BOOL) forReading;
        !           363: {
        !           364:        IOReturn                ioReturn = IO_R_SUCCESS;
        !           365:        kern_return_t           status;
        !           366:        vm_offset_t             rangeStart;
        !           367:        vm_offset_t             rangeEnd;
        !           368: 
        !           369:        if (forReading) {
        !           370:            options     |= ioWiredForRead;
        !           371:        }
        !           372:        else {
        !           373:            options     &= ~ioWiredForRead;
        !           374:        }
        !           375:        if (residencyCount++ == 0) {    /* Note: AtomicIncrement        */
        !           376:            rangeStart  = trunc_page(state.ioRange.start);
        !           377:            rangeEnd    = round_page(
        !           378:                                state.ioRange.start + state.ioRange.size);
        !           379:            status      = vm_map_pageable(
        !           380:                                /* (vm_map_t) */ client,
        !           381:                                rangeStart,
        !           382:                                rangeEnd,
        !           383:                                FALSE           /* Wire range   */
        !           384:                            );
        !           385:            if (status != KERN_SUCCESS) {
        !           386:                ioReturn = IO_R_CANT_WIRE;
        !           387:                --residencyCount;
        !           388:            }
        !           389:            else if (forReading == FALSE) {
        !           390:                /*
        !           391:                 * Is this really needed?
        !           392:                 */
        !           393:                // flush_cache_v(rangeStart, rangeEnd - rangeStart);
        !           394:            }
        !           395:        }
        !           396:        return (ioReturn);
        !           397: }
        !           398: 
        !           399: /**
        !           400:  * Make the memory described by this underlying IOMemoryContainer pageable.
        !           401:  * This is called by the virtual memory manager and/or file system after
        !           402:  * completing an I/O request.  The IOMemoryContainer maintains a reference
        !           403:  * count: the last caller frees the memory the others just decrement the count.
        !           404:  * This method returns an error status if any range could not be freed,
        !           405:  * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range
        !           406:  * can't be unwired (but there is no indication as to which range).
        !           407:  */
        !           408: - (IOReturn)                   unwireMemory
        !           409: {
        !           410:        IOReturn                ioReturn = IO_R_SUCCESS;
        !           411:        kern_return_t           status;
        !           412:        vm_offset_t             rangeStart;
        !           413:        vm_offset_t             rangeEnd;
        !           414: 
        !           415:        if (residencyCount-- == 1) {    /* NOTE: AtomicDecrement */
        !           416:            rangeStart  = trunc_page(state.ioRange.start);
        !           417:            rangeEnd    = round_page(
        !           418:                                state.ioRange.start + state.ioRange.size);
        !           419:            status      = vm_map_pageable(
        !           420:                                /* (vm_map_t) */ client,
        !           421:                                rangeStart,
        !           422:                                rangeEnd,
        !           423:                                TRUE            /* Make pageable */
        !           424:                            );
        !           425:            if (status != KERN_SUCCESS) {
        !           426:                ioReturn = IO_R_CANT_WIRE;
        !           427:            }
        !           428:        }
        !           429:        return (ioReturn);
        !           430: }
        !           431: 
        !           432: @end /* IOSimpleMemoryDescriptor : IOMemoryDescriptor */
        !           433: #endif /* KERNEL */
        !           434: 

unix.superglobalmegacorp.com

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