Annotation of driverkit/libDriver/Kernel/IOSimpleMemoryDescriptor.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:  * 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.