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