|
|
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: * IOMemoryDescriptor.m ! 26: * Copyright 1997-98 Apple Computer Inc. All Rights Reserved. ! 27: * ! 28: * IOMemoryDescriptor describes the client memory needed to perform an I/O ! 29: * request. It contains a single IOMemoryContainer that describes one or ! 30: * more ranges of memory. IOMemoryDescriptor is used directly for simple ! 31: * (non-RAID) transfers, and is the underlying object used for striped or ! 32: * mirrored requests. Logical and Physical memory cannot be mixed in a single ! 33: * IOMemoryDescriptor. Several IOMemoryDescriptors may reference a single ! 34: * IOMemoryContainer (by using the replicate method). ! 35: */ ! 36: #import <driverkit/IOMemoryDescriptor.h> ! 37: #import <mach/vm_param.h> ! 38: #import <limits.h> ! 39: ! 40: /* ! 41: * Compute the start of the next physical page ! 42: */ ! 43: #define next_page(x) (trunc_page(((unsigned int) x) + page_size)) ! 44: ! 45: @interface IOMemoryDescriptor(Private) ! 46: /** ! 47: * Initialize an IOMemoryDescriptor object. ! 48: */ ! 49: - (id) initWithIOMemoryContainer ! 50: : (IOMemoryContainer *) ioMemoryContainer; ! 51: /** ! 52: * Free the descriptor and it's container. ! 53: */ ! 54: - (id) free; ! 55: /* ! 56: * validate is called when the state needs to be validated. ! 57: */ ! 58: - (void) validate; ! 59: /* ! 60: * Retrieve the current logical range (returns a zero-length range on failure). ! 61: */ ! 62: - (void) getCurrentLogicalRange; ! 63: ! 64: /* ! 65: * Retrieve the current physical range. This can fail if the O.S. returns ! 66: * an error status. ! 67: */ ! 68: - (IOReturn) getCurrentPhysicalRange; ! 69: ! 70: /* ! 71: * Force the state to the end of the entire container (for reposition ! 72: * errors). ! 73: */ ! 74: - (void) setPositionAtEnd; ! 75: @end /* IOMemoryContainer(Private) */ ! 76: ! 77: @implementation IOMemoryDescriptor(Private) ! 78: /** ! 79: * Create an empty IOMemoryDescriptor object. ! 80: */ ! 81: - (id) initWithIOMemoryContainer ! 82: : (IOMemoryContainer *) thisIOMemoryContainer ! 83: { ! 84: ioMemoryContainer = thisIOMemoryContainer; ! 85: state.currentOffset = 0; ! 86: retainCount = 1; ! 87: valid = FALSE; /* Resets other values */ ! 88: [self setMaxSegmentCount : UINT_MAX]; ! 89: return (self); ! 90: } ! 91: ! 92: /** ! 93: * Dispose of the object. This decrements the IOMemoryContainer's ! 94: * reference count and frees the IOMemoryContainer if this IOMemoryDescriptor ! 95: * is the last referencer. ! 96: */ ! 97: - free ! 98: { ! 99: [ioMemoryContainer release]; ! 100: return ([super free]); ! 101: } ! 102: ! 103: /** ! 104: * Extract the next logical range from the IOMemoryContainer. ! 105: * If this fails because rangeIndex exceeds the container max, ! 106: * a zero-length range will be returned. ! 107: */ ! 108: - (void) getCurrentLogicalRange ! 109: { ! 110: if ([ioMemoryContainer logicalRange: &state.ioRange ! 111: index: state.rangeIndex] != IO_R_SUCCESS) { ! 112: state.ioRange.start = 0xDEADBEEF; ! 113: state.ioRange.size = 0xFFFFFFFF; ! 114: } ! 115: state.logicalOffset = 0; ! 116: state.physicalOffset = 0; ! 117: } ! 118: ! 119: /** ! 120: * Return the physical address that corresponds to the current logical ! 121: * address. The state is valid at this point. This method sets the ! 122: * physicalPageLength to the maximumn number of bytes that can be ! 123: * transferred in this page. ! 124: */ ! 125: - (IOReturn) getCurrentPhysicalRange ! 126: { ! 127: IOReturn ioReturn; ! 128: unsigned int nextPageAddress; ! 129: ! 130: state.physicalOffset = 0; /* At page start */ ! 131: ioReturn = IOPhysicalFromVirtual( ! 132: [ioMemoryContainer client], ! 133: state.ioRange.start + state.logicalOffset, ! 134: (vm_offset_t *) &state.physical.address ! 135: ); ! 136: if (ioReturn != IO_R_SUCCESS) { ! 137: state.physical.address = 0; ! 138: state.physical.length = 0; ! 139: } ! 140: else { ! 141: /* ! 142: * The amount we can transfer is the number of bytes ! 143: * from the current start index to the next page ! 144: * (limited by scsiReq->maxTransfer). Mach lacks ! 145: * a method for determining the page size. We'll ! 146: * use 4096 for convenience (the only cost is extra ! 147: * cycles through the for loop). ! 148: */ ! 149: nextPageAddress = next_page(state.physical.address); ! 150: state.physical.length = ! 151: nextPageAddress - ((unsigned int) state.physical.address); ! 152: } ! 153: return (ioReturn); ! 154: } ! 155: ! 156: /** ! 157: * Validate the state so that all state values agree with ! 158: * the currentOffset. ! 159: */ ! 160: - (void) validate ! 161: { ! 162: unsigned int totalByteCount = [ioMemoryContainer totalByteCount]; ! 163: unsigned int totalRangeCount = [ioMemoryContainer rangeCount]; ! 164: ! 165: if (state.currentOffset >= totalByteCount) { ! 166: [self setPositionAtEnd]; ! 167: } ! 168: else { ! 169: unsigned int offsetAtRangeStart = 0; ! 170: unsigned int offsetAtRangeEnd; ! 171: for (state.rangeIndex = 0; ! 172: state.rangeIndex < totalRangeCount; ! 173: state.rangeIndex++) { ! 174: ! 175: /* Check for an invalid range or other problems */ ! 176: [self getCurrentLogicalRange]; ! 177: if (0xDEADBEEF == state.ioRange.start ! 178: && 0xFFFFFFFF == state.ioRange.size) { ! 179: IOPanic("IOMemoryDescriptor: " ! 180: "validate fell of the end of the world\n"); ! 181: } ! 182: offsetAtRangeEnd = offsetAtRangeStart + state.ioRange.size; ! 183: if (offsetAtRangeEnd > state.currentOffset) { ! 184: state.logicalOffset = ! 185: state.currentOffset - offsetAtRangeStart; ! 186: break; /* Normal exit */ ! 187: } ! 188: offsetAtRangeStart = offsetAtRangeEnd; ! 189: } ! 190: if (state.rangeIndex >= totalRangeCount) { ! 191: [self setPositionAtEnd]; /* Bug: can't happen */ ! 192: } ! 193: } ! 194: state.physicalOffset = 0; /* Invalidate physical */ ! 195: valid = TRUE; ! 196: } ! 197: ! 198: /* ! 199: * Force the state to the end of the entire container (for reposition ! 200: * errors). ! 201: */ ! 202: - (void) setPositionAtEnd ! 203: { ! 204: state.rangeIndex = [ioMemoryContainer rangeCount] - 1; ! 205: [self getCurrentLogicalRange]; ! 206: state.logicalOffset = state.ioRange.size; ! 207: } ! 208: ! 209: @end /* IOMemoryDescriptor(Private) */ ! 210: ! 211: @implementation IOMemoryDescriptor ! 212: ! 213: /** ! 214: * Initialize an IOMemoryDescriptor object for a logical scatter-gather list. ! 215: * The scatter-gather list is provided in DriverKit IORange format. If byReference ! 216: * is TRUE, the associated IOMemoryContainer will hold a reference to the range ! 217: * vector (which must remain addressable during the lifetime of the object). If ! 218: * FALSE, the range vector will be copied into the IOMemoryContainer object. ! 219: */ ! 220: - (id) initWithIORange ! 221: : (const IORange *) ioRange ! 222: count : (unsigned int) count ! 223: byReference : (BOOL) byReference ! 224: { ! 225: IOMemoryContainer *thisIOMemoryContainer = ! 226: [[IOMemoryContainer alloc] initWithIORange ! 227: : ioRange ! 228: count : count ! 229: byReference : byReference ! 230: ]; ! 231: [self initWithIOMemoryContainer : thisIOMemoryContainer]; ! 232: return (self); ! 233: ! 234: } ! 235: ! 236: /** ! 237: * Initialize an IOMemoryDescriptor object for a single logical range. ! 238: */ ! 239: - (id) initWithAddress ! 240: : (void *) address ! 241: length : (unsigned int) length ! 242: { ! 243: IOMemoryContainer *thisIOMemoryContainer = ! 244: [[IOMemoryContainer alloc] initWithAddress ! 245: : address ! 246: length : length ! 247: ]; ! 248: [self initWithIOMemoryContainer : thisIOMemoryContainer]; ! 249: return (self); ! 250: } ! 251: ! 252: ! 253: - (id) initWithIOV ! 254: : (const struct iovec *) iov ! 255: count : (unsigned int) count ! 256: { ! 257: IOMemoryContainer *thisIOMemoryContainer = ! 258: [[IOMemoryContainer alloc] initWithIOV ! 259: : iov ! 260: count : count ! 261: ]; ! 262: [self initWithIOMemoryContainer : thisIOMemoryContainer]; ! 263: return (self); ! 264: } ! 265: ! 266: /** ! 267: * Manage the retain/release reference count. See NSObject for details. ! 268: */ ! 269: - (unsigned int) retainCount ! 270: { ! 271: return (retainCount); ! 272: } ! 273: ! 274: - (id) retain ! 275: { ! 276: ++retainCount; ! 277: return (self); ! 278: } ! 279: ! 280: - (oneway void) release ! 281: { ! 282: if (--retainCount == 0) { ! 283: [self free]; ! 284: } ! 285: } ! 286: ! 287: ! 288: /** ! 289: * Return a copy of this IOMemoryDescriptor and its IOMemoryContainer. ! 290: * The IOMemoryContainer's reference count will be incremented. ! 291: * The current position is not duplicated: the clone will be reset ! 292: * to position zero. ! 293: */ ! 294: - (id) replicate ! 295: { ! 296: IOMemoryDescriptor *result; ! 297: ! 298: [ioMemoryContainer retain]; ! 299: result = [[self copy] initWithIOMemoryContainer ! 300: : ioMemoryContainer ! 301: ]; ! 302: if (result) { ! 303: [result setMaxSegmentCount : maxSegmentCount]; ! 304: [result setClient : [self client]]; ! 305: } ! 306: return (result); ! 307: } ! 308: ! 309: /** ! 310: * Accessor methods ! 311: */ ! 312: - (unsigned int) currentOffset ! 313: { ! 314: return (state.currentOffset); ! 315: } ! 316: ! 317: - (unsigned int) totalByteCount ! 318: { ! 319: return ([ioMemoryContainer totalByteCount]); ! 320: } ! 321: ! 322: - (unsigned int) maxSegmentCount ! 323: { ! 324: return (maxSegmentCount); ! 325: } ! 326: /* ! 327: * Retrieve the ioMemoryContainer ! 328: */ ! 329: - (id) ioMemoryContainer ! 330: { ! 331: return (ioMemoryContainer); ! 332: } ! 333: ! 334: ! 335: ! 336: - (void) setMaxSegmentCount ! 337: : (unsigned int) newMaxSegmentCount ! 338: { ! 339: maxSegmentCount = (newMaxSegmentCount == 0) ! 340: ? [self totalByteCount] ! 341: : newMaxSegmentCount; ! 342: } ! 343: ! 344: - (vm_task_t) client ! 345: { ! 346: return ([ioMemoryContainer client]); ! 347: } ! 348: ! 349: - (void) setClient ! 350: : (vm_task_t) client ! 351: { ! 352: [ioMemoryContainer setClient : client]; ! 353: } ! 354: ! 355: - (void) setIOMemoryContainer ! 356: : (id) newIOMemoryContainer ! 357: { ! 358: if (ioMemoryContainer != newIOMemoryContainer) { ! 359: [ioMemoryContainer release]; ! 360: [newIOMemoryContainer retain]; ! 361: ioMemoryContainer = newIOMemoryContainer; ! 362: } ! 363: state.currentOffset = 0; ! 364: valid = FALSE; /* Resets other values */ ! 365: } ! 366: ! 367: /** ! 368: * This retrieves all positioning information -- it is intended for ! 369: * processing SCSI Save Data Pointers messages. Callers should treat ! 370: * IOMemoryDescriptorState as an opaque object. ! 371: */ ! 372: - (void) state ! 373: : (IOMemoryDescriptorState *) statePtr ! 374: { ! 375: /* ! 376: * If we're called without a valid state, setState will ! 377: * fail (as the new state will be invalid). Note that the ! 378: * state is invalid when the IOMemoryDescriptor is first ! 379: * created. ! 380: */ ! 381: if (valid == FALSE) { ! 382: [self validate]; ! 383: } ! 384: *statePtr = state; ! 385: } ! 386: ! 387: ! 388: /** ! 389: * Reposition the IOMemoryDescriptor's current access point. (The TECO "dot"). ! 390: * setState should be be called with the results of a previous state ! 391: * method. It is very fast. The caller must not modify the state. ! 392: */ ! 393: - (void) setState ! 394: : (const IOMemoryDescriptorState *) statePtr ! 395: { ! 396: state = *statePtr; ! 397: valid = TRUE; ! 398: } ! 399: ! 400: /** ! 401: * Set the current access point to the specified byte index. This is an ! 402: * absolute position within the IOMemoryDescriptor. This will be slow ! 403: * for complex memory descriptors. setPosition does not check the parameter ! 404: * for validity -- this is done by the nextPhysicalRange method. ! 405: */ ! 406: - (void) setPosition ! 407: : (unsigned int) newPosition ! 408: { ! 409: if (state.currentOffset != newPosition) { ! 410: state.currentOffset = newPosition; ! 411: valid = FALSE; ! 412: } ! 413: } ! 414: ! 415: /** ! 416: * Set the current access point to the relative position with respect ! 417: * to the current position. This is equivalent to writing: ! 418: * [ioMemoryDescriptor setPosition ! 419: * : [ioMemoryDescriptor currentOffset] + offset]; ! 420: * This will be slow for complex memory descriptors. setOffset does not check ! 421: * the parameter for validity -- this is done by the nextPhysicalRange method. ! 422: */ ! 423: - (void) setOffset ! 424: : (signed int) offset ! 425: { ! 426: state.currentOffset += offset; ! 427: valid = FALSE; ! 428: } ! 429: ! 430: ! 431: /** ! 432: * Return one or more logical ranges. Return zero if the transfer is outside ! 433: * of the defined range (I.e., if all data has been transferred). ! 434: * @param maxRanges The maximum number of ranges to retrieve. ! 435: * @param maxByteCount The maximum number of bytes to retrieve ! 436: * in the entire sequence. To use the remaining ! 437: * transfer count, specify UINT_MAX (from limits.h). ! 438: * @param newPosition The new value of currentOffset (may be NULL) ! 439: * @param actualRanges The actual number of ranges retrieved ! 440: * (NULL if not needed) ! 441: * @param logicalRanges A vector of logical range elements. ! 442: * Return the total number of bytes in all ranges. Return zero if the current ! 443: * offset is beyond the end of the range. ! 444: */ ! 445: - (unsigned int) getLogicalRanges ! 446: : (unsigned int) maxRanges ! 447: maxByteCount : (unsigned int) maxByteCount ! 448: newPosition : (unsigned int *) newPosition ! 449: actualRanges : (unsigned int *) actualRanges ! 450: logicalRanges : (IORange *) logicalRanges ! 451: { ! 452: unsigned int byteCount; ! 453: unsigned int transferCount = 0; ! 454: unsigned int rangeCount; ! 455: unsigned int totalByteCount = [ioMemoryContainer totalByteCount]; ! 456: ! 457: if (valid == FALSE) { ! 458: [self validate]; ! 459: } ! 460: for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) { ! 461: byteCount = totalByteCount - state.currentOffset; ! 462: if (state.logicalOffset >= state.ioRange.size) { ! 463: ++state.rangeIndex; ! 464: [self getCurrentLogicalRange]; ! 465: } ! 466: if (byteCount > (state.ioRange.size - state.logicalOffset)) { ! 467: byteCount = state.ioRange.size - state.logicalOffset; ! 468: } ! 469: if (byteCount > maxSegmentCount) { ! 470: byteCount = maxSegmentCount; ! 471: } ! 472: if (byteCount > maxByteCount) { ! 473: byteCount = maxByteCount; ! 474: } ! 475: if (byteCount == 0) { ! 476: break; /* Fell off the end */ ! 477: } ! 478: logicalRanges->size = byteCount; ! 479: logicalRanges->start = state.ioRange.start ! 480: + state.logicalOffset; ! 481: ++logicalRanges; ! 482: state.logicalOffset += byteCount; ! 483: transferCount += byteCount; ! 484: state.currentOffset += transferCount; ! 485: } ! 486: if (actualRanges != NULL) { ! 487: *actualRanges = rangeCount; ! 488: } ! 489: if (newPosition != NULL) { ! 490: *newPosition = state.currentOffset; ! 491: } ! 492: state.physicalOffset = 0; /* Invalid physical range */ ! 493: return (transferCount); ! 494: } ! 495: ! 496: /** ! 497: * Return one or more physical ranges. Return zero if the transfer is outside ! 498: * of the defined range (I.e., if all data has been transferred). ! 499: * @param maxRanges The maximum number of ranges to retrieve. ! 500: * @param maxByteCount The maximum number of bytes to retrieve ! 501: * in the entire sequence. To use the remaining ! 502: * transfer count, use UINT_MAX (from limits.h). ! 503: * @param newPosition The new value of currentOffset (may be NULL) ! 504: * @param actualRanges The actual number of ranges retrieved ! 505: * (NULL if not needed) ! 506: * @param physicalRanges A vector of physical range elements. ! 507: * Return the total number of bytes in all ranges. Return zero if the current ! 508: * offset is beyond the end of the range. ! 509: */ ! 510: - (unsigned int) getPhysicalRanges ! 511: : (unsigned int) maxRanges ! 512: maxByteCount : (unsigned int) maxByteCount ! 513: newPosition : (unsigned int *) newPosition ! 514: actualRanges : (unsigned int *) actualRanges ! 515: physicalRanges : (PhysicalRange *) physicalRanges ! 516: { ! 517: unsigned int byteCount; ! 518: unsigned int transferCount = 0; ! 519: unsigned int rangeCount; ! 520: unsigned int totalByteCount = [ioMemoryContainer totalByteCount]; ! 521: ! 522: if (valid == FALSE) { ! 523: [self validate]; ! 524: } ! 525: for (rangeCount = 0; rangeCount < maxRanges; rangeCount++) { ! 526: byteCount = totalByteCount - state.currentOffset; ! 527: if (state.logicalOffset >= state.ioRange.size) { ! 528: ++state.rangeIndex; ! 529: [self getCurrentLogicalRange]; ! 530: } ! 531: if (byteCount > (state.ioRange.size - state.logicalOffset)) { ! 532: byteCount = state.ioRange.size - state.logicalOffset; ! 533: } ! 534: if ((byteCount + transferCount) > maxSegmentCount) { ! 535: byteCount = maxSegmentCount - transferCount; ! 536: } ! 537: if ((byteCount + transferCount) > maxByteCount) { ! 538: byteCount = maxByteCount - transferCount; ! 539: } ! 540: if (byteCount == 0) { ! 541: break; /* Fell off the end */ ! 542: } ! 543: if (state.physicalOffset == 0 ! 544: || state.physicalOffset >= state.physical.length) { ! 545: if ([self getCurrentPhysicalRange] != IO_R_SUCCESS) { ! 546: break; ! 547: } ! 548: } ! 549: if (byteCount > (state.physical.length - state.physicalOffset)) { ! 550: byteCount = state.physical.length - state.physicalOffset; ! 551: } ! 552: physicalRanges->length = byteCount; ! 553: physicalRanges->address = (void *) ! 554: (((unsigned int) state.physical.address) ! 555: + state.physicalOffset); ! 556: ++physicalRanges; ! 557: transferCount += byteCount; ! 558: state.physicalOffset += byteCount; ! 559: state.logicalOffset += byteCount; ! 560: state.currentOffset += byteCount; ! 561: } ! 562: if (actualRanges != NULL) { ! 563: *actualRanges = rangeCount; ! 564: } ! 565: if (newPosition != NULL) { ! 566: *newPosition = state.currentOffset; ! 567: } ! 568: return (transferCount); ! 569: } ! 570: ! 571: /** ! 572: * Copy bytes from the caller's address space to the IOMemoryContainer ! 573: * client address space. This is an inefficient routine that should only ! 574: * be used for "corner cases" such as handling unaligned transfers. ! 575: * The copy begins at the current logical address. The current logical ! 576: * position will be incremented. ! 577: * @param buffer The starting buffer address in the caller's ! 578: * address space. ! 579: * @param count The number of bytes to transfer. ! 580: * @return The actual number of bytes transferred. ! 581: */ ! 582: - (unsigned int) writeToClient ! 583: : (void *) buffer ! 584: count : (unsigned int) count ! 585: { ! 586: unsigned int totalByteCount; ! 587: unsigned int thisCount; ! 588: PhysicalRange range; ! 589: vm_address_t clientVirtualAddress; ! 590: ! 591: for (totalByteCount = 0; totalByteCount < count;) { ! 592: thisCount = [self getPhysicalRanges ! 593: : 1 /* Only one range */ ! 594: maxByteCount : count - totalByteCount ! 595: newPosition : NULL ! 596: actualRanges : NULL ! 597: physicalRanges : &range ! 598: ]; ! 599: if (thisCount == 0) { ! 600: break; /* Ran off the end of the user buffer */ ! 601: } ! 602: clientVirtualAddress = [self mapPhysicalAddressIntoIOTask : &range]; ! 603: if (clientVirtualAddress == (vm_address_t) NULL) { ! 604: [self setOffset : -range.length]; ! 605: break; ! 606: } ! 607: else { ! 608: bcopy(buffer, clientVirtualAddress, range.length); ! 609: ((unsigned char *) buffer) += range.length; ! 610: totalByteCount += range.length; ! 611: [self unmapVirtualAddressFromIOTask ! 612: : clientVirtualAddress ! 613: length : range.length ! 614: ]; ! 615: } ! 616: } ! 617: return (totalByteCount); ! 618: } ! 619: ! 620: /** ! 621: * Copy bytes from the IOMemoryContainer client's address space to the ! 622: * caller's address space. This is an inefficient routine that should only ! 623: * be used for "corner cases" such as handling unaligned transfers. ! 624: * The copy begins at the current logical address. The current logical ! 625: * position will be incremented. ! 626: * @param buffer The starting buffer address in the caller's ! 627: * address space. ! 628: * @param count The number of bytes to transfer. ! 629: * @return The actual number of bytes transferred. ! 630: */ ! 631: - (unsigned int) readFromClient ! 632: : (void *) buffer ! 633: count : (unsigned int) count ! 634: { ! 635: unsigned int totalByteCount; ! 636: unsigned int thisCount; ! 637: PhysicalRange range; ! 638: vm_address_t clientVirtualAddress; ! 639: ! 640: for (totalByteCount = 0; totalByteCount < count;) { ! 641: thisCount = [self getPhysicalRanges ! 642: : 1 /* Only one range */ ! 643: maxByteCount : count - totalByteCount ! 644: newPosition : NULL ! 645: actualRanges : NULL ! 646: physicalRanges : &range ! 647: ]; ! 648: if (thisCount == 0) { ! 649: break; /* Ran off the end of the user buffer */ ! 650: } ! 651: clientVirtualAddress = [self mapPhysicalAddressIntoIOTask : &range]; ! 652: if (clientVirtualAddress == (vm_address_t) NULL) { ! 653: [self setOffset : -range.length]; ! 654: break; ! 655: } ! 656: else { ! 657: bcopy(clientVirtualAddress, buffer, range.length); ! 658: ((unsigned char *) buffer) += range.length; ! 659: totalByteCount += range.length; ! 660: [self unmapVirtualAddressFromIOTask ! 661: : clientVirtualAddress ! 662: length : range.length ! 663: ]; ! 664: } ! 665: } ! 666: return (totalByteCount); ! 667: } ! 668: ! 669: /** ! 670: * mapPhysicalAddressIntoIOTask is used to map a potentially ! 671: * unaligned physical address and range into our virtual address ! 672: * space. It is a direct wrapper for IOMapPhysicalIntoIOTask ! 673: * that handles unaligned physical addresses. ! 674: */ ! 675: - (vm_address_t) mapPhysicalAddressIntoIOTask ! 676: : (const PhysicalRange *) range ! 677: { ! 678: vm_address_t clientVirtualAddress; ! 679: unsigned int offset; ! 680: IOReturn ioReturn; ! 681: ! 682: offset = ((unsigned int) range->address) & page_mask; ! 683: ioReturn = IOMapPhysicalIntoIOTask( ! 684: range->address - offset, ! 685: range->length + offset, ! 686: &clientVirtualAddress ! 687: ); ! 688: if (ioReturn != IO_R_SUCCESS) { ! 689: clientVirtualAddress = (vm_address_t) NULL; ! 690: } ! 691: else { ! 692: /* ! 693: * Ensure that clientVirtualAddress is on a page ! 694: * boundary and add in the actual offset. ! 695: */ ! 696: clientVirtualAddress = (vm_address_t) ! 697: (((unsigned int) clientVirtualAddress) & ~page_mask) ! 698: + offset; ! 699: } ! 700: return (clientVirtualAddress); ! 701: } ! 702: ! 703: /** ! 704: * Un-map a range that was mapped by mapPhysicalAddressIntoIOTask. ! 705: * rangeLength must be identical to the range.length parameter passed ! 706: * to mapPhysicalAddressIntoIOTask. ! 707: */ ! 708: - (void) unmapVirtualAddressFromIOTask ! 709: : (vm_address_t) clientVirtualAddress ! 710: length : (unsigned int) rangeLength ! 711: { ! 712: unsigned int offset; ! 713: vm_address_t pageBaseAddress; ! 714: ! 715: offset = ((unsigned int) clientVirtualAddress) & page_mask; ! 716: pageBaseAddress = (vm_address_t) ! 717: ((unsigned int) clientVirtualAddress) & ~page_mask; ! 718: (void) IOUnmapPhysicalFromIOTask( ! 719: pageBaseAddress, rangeLength + offset); ! 720: } ! 721: ! 722: /** ! 723: * Make the memory described by this IOMemoryDescriptor resident. ! 724: * This is called by the virtual memory manager and/or file system before ! 725: * starting an I/O request. Residency is an all-or-nothing process. The ! 726: * IOMemoryDescriptor maintains a reference count: the first caller makes the ! 727: * memory resident; the others just increment the count. This method returns ! 728: * an error status if any range cannot be made resident and all memory will ! 729: * be made pageable. This method may only be called by kernel servers. ! 730: */ ! 731: - (IOReturn) wireMemory ! 732: : (BOOL) forReading ! 733: { ! 734: return ([ioMemoryContainer wireMemory : forReading]); ! 735: } ! 736: ! 737: /** ! 738: * Make the memory described by this underlying IOMemoryDescriptor pageable. ! 739: * This is called by the virtual memory manager and/or file system after ! 740: * completing an I/O request. The IOMemoryDescriptor maintains a reference ! 741: * count: the last caller frees the memory the others just decrement the count. ! 742: * This method returns an error status if any range could not be freed, ! 743: * but always tries to free all ranges. Return IO_R_VM_FAILURE if any range ! 744: * can't be unwired (but there is no indication as to which range). ! 745: */ ! 746: - (IOReturn) unwireMemory ! 747: { ! 748: return ([ioMemoryContainer unwireMemory]); ! 749: } ! 750: ! 751: /** ! 752: * Normalize cache coherency (if needed by this particular hardware ! 753: * architecture) before starting a DMA operation. This normalizes all ! 754: * memory described by this IOMemoryContainer. This is used as follows: ! 755: * mem = [IOMemoryDescriptor allocLogicalRange ! 756: * : address ! 757: * length : length]; ! 758: * [mem makeResident]; ! 759: * [mem checkpoint : ioCheckpointInput]; ! 760: * ... Extract physical ranges and do DMA I/O ... ! 761: * [mem checkpoint : ioCheckpointComplete]; ! 762: * [mem makePageable]; ! 763: * [mem free]; ! 764: * A checkpoint call may specify any combination of ioCheckpointInput, ! 765: * ioCheckpointOutput, or ioCheckpointNoDirection. After DMA completes, ! 766: * drivers must call checkpoint with ioCheckpointComplete as the only ! 767: * parameter. The actual operation of checkpoint is processor-specific. ! 768: */ ! 769: - (IOReturn) checkpoint ! 770: : (IOMemoryCheckpointOption) option ! 771: { ! 772: /* ! 773: * *** Hmm: if we have multiple users, the checkpoint probably should be ! 774: * *** inside the descriptor, not the container ! 775: */ ! 776: return ([ioMemoryContainer checkpoint : option]); ! 777: } ! 778: ! 779: @end /* IOMemoryDescriptor : IOObject */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.