|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.