Annotation of driverkit/libDriver/IOMemoryContainer.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:  * IOMemoryContainer.m
        !            26:  * Copyright 1997-98 Apple Computer Inc. All Rights Reserved.
        !            27:  *
        !            28:  * IOMemoryContainer describes client memory. It is constructed and manipulated
        !            29:  * by MemoryDescriptor classes. It is not "visible" to client and server
        !            30:  * code. Note that IOMemoryContainer objects do not provide enumeration or
        !            31:  * positioning services: they only describe a particular range of memory.
        !            32:  *
        !            33:  * IOMemoryContainer may be used in both user space and kernel space.
        !            34:  * The memory described by a user-space IOMemoryContainer can be
        !            35:  * accessed by the creating task as a collection of logical extents.
        !            36:  * Kernel processes, after making the memory resident, can access
        !            37:  * the container memory as either logical or physical extents.
        !            38:  */
        !            39: #import <driverkit/IOMemoryContainer.h>
        !            40: #import <driverkit/generalFuncs.h>
        !            41: #import <mach/vm_param.h>
        !            42: 
        !            43: /*
        !            44:  * This is the information that is transferred by the serialization
        !            45:  * methods. This fixed-length header will be followed by <rangeCount>
        !            46:  * IORange values.
        !            47:  */
        !            48: typedef struct {
        !            49:     vm_task_t          client;
        !            50:     unsigned int       rangeCount;
        !            51: } IOMemoryContainerSerialization;
        !            52: #define kSerializationSize     (sizeof (IOMemoryContainerSerialization))
        !            53: 
        !            54: @interface IOMemoryContainer(Private)
        !            55: - (id)                 init;
        !            56: - (id)                 free;
        !            57: @end /* IOMemoryContainer(Private) */
        !            58: 
        !            59: @implementation IOMemoryContainer(Private)
        !            60: /**
        !            61:  * Initialize an empty IOMemoryContainer object.
        !            62:  */
        !            63: - (id)                 init
        !            64: {
        !            65:        /*
        !            66:         * Initialize all fields to zero (but with one reference).
        !            67:         */
        !            68:        options                 = 0;
        !            69:        retainCount             = 1;
        !            70:        residencyCount          = 0;
        !            71: #ifdef KERNEL
        !            72:        client                  = IOVmTaskSelf();
        !            73: #else
        !            74:        client                  = IO_NULL_VM_TASK;
        !            75: #endif /* KERNEL */
        !            76:        rangeCount              = 0;
        !            77:        totalByteCount          = 0;
        !            78:        range.logical.start     = 0;
        !            79:        range.logical.size      = 0;
        !            80:        return (self);
        !            81: }
        !            82: 
        !            83: /**
        !            84:  * Dispose of the object. Note that free ignores the retainCount and
        !            85:  * referenceCount and always frees the IOMemoryContainer object.
        !            86:  */
        !            87: - (id)                 free
        !            88: {
        !            89:        if (rangeCount > 1 && range.vector != NULL) {
        !            90:            if ((options & ioRangeByReference) == 0) {
        !            91:                IOFree((void *) range.vector, rangeCount * sizeof (IORange));
        !            92:            }
        !            93:            rangeCount = 0;
        !            94:            range.vector = NULL;
        !            95:        }
        !            96:        return [super free];
        !            97: }
        !            98: 
        !            99: @end /* IOMemoryContainer(Private) */
        !           100: 
        !           101: 
        !           102: @implementation IOMemoryContainer
        !           103: 
        !           104: /**
        !           105:  * Create an IOMemoryContainer object for a logical scatter-gather list in the
        !           106:  * caller's address map. The scatter-gather list is provided in DriverKit
        !           107:  * IORange format. If byReference is TRUE, the IOMemoryContainer will hold
        !           108:  * a reference to the range vector (which must remain addressable during the
        !           109:  * lifetime of the object). If FALSE, the range vector will be copied into
        !           110:  * the IOMemoryContainer object.
        !           111:  */
        !           112: - (id)                 initWithIORange
        !           113:                        : (const IORange *) ioRange
        !           114:        count           : (unsigned int) thisRangeCount
        !           115:        byReference     : (BOOL) initByReference
        !           116: {
        !           117:        unsigned int    size;
        !           118:        unsigned int    i;
        !           119:        
        !           120:        switch (thisRangeCount) {
        !           121:        case 0:
        !           122:            [self initWithAddress
        !           123:                                : NULL
        !           124:                    length      : 0
        !           125:                ];
        !           126:            break;
        !           127:        case 1:
        !           128:            [self initWithAddress
        !           129:                                : (void *) ioRange->start
        !           130:                    length      : ioRange->size
        !           131:                ];
        !           132:            break;
        !           133:        default:
        !           134:            [self init];
        !           135:            rangeCount          = thisRangeCount;
        !           136:            size                = thisRangeCount * sizeof (IORange);
        !           137:            if (initByReference) {
        !           138:                options         |= ioRangeByReference;
        !           139:                range.vector    = ioRange;
        !           140:            }
        !           141:            else {
        !           142:                range.vector    = IOMalloc(size);
        !           143:                IOCopyMemory(
        !           144:                    (void *) ioRange,           /* Copy from here       */
        !           145:                    (void *) range.vector,      /* Copy to here         */
        !           146:                    size,                       /* Total byte count     */
        !           147:                    4                           /* Bytes per transfer   */
        !           148:                );
        !           149:            }
        !           150:            for (i = 0; i < thisRangeCount; i++) {
        !           151:                totalByteCount += ioRange[i].size;
        !           152:            }
        !           153:            break;
        !           154:        }
        !           155:        return (self);
        !           156: }
        !           157: 
        !           158: /**
        !           159:  * Create an IOMemoryContainer object for a single logical range.
        !           160:  */
        !           161: - (id)                 initWithAddress
        !           162:                        : (void *) address
        !           163:        length          : (unsigned int) length
        !           164: {
        !           165:        [self init];
        !           166:        rangeCount              = 1;
        !           167:        range.logical.start     = (unsigned int) address;
        !           168:        range.logical.size      = length;
        !           169:        totalByteCount          = length;
        !           170:        return (self);
        !           171: }
        !           172: 
        !           173: 
        !           174: /**
        !           175:  * Create an IOMemoryContainer object for a logical scatter-gather list in the
        !           176:  * caller's address map. The scatter-gather list is provided in BSD
        !           177:  * Unix iov format.
        !           178:  */
        !           179: - (id)                 initWithIOV
        !           180:                        : (const struct iovec *) iov
        !           181:        count           : (unsigned int) iovCount
        !           182: {
        !           183:        unsigned int    size;
        !           184:        unsigned int    i;
        !           185: 
        !           186:        switch (iovCount) {
        !           187:        case 0:
        !           188:            [self initWithAddress : NULL
        !           189:                    length      : 0
        !           190:                ];
        !           191:            break;
        !           192:        case 1:
        !           193:            [self initWithAddress : iov->iov_base
        !           194:                    length      : iov->iov_len
        !           195:                ];
        !           196:            break;
        !           197:        default:
        !           198:            [self init];
        !           199:            range.vector        = IOMalloc(size);
        !           200:            rangeCount          = iovCount;
        !           201:            size                = iovCount * sizeof (IORange);
        !           202:            for (i = 0; i < iovCount; i++, iov++) {
        !           203:                ((IORange *) range.vector)[i].start =
        !           204:                                (unsigned int) iov->iov_base;
        !           205:                ((IORange *) range.vector)[i].size = iov->iov_len;
        !           206:                totalByteCount  += iov->iov_len;
        !           207:            }
        !           208:            break;
        !           209:        }
        !           210:        return (self);
        !           211: }
        !           212: 
        !           213: /**
        !           214:  * Accessor methods
        !           215:  */
        !           216: - (unsigned int)       rangeCount
        !           217: {
        !           218:        return (rangeCount);
        !           219: }
        !           220: 
        !           221: - (unsigned int)       totalByteCount
        !           222: {
        !           223:        return (totalByteCount);
        !           224: }
        !           225: 
        !           226: /**
        !           227:  * Manage the retain/release reference count. See NSObject for details.
        !           228:  */
        !           229: - (unsigned int)       retainCount
        !           230: {
        !           231:        return (retainCount);
        !           232: }
        !           233: 
        !           234: - (id)                 retain
        !           235: {
        !           236:        ++retainCount;
        !           237:        return (self);
        !           238: }
        !           239: 
        !           240: - (oneway void)                release
        !           241: {
        !           242:        if (--retainCount == 0) {
        !           243:            [self free];
        !           244:        }
        !           245: }
        !           246: 
        !           247: /**
        !           248:  * Return one range segment. These return errors if the parameter is
        !           249:  * incorrect (calling logicalRange on physicalRanges, index out of bounds).
        !           250:  */
        !           251: 
        !           252: /**
        !           253:  * Return the logical address and length for the i'th logical range.
        !           254:  * Return IO_R_INVALID_ARG if the index is outside the allocated range.
        !           255:  */
        !           256: - (IOReturn)           logicalRange
        !           257:                        : (IORange *) logicalRange
        !           258:        index           : (unsigned int) thisIndex
        !           259: {
        !           260:        IOReturn        ioReturn;
        !           261:        
        !           262:        if (thisIndex >= rangeCount || logicalRange == NULL) {
        !           263:            ioReturn            = IO_R_INVALID_ARG;
        !           264:        }
        !           265:        else {
        !           266:            ioReturn            = IO_R_SUCCESS;
        !           267:            if (rangeCount == 1) {
        !           268:                *logicalRange = range.logical;
        !           269:            }
        !           270:            else {
        !           271:                *logicalRange = range.vector[thisIndex];
        !           272:            }
        !           273:        }
        !           274:        return (ioReturn);
        !           275: }
        !           276: @end /* IOMemoryContainer : Object */
        !           277: 
        !           278: #ifdef KERNEL
        !           279: @implementation IOMemoryContainer(Kernel)
        !           280: 
        !           281: /*
        !           282:  * Kernel-specific methods. By default, non-kernel objects contain a NULL
        !           283:  * vm_task_t value. Kernel tasks will set the client to the task that
        !           284:  * provided this memory.
        !           285:  */
        !           286: 
        !           287: - (vm_task_t)          client
        !           288: {
        !           289:        return (client);
        !           290: }
        !           291: 
        !           292: - (void)               setClient
        !           293:                        : (vm_task_t) thisClient
        !           294: {
        !           295:        client = thisClient;
        !           296: }
        !           297: 
        !           298: 
        !           299: /**
        !           300:  * Make the memory described by this IOMemoryContainer resident.
        !           301:  * This is called by the virtual memory manager and/or file system before
        !           302:  * starting an I/O request. Residency is an all-or-nothing process. The
        !           303:  * IOMemoryContainer maintains a reference count: the first caller makes the
        !           304:  * memory resident; the others just increment the count. This method returns
        !           305:  * an error status if any range cannot be made resident and all memory will
        !           306:  * be made pageable. This method may only be called by kernel servers.
        !           307:  */
        !           308: - (IOReturn)           wireMemory
        !           309:                        : (BOOL) forReading
        !           310: {
        !           311:        IOReturn        ioReturn = IO_R_SUCCESS;
        !           312:        kern_return_t   status;
        !           313:        unsigned int    i;
        !           314:        unsigned int    successCount;
        !           315:        IORange         thisRange;
        !           316:        vm_offset_t     rangeStart;
        !           317:        vm_offset_t     rangeEnd;
        !           318:        
        !           319:        /*
        !           320:         * Increment the residency counter. If it was not zero when we were
        !           321:         * called, we have already made this memory resident, so just exit.
        !           322:         * If it was zero, this is the first call and we must make all ranges
        !           323:         * resident.
        !           324:         */
        !           325:        if (forReading)
        !           326:            options |=  ioWiredForRead;
        !           327:        else
        !           328:            options &= ~ioWiredForRead;
        !           329: 
        !           330:        if (residencyCount++ == 0) {    /* NOTE: AtomicIncrement */
        !           331:            successCount = 0;
        !           332:            for (i = 0; i < rangeCount && ioReturn == IO_R_SUCCESS; i++) {
        !           333:                ioReturn = [self logicalRange   : &thisRange
        !           334:                                index           : i
        !           335:                            ];
        !           336:                if (ioReturn == IO_R_SUCCESS) {
        !           337:                    rangeStart  = trunc_page(thisRange.start);
        !           338:                    rangeEnd    = round_page(thisRange.start + thisRange.size);
        !           339:                    status      = vm_map_pageable(
        !           340:                                        client,
        !           341:                                        rangeStart,
        !           342:                                        rangeEnd,
        !           343:                                        FALSE           /* Wire range   */
        !           344:                                    );
        !           345:                    if (status != KERN_SUCCESS)
        !           346:                        ioReturn = IO_R_CANT_WIRE;      /* Wire failed  */
        !           347:                    else {
        !           348:                        if (forReading == FALSE) {
        !           349:                            /*
        !           350:                             * Is this really needed?
        !           351:                             */
        !           352:                            // flush_cache_v(rangeStart, rangeEnd - rangeStart);
        !           353:                        }
        !           354:                        ++successCount;
        !           355:                    }
        !           356:                }
        !           357:            }
        !           358:        }
        !           359:        if (ioReturn != IO_R_SUCCESS) {
        !           360:            /*
        !           361:             * Unwire partial preparations.
        !           362:             */
        !           363:            for (i = 0; i < successCount; i++) {
        !           364:                [self logicalRange : &thisRange index : i];
        !           365:                rangeStart      = trunc_page(thisRange.start);
        !           366:                rangeEnd        = round_page(thisRange.start + thisRange.size);
        !           367:                (void) vm_map_pageable(
        !           368:                        client,
        !           369:                        rangeStart,
        !           370:                        rangeEnd,
        !           371:                        TRUE            /* Unwire range */
        !           372:                    );
        !           373:            }
        !           374:            --residencyCount;
        !           375:        }
        !           376:        return (ioReturn);
        !           377: }
        !           378: 
        !           379: /**
        !           380:  * Make the memory described by this underlying IOMemoryContainer pageable.
        !           381:  * This is called by the virtual memory manager and/or file system after
        !           382:  * completing an I/O request.  The IOMemoryContainer maintains a reference
        !           383:  * count: the last caller frees the memory the others just decrement the count.
        !           384:  * This method returns an error status if any range could not be freed,
        !           385:  * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range
        !           386:  * can't be unwired (but there is no indication as to which range).
        !           387:  */
        !           388: - (IOReturn)           unwireMemory
        !           389: {
        !           390:        IOReturn        ioReturn = IO_R_SUCCESS;
        !           391:        IOReturn        finalResult = IO_R_SUCCESS;
        !           392:        kern_return_t   status;
        !           393:        unsigned int    i;
        !           394:        IORange         thisRange;
        !           395:        vm_offset_t     rangeStart;
        !           396:        vm_offset_t     rangeEnd;
        !           397:        
        !           398:        /*
        !           399:         * Decrement the residency counter. If is zero after decrement, this
        !           400:         * is the last caller, so make the ranges pageable.
        !           401:         */
        !           402:        if (--residencyCount == 0) {    /* NOTE: AtomicDecrement */
        !           403:            for (i = 0; i < rangeCount; i++) {
        !           404:                ioReturn = [self logicalRange   : &thisRange
        !           405:                                index           : i
        !           406:                            ];
        !           407:                if (finalResult != IO_R_SUCCESS) {
        !           408:                    finalResult = ioReturn;
        !           409:                }
        !           410:                else {
        !           411:                    rangeStart  = trunc_page(thisRange.start);
        !           412:                    rangeEnd    = round_page(thisRange.start + thisRange.size);
        !           413:                    status = vm_map_pageable(
        !           414:                                client,
        !           415:                                rangeStart,
        !           416:                                rangeEnd,
        !           417:                                TRUE            /* Make range pageable  */
        !           418:                            );
        !           419:                    if (status != KERN_SUCCESS && finalResult == IO_R_SUCCESS) {
        !           420:                        finalResult = IO_R_VM_FAILURE;
        !           421:                    }
        !           422:                }
        !           423:            }
        !           424:        }
        !           425:        return (finalResult);
        !           426: }
        !           427: 
        !           428: /**
        !           429:  * Normalize cache coherency (if needed by this particular hardware
        !           430:  * architecture) before starting a DMA operation. This normalizes all
        !           431:  * memory described by this IOMemoryContainer.  This is used as follows:
        !           432:  *     mem = [[IOMemoryDescriptor alloc] initWithAddress
        !           433:  *                             : address
        !           434:  *                     length  : length];
        !           435:  *     [mem makeResident];
        !           436:  *     [mem checkpoint : ioCheckpointInput];
        !           437:  *     ... Extract physical ranges and do DMA I/O ...
        !           438:  *     [mem checkpoint : ioCheckpointComplete];
        !           439:  *     [mem makePageable];
        !           440:  *     [mem free];
        !           441:  * A checkpoint call may specify any combination of ioCheckpointInput,
        !           442:  * ioCheckpointOutput, or ioCheckpointNoDirection. After DMA completes,
        !           443:  * drivers must call checkpoint with ioCheckpointComplete as the only
        !           444:  * parameter. The actual operation of checkpoint is processor-specific.
        !           445:  * Note that wireMemory and unwireMemory will call checkpoint with appropriate
        !           446:  * options: it need only be called explicitly if the same buffer is used
        !           447:  * for multiple I/O requests, as might be the case for a video-to-disk
        !           448:  * process.
        !           449:  */
        !           450: - (IOReturn)           checkpoint
        !           451:                        : (IOMemoryCheckpointOption) option
        !           452: {
        !           453:        /* Override if necessary */
        !           454:        return (IO_R_SUCCESS);
        !           455: }
        !           456:                        
        !           457: @end /* IOMemoryContainer(Kernel) */
        !           458: #endif /* KERNEL */
        !           459: 

unix.superglobalmegacorp.com

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