|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. ! 24: * ! 25: * HISTORY ! 26: * ! 27: */ ! 28: ! 29: #include <IOKit/assert.h> ! 30: #include <IOKit/system.h> ! 31: #include <IOKit/IOLib.h> ! 32: #include <IOKit/IOMemoryDescriptor.h> ! 33: ! 34: #include <IOKit/IOKitDebug.h> ! 35: ! 36: #include <libkern/c++/OSContainers.h> ! 37: ! 38: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 39: ! 40: OSDefineMetaClass( IOMemoryDescriptor, OSObject ) ! 41: OSDefineAbstractStructors( IOMemoryDescriptor, OSObject ) ! 42: ! 43: #define super IOMemoryDescriptor ! 44: ! 45: OSDefineMetaClassAndStructors(IOGeneralMemoryDescriptor, IOMemoryDescriptor) ! 46: ! 47: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 48: ! 49: /* ! 50: * withAddress: ! 51: * ! 52: * Create a new IOMemoryDescriptor. The buffer is a virtual address ! 53: * relative to the specified task. If no task is supplied, the kernel ! 54: * task is implied. ! 55: */ ! 56: IOMemoryDescriptor * ! 57: IOMemoryDescriptor::withAddress(void * address, ! 58: IOByteCount withLength, ! 59: IODirection withDirection) ! 60: { ! 61: IOGeneralMemoryDescriptor * that = new IOGeneralMemoryDescriptor; ! 62: if (that) ! 63: { ! 64: if (that->initWithAddress(address, withLength, withDirection)) ! 65: return that; ! 66: ! 67: that->release(); ! 68: } ! 69: return 0; ! 70: } ! 71: ! 72: IOMemoryDescriptor * ! 73: IOMemoryDescriptor::withAddress(vm_address_t address, ! 74: IOByteCount withLength, ! 75: IODirection withDirection, ! 76: task_t withTask) ! 77: { ! 78: IOGeneralMemoryDescriptor * that = new IOGeneralMemoryDescriptor; ! 79: if (that) ! 80: { ! 81: if (that->initWithAddress(address, withLength, withDirection, withTask)) ! 82: return that; ! 83: ! 84: that->release(); ! 85: } ! 86: return 0; ! 87: } ! 88: ! 89: IOMemoryDescriptor * ! 90: IOMemoryDescriptor::withPhysicalAddress( ! 91: IOPhysicalAddress address, ! 92: IOByteCount withLength, ! 93: IODirection withDirection ) ! 94: { ! 95: return( IOMemoryDescriptor::withAddress( address, withLength, ! 96: withDirection, (task_t) 0 )); ! 97: } ! 98: ! 99: ! 100: /* ! 101: * withRanges: ! 102: * ! 103: * Create a new IOMemoryDescriptor. The buffer is made up of several ! 104: * virtual address ranges, from a given task. ! 105: * ! 106: * Passing the ranges as a reference will avoid an extra allocation. ! 107: */ ! 108: IOMemoryDescriptor * ! 109: IOMemoryDescriptor::withRanges( IOVirtualRange * ranges, ! 110: UInt32 withCount, ! 111: IODirection withDirection, ! 112: task_t withTask, ! 113: bool asReference = false) ! 114: { ! 115: IOGeneralMemoryDescriptor * that = new IOGeneralMemoryDescriptor; ! 116: if (that) ! 117: { ! 118: if (that->initWithRanges(ranges, withCount, withDirection, withTask, asReference)) ! 119: return that; ! 120: ! 121: that->release(); ! 122: } ! 123: return 0; ! 124: } ! 125: ! 126: IOMemoryDescriptor * ! 127: IOMemoryDescriptor::withPhysicalRanges( IOPhysicalRange * ranges, ! 128: UInt32 withCount, ! 129: IODirection withDirection, ! 130: bool asReference = false) ! 131: { ! 132: IOGeneralMemoryDescriptor * that = new IOGeneralMemoryDescriptor; ! 133: if (that) ! 134: { ! 135: if (that->initWithPhysicalRanges(ranges, withCount, withDirection, asReference)) ! 136: return that; ! 137: ! 138: that->release(); ! 139: } ! 140: return 0; ! 141: } ! 142: ! 143: IOMemoryDescriptor * ! 144: IOMemoryDescriptor::withSubRange(IOMemoryDescriptor * of, ! 145: IOByteCount offset, ! 146: IOByteCount length, ! 147: IODirection withDirection) ! 148: { ! 149: IOSubMemoryDescriptor * that = new IOSubMemoryDescriptor; ! 150: ! 151: if (that && !that->initSubRange(of, offset, length, withDirection)) { ! 152: that->release(); ! 153: that = 0; ! 154: } ! 155: return that; ! 156: } ! 157: ! 158: /* ! 159: * initWithAddress: ! 160: * ! 161: * Initialize an IOMemoryDescriptor. The buffer is a virtual address ! 162: * relative to the specified task. If no task is supplied, the kernel ! 163: * task is implied. ! 164: * ! 165: * An IOMemoryDescriptor can be re-used by calling initWithAddress or ! 166: * initWithRanges again on an existing instance -- note this behavior ! 167: * is not commonly supported in other I/O Kit classes, although it is ! 168: * supported here. ! 169: */ ! 170: bool ! 171: IOGeneralMemoryDescriptor::initWithAddress(void * address, ! 172: IOByteCount withLength, ! 173: IODirection withDirection) ! 174: { ! 175: _singleRange.v.address = (vm_address_t) address; ! 176: _singleRange.v.length = withLength; ! 177: ! 178: return initWithRanges(&_singleRange.v, 1, withDirection, kernel_task, true); ! 179: } ! 180: ! 181: bool ! 182: IOGeneralMemoryDescriptor::initWithAddress(vm_address_t address, ! 183: IOByteCount withLength, ! 184: IODirection withDirection, ! 185: task_t withTask) ! 186: { ! 187: _singleRange.v.address = address; ! 188: _singleRange.v.length = withLength; ! 189: ! 190: return initWithRanges(&_singleRange.v, 1, withDirection, withTask, true); ! 191: } ! 192: ! 193: bool ! 194: IOGeneralMemoryDescriptor::initWithPhysicalAddress( ! 195: IOPhysicalAddress address, ! 196: IOByteCount withLength, ! 197: IODirection withDirection ) ! 198: { ! 199: _singleRange.p.address = address; ! 200: _singleRange.p.length = withLength; ! 201: ! 202: return initWithPhysicalRanges( &_singleRange.p, 1, withDirection, true); ! 203: } ! 204: ! 205: /* ! 206: * initWithRanges: ! 207: * ! 208: * Initialize an IOMemoryDescriptor. The buffer is made up of several ! 209: * virtual address ranges, from a given task ! 210: * ! 211: * Passing the ranges as a reference will avoid an extra allocation. ! 212: * ! 213: * An IOMemoryDescriptor can be re-used by calling initWithAddress or ! 214: * initWithRanges again on an existing instance -- note this behavior ! 215: * is not commonly supported in other I/O Kit classes, although it is ! 216: * supported here. ! 217: */ ! 218: bool ! 219: IOGeneralMemoryDescriptor::initWithRanges( ! 220: IOVirtualRange * ranges, ! 221: UInt32 withCount, ! 222: IODirection withDirection, ! 223: task_t withTask, ! 224: bool asReference = false) ! 225: { ! 226: assert(ranges); ! 227: assert(withCount); ! 228: ! 229: /* ! 230: * We can check the _initialized instance variable before having ever set ! 231: * it to an initial value because I/O Kit guarantees that all our instance ! 232: * variables are zeroed on an object's allocation. ! 233: */ ! 234: ! 235: if (_initialized == false) ! 236: { ! 237: if (super::init() == false) return false; ! 238: _initialized = true; ! 239: } ! 240: else ! 241: { ! 242: /* ! 243: * An existing memory descriptor is being retargeted to point to ! 244: * somewhere else. Clean up our present state. ! 245: */ ! 246: ! 247: assert(_wireCount == 0); ! 248: ! 249: while (_wireCount) ! 250: complete(); ! 251: if (_kernPtr) ! 252: unmapFromKernel(); ! 253: if (_ranges.v && _rangesIsAllocated) ! 254: IODelete(_ranges.v, IOVirtualRange, _rangesCount); ! 255: } ! 256: ! 257: /* ! 258: * Initialize the memory descriptor. ! 259: */ ! 260: ! 261: _ranges.v = 0; ! 262: _rangesCount = withCount; ! 263: _rangesIsAllocated = asReference ? false : true; ! 264: _direction = withDirection; ! 265: _length = 0; ! 266: _task = withTask; ! 267: _position = 0; ! 268: _positionAtIndex = 0; ! 269: _positionAtOffset = 0; ! 270: _kernPtr = 0; ! 271: _cachedPhysicalAddress = 0; ! 272: _cachedVirtualAddress = 0; ! 273: ! 274: if (asReference) ! 275: _ranges.v = ranges; ! 276: else ! 277: { ! 278: _ranges.v = IONew(IOVirtualRange, withCount); ! 279: if (_ranges.v == 0) return false; ! 280: bcopy(/* from */ ranges, _ranges.v, withCount * sizeof(IOVirtualRange)); ! 281: } ! 282: ! 283: for (unsigned index = 0; index < _rangesCount; index++) ! 284: { ! 285: _length += _ranges.v[index].length; ! 286: } ! 287: ! 288: return true; ! 289: } ! 290: ! 291: bool ! 292: IOGeneralMemoryDescriptor::initWithPhysicalRanges( IOPhysicalRange * ranges, ! 293: UInt32 withCount, ! 294: IODirection withDirection, ! 295: bool asReference = false) ! 296: { ! 297: #warning assuming virtual, physical addresses same size ! 298: return( initWithRanges( (IOVirtualRange *) ranges, ! 299: withCount, withDirection, (task_t) 0, asReference )); ! 300: } ! 301: ! 302: /* ! 303: * free ! 304: * ! 305: * Free resources. ! 306: */ ! 307: void IOGeneralMemoryDescriptor::free() ! 308: { ! 309: while (_wireCount) ! 310: complete(); ! 311: if (_kernPtr) ! 312: unmapFromKernel(); ! 313: if (_ranges.v && _rangesIsAllocated) ! 314: IODelete(_ranges.v, IOVirtualRange, _rangesCount); ! 315: super::free(); ! 316: } ! 317: ! 318: void IOGeneralMemoryDescriptor::unmapFromKernel() ! 319: { ! 320: kern_return_t krtn; ! 321: vm_offset_t off; ! 322: // Pull the shared pages out of the task map ! 323: // Do we need to unwire it first? ! 324: for ( off = 0; off < _kernSize; off += page_size ) ! 325: { ! 326: pmap_change_wiring( ! 327: kernel_pmap, ! 328: _kernPtrAligned + off, ! 329: FALSE); ! 330: ! 331: pmap_remove( ! 332: kernel_pmap, ! 333: _kernPtrAligned + off, ! 334: _kernPtrAligned + off + page_size); ! 335: } ! 336: // Free the former shmem area in the task ! 337: krtn = vm_deallocate(kernel_map, ! 338: _kernPtrAligned, ! 339: _kernSize ); ! 340: assert(krtn == KERN_SUCCESS); ! 341: _kernPtr = 0; ! 342: } ! 343: ! 344: void IOGeneralMemoryDescriptor::mapIntoKernel(unsigned rangeIndex) ! 345: { ! 346: kern_return_t krtn; ! 347: vm_offset_t off; ! 348: ! 349: if (_kernPtr) ! 350: { ! 351: if (_kernPtrAtIndex == rangeIndex) return; ! 352: unmapFromKernel(); ! 353: assert(_kernPtr == 0); ! 354: } ! 355: ! 356: vm_offset_t srcAlign = trunc_page(_ranges.v[rangeIndex].address); ! 357: ! 358: _kernSize = trunc_page(_ranges.v[rangeIndex].address + ! 359: _ranges.v[rangeIndex].length + ! 360: page_size - 1) - srcAlign; ! 361: ! 362: /* Find some memory of the same size in kernel task. We use vm_allocate() ! 363: to do this. vm_allocate inserts the found memory object in the ! 364: target task's map as a side effect. */ ! 365: krtn = vm_allocate( kernel_map, ! 366: &_kernPtrAligned, ! 367: _kernSize, ! 368: TRUE ); // Find first fit ! 369: assert(krtn == KERN_SUCCESS); ! 370: if(krtn) return; ! 371: ! 372: /* For each page in the area allocated from the kernel map, ! 373: find the physical address of the page. ! 374: Enter the page in the target task's pmap, at the ! 375: appropriate target task virtual address. */ ! 376: for ( off = 0; off < _kernSize; off += page_size ) ! 377: { ! 378: vm_offset_t kern_phys_addr, phys_addr; ! 379: if( _task) ! 380: phys_addr = pmap_extract( get_task_pmap(_task), srcAlign + off ); ! 381: else ! 382: phys_addr = srcAlign + off; ! 383: assert(phys_addr); ! 384: if(phys_addr == 0) return; ! 385: ! 386: // Check original state. ! 387: kern_phys_addr = pmap_extract( kernel_pmap, _kernPtrAligned + off ); ! 388: // Set virtual page to point to the right physical one ! 389: pmap_enter( ! 390: kernel_pmap, ! 391: _kernPtrAligned + off, ! 392: phys_addr, ! 393: VM_PROT_READ|VM_PROT_WRITE, ! 394: TRUE); ! 395: } ! 396: _kernPtr = _kernPtrAligned + (_ranges.v[rangeIndex].address - srcAlign); ! 397: _kernPtrAtIndex = rangeIndex; ! 398: } ! 399: ! 400: /* ! 401: * getDirection: ! 402: * ! 403: * Get the direction of the transfer. ! 404: */ ! 405: IODirection IOMemoryDescriptor::getDirection() const ! 406: { ! 407: return _direction; ! 408: } ! 409: ! 410: /* ! 411: * getLength: ! 412: * ! 413: * Get the length of the transfer (over all ranges). ! 414: */ ! 415: IOByteCount IOMemoryDescriptor::getLength() const ! 416: { ! 417: return _length; ! 418: } ! 419: ! 420: void IOMemoryDescriptor::setTag( ! 421: IOOptionBits tag ) ! 422: { ! 423: _tag = tag; ! 424: } ! 425: ! 426: IOOptionBits IOMemoryDescriptor::getTag( void ) ! 427: { ! 428: return( _tag); ! 429: } ! 430: ! 431: /* ! 432: * setPosition ! 433: * ! 434: * Set the logical start position inside the client buffer. ! 435: * ! 436: * It is convention that the position reflect the actual byte count that ! 437: * is successfully transferred into or out of the buffer, before the I/O ! 438: * request is "completed" (ie. sent back to its originator). ! 439: */ ! 440: ! 441: void IOGeneralMemoryDescriptor::setPosition(IOByteCount position) ! 442: { ! 443: assert(position <= _length); ! 444: ! 445: if (position >= _length) ! 446: { ! 447: _position = _length; ! 448: _positionAtIndex = _rangesCount; /* careful: out-of-bounds */ ! 449: _positionAtOffset = 0; ! 450: return; ! 451: } ! 452: ! 453: if (position < _position) ! 454: { ! 455: _positionAtOffset = position; ! 456: _positionAtIndex = 0; ! 457: } ! 458: else ! 459: { ! 460: _positionAtOffset += (position - _position); ! 461: } ! 462: _position = position; ! 463: ! 464: while (_positionAtOffset >= _ranges.v[_positionAtIndex].length) ! 465: { ! 466: _positionAtOffset -= _ranges.v[_positionAtIndex].length; ! 467: _positionAtIndex++; ! 468: } ! 469: } ! 470: ! 471: /* ! 472: * readBytes: ! 473: * ! 474: * Copy data from the memory descriptor's buffer into the specified buffer, ! 475: * relative to the current position. The memory descriptor's position is ! 476: * advanced based on the number of bytes copied. ! 477: */ ! 478: ! 479: IOByteCount IOGeneralMemoryDescriptor::readBytes(IOByteCount offset, ! 480: void * bytes, IOByteCount withLength) ! 481: { ! 482: IOByteCount bytesLeft; ! 483: void * segment; ! 484: IOByteCount segmentLength; ! 485: ! 486: if( offset != _position) ! 487: setPosition( offset ); ! 488: ! 489: withLength = min(withLength, _length - _position); ! 490: bytesLeft = withLength; ! 491: ! 492: #if 0 ! 493: while (bytesLeft && (_position < _length)) ! 494: { ! 495: /* Compute the relative length to the end of this virtual segment. */ ! 496: segmentLength = min(_ranges.v[_positionAtIndex].length - _positionAtOffset, bytesLeft); ! 497: ! 498: /* Compute the relative address of this virtual segment. */ ! 499: segment = (void *)(_ranges.v[_positionAtIndex].address + _positionAtOffset); ! 500: ! 501: if (KERN_SUCCESS != vm_map_read_user(get_task_map(_task), ! 502: /* from */ (vm_offset_t) segment, /* to */ (vm_offset_t) bytes, ! 503: /* size */ segmentLength)) ! 504: { ! 505: assert( false ); ! 506: bytesLeft = withLength; ! 507: break; ! 508: } ! 509: bytesLeft -= segmentLength; ! 510: offset += segmentLength; ! 511: setPosition(offset); ! 512: } ! 513: #else ! 514: while (bytesLeft && (segment = getVirtualSegment(offset, &segmentLength))) ! 515: { ! 516: segmentLength = min(segmentLength, bytesLeft); ! 517: bcopy(/* from */ segment, /* to */ bytes, /* size */ segmentLength); ! 518: bytesLeft -= segmentLength; ! 519: offset += segmentLength; ! 520: } ! 521: #endif ! 522: ! 523: return withLength - bytesLeft; ! 524: } ! 525: ! 526: /* ! 527: * writeBytes: ! 528: * ! 529: * Copy data to the memory descriptor's buffer from the specified buffer, ! 530: * relative to the current position. The memory descriptor's position is ! 531: * advanced based on the number of bytes copied. ! 532: */ ! 533: IOByteCount IOGeneralMemoryDescriptor::writeBytes(IOByteCount offset, ! 534: const void* bytes,IOByteCount withLength) ! 535: { ! 536: IOByteCount bytesLeft; ! 537: void * segment; ! 538: IOByteCount segmentLength; ! 539: ! 540: if( offset != _position) ! 541: setPosition( offset ); ! 542: ! 543: withLength = min(withLength, _length - _position); ! 544: bytesLeft = withLength; ! 545: ! 546: #if 0 ! 547: while (bytesLeft && (_position < _length)) ! 548: { ! 549: assert(_position <= _length); ! 550: ! 551: /* Compute the relative length to the end of this virtual segment. */ ! 552: segmentLength = min(_ranges.v[_positionAtIndex].length - _positionAtOffset, bytesLeft); ! 553: ! 554: /* Compute the relative address of this virtual segment. */ ! 555: segment = (void *)(_ranges.v[_positionAtIndex].address + _positionAtOffset); ! 556: ! 557: if (KERN_SUCCESS != vm_map_write_user(get_task_map(_task), ! 558: /* from */ (vm_offset_t) bytes, ! 559: /* to */ (vm_offset_t) segment, ! 560: /* size */ segmentLength)) ! 561: { ! 562: assert( false ); ! 563: bytesLeft = withLength; ! 564: break; ! 565: } ! 566: bytesLeft -= segmentLength; ! 567: offset += segmentLength; ! 568: setPosition(offset); ! 569: } ! 570: #else ! 571: while (bytesLeft && (segment = getVirtualSegment(offset, &segmentLength))) ! 572: { ! 573: segmentLength = min(segmentLength, bytesLeft); ! 574: bcopy(/* from */ bytes, /* to */ segment, /* size */ segmentLength); ! 575: bytesLeft -= segmentLength; ! 576: offset += segmentLength; ! 577: } ! 578: #endif ! 579: ! 580: return withLength - bytesLeft; ! 581: } ! 582: ! 583: /* ! 584: * getPhysicalSegment: ! 585: * ! 586: * Get the physical address of the buffer, relative to the current position. ! 587: * If the current position is at the end of the buffer, a zero is returned. ! 588: */ ! 589: IOPhysicalAddress ! 590: IOGeneralMemoryDescriptor::getPhysicalSegment(IOByteCount offset, ! 591: IOByteCount * lengthOfSegment) ! 592: { ! 593: vm_address_t virtualAddress; ! 594: IOByteCount virtualLength; ! 595: pmap_t virtualPMap; ! 596: IOPhysicalAddress physicalAddress; ! 597: IOPhysicalLength physicalLength; ! 598: ! 599: if ((0 == _task) && (1 == _rangesCount)) ! 600: { ! 601: assert(offset <= _length); ! 602: if (offset >= _length) ! 603: { ! 604: physicalAddress = 0; ! 605: physicalLength = 0; ! 606: } ! 607: else ! 608: { ! 609: physicalLength = _length - offset; ! 610: physicalAddress = offset + _ranges.v[0].address; ! 611: } ! 612: ! 613: if (lengthOfSegment) ! 614: *lengthOfSegment = physicalLength; ! 615: return physicalAddress; ! 616: } ! 617: ! 618: if( offset != _position) ! 619: setPosition( offset ); ! 620: ! 621: assert(_position <= _length); ! 622: ! 623: /* Fail gracefully if the position is at (or past) the end-of-buffer. */ ! 624: if (_position >= _length) ! 625: { ! 626: *lengthOfSegment = 0; ! 627: return 0; ! 628: } ! 629: ! 630: /* Prepare to compute the largest contiguous physical length possible. */ ! 631: ! 632: virtualAddress = _ranges.v[_positionAtIndex].address + _positionAtOffset; ! 633: virtualLength = _ranges.v[_positionAtIndex].length - _positionAtOffset; ! 634: if( _task) ! 635: virtualPMap = get_task_pmap(_task); ! 636: else ! 637: virtualPMap = 0; ! 638: ! 639: physicalAddress = (virtualAddress == _cachedVirtualAddress) ? ! 640: _cachedPhysicalAddress : /* optimization */ ! 641: virtualPMap ? ! 642: pmap_extract(virtualPMap, virtualAddress) : ! 643: virtualAddress; ! 644: physicalLength = trunc_page(physicalAddress) + page_size - physicalAddress; ! 645: ! 646: if (physicalAddress == 0) /* memory must be wired in order to proceed */ ! 647: { ! 648: assert(physicalAddress); ! 649: *lengthOfSegment = 0; ! 650: return 0; ! 651: } ! 652: ! 653: /* Compute the largest contiguous physical length possible, within range. */ ! 654: vm_address_t virtualPage = trunc_page(virtualAddress); ! 655: IOPhysicalAddress physicalPage = trunc_page(physicalAddress); ! 656: ! 657: while (physicalLength < virtualLength) ! 658: { ! 659: physicalPage += page_size; ! 660: virtualPage += page_size; ! 661: _cachedVirtualAddress = virtualPage; ! 662: _cachedPhysicalAddress = virtualPMap ? ! 663: pmap_extract(virtualPMap, virtualPage) : ! 664: virtualPage; ! 665: ! 666: if (_cachedPhysicalAddress != physicalPage) break; ! 667: ! 668: physicalLength += page_size; ! 669: } ! 670: ! 671: /* Clip contiguous physical length at the end of this range. */ ! 672: if (physicalLength > virtualLength) ! 673: physicalLength = virtualLength; ! 674: ! 675: if( lengthOfSegment) ! 676: *lengthOfSegment = physicalLength; ! 677: ! 678: return physicalAddress; ! 679: } ! 680: ! 681: ! 682: /* ! 683: * getVirtualSegment: ! 684: * ! 685: * Get the virtual address of the buffer, relative to the current position. ! 686: * If the memory wasn't mapped into the caller's address space, it will be ! 687: * mapped in now. If the current position is at the end of the buffer, a ! 688: * null is returned. ! 689: */ ! 690: void * IOGeneralMemoryDescriptor::getVirtualSegment(IOByteCount offset, ! 691: IOByteCount * lengthOfSegment) ! 692: { ! 693: if( offset != _position) ! 694: setPosition( offset ); ! 695: ! 696: assert(_position <= _length); ! 697: ! 698: /* Fail gracefully if the position is at (or past) the end-of-buffer. */ ! 699: if (_position >= _length) ! 700: { ! 701: *lengthOfSegment = 0; ! 702: return 0; ! 703: } ! 704: ! 705: /* Compute the relative length to the end of this virtual segment. */ ! 706: *lengthOfSegment = _ranges.v[_positionAtIndex].length - _positionAtOffset; ! 707: ! 708: /* Compute the relative address of this virtual segment. */ ! 709: if (_task == kernel_task) ! 710: return (void *)(_ranges.v[_positionAtIndex].address + _positionAtOffset); ! 711: else ! 712: { ! 713: mapIntoKernel(_positionAtIndex); ! 714: return (void *)(_kernPtr + _positionAtOffset); ! 715: } ! 716: } ! 717: ! 718: /* ! 719: * prepare ! 720: * ! 721: * Prepare the memory for an I/O transfer. This involves paging in ! 722: * the memory, if necessary, and wiring it down for the duration of ! 723: * the transfer. The complete() method completes the processing of ! 724: * the memory after the I/O transfer finishes. This method needn't ! 725: * called for non-pageable memory. ! 726: */ ! 727: IOReturn IOGeneralMemoryDescriptor::prepare( ! 728: IODirection forDirection = kIODirectionNone) ! 729: { ! 730: IOReturn rc = kIOReturnSuccess; ! 731: ! 732: _wireCount++; ! 733: if(_task && (_task != kernel_task) && (_wireCount == 1)) { ! 734: UInt rangeIndex; ! 735: kern_return_t rc; ! 736: vm_prot_t access = VM_PROT_DEFAULT; // Could be cleverer using _direction ! 737: ! 738: // ! 739: // Check user read/write access to the data buffer. ! 740: // ! 741: ! 742: for (rangeIndex = 0; rangeIndex < _rangesCount; rangeIndex++) ! 743: { ! 744: vm_offset_t checkBase = trunc_page(_ranges.v[rangeIndex].address); ! 745: vm_size_t checkSize = round_page(_ranges.v[rangeIndex].length ); ! 746: ! 747: while (checkSize) ! 748: { ! 749: vm_region_basic_info_data_t regionInfo; ! 750: mach_msg_type_number_t regionInfoSize = sizeof(regionInfo); ! 751: vm_size_t regionSize; ! 752: ! 753: if ( (vm_region( ! 754: /* map */ get_task_map(_task), ! 755: /* address */ &checkBase, ! 756: /* size */ ®ionSize, ! 757: /* flavor */ VM_REGION_BASIC_INFO, ! 758: /* info */ (vm_region_info_t) ®ionInfo, ! 759: /* info size */ ®ionInfoSize, ! 760: /* object name */ 0 ) != KERN_SUCCESS ) || ! 761: ( (_direction & kIODirectionIn ) && ! 762: !(regionInfo.protection & VM_PROT_WRITE) ) || ! 763: ( (_direction & kIODirectionOut) && ! 764: !(regionInfo.protection & VM_PROT_READ ) ) ) ! 765: { ! 766: return kIOReturnVMError; ! 767: } ! 768: ! 769: assert((regionSize & PAGE_MASK) == 0); ! 770: ! 771: regionSize = min(regionSize, checkSize); ! 772: checkSize -= regionSize; ! 773: checkBase += regionSize; ! 774: } // (for each vm region) ! 775: } // (for each io range) ! 776: ! 777: for(rangeIndex = 0; rangeIndex < _rangesCount; rangeIndex++) { ! 778: ! 779: vm_offset_t srcAlign = trunc_page(_ranges.v[rangeIndex].address); ! 780: IOByteCount srcAlignEnd = trunc_page(_ranges.v[rangeIndex].address + ! 781: _ranges.v[rangeIndex].length + ! 782: page_size - 1); ! 783: rc = vm_map_wire(get_task_map(_task), srcAlign, ! 784: srcAlignEnd, access, FALSE); ! 785: if(rc != KERN_SUCCESS) { ! 786: UInt doneIndex; ! 787: IOLog("IOMemoryDescriptor::prepare: vm_map_wire failed: %d\n", rc); ! 788: for(doneIndex = 0; doneIndex < rangeIndex; doneIndex++) { ! 789: vm_offset_t srcAlign = trunc_page(_ranges.v[doneIndex].address); ! 790: IOByteCount srcAlignEnd = trunc_page(_ranges.v[doneIndex].address + ! 791: _ranges.v[doneIndex].length + ! 792: page_size - 1); ! 793: vm_map_unwire(get_task_map(_task), srcAlign, ! 794: srcAlignEnd, FALSE); ! 795: } ! 796: _wireCount = 0; // Back to unwired state now. ! 797: } ! 798: } ! 799: } ! 800: return rc; ! 801: } ! 802: ! 803: /* ! 804: * complete ! 805: * ! 806: * Complete processing of the memory after an I/O transfer finishes. ! 807: * This method should not be called unless a prepare was previously ! 808: * issued; the prepare() and complete() must occur in pairs, before ! 809: * before and after an I/O transfer involving pageable memory. ! 810: */ ! 811: IOReturn IOGeneralMemoryDescriptor::complete( ! 812: IODirection forDirection = kIODirectionNone) ! 813: { ! 814: assert(_wireCount); ! 815: _wireCount--; ! 816: if(_task && (_task != kernel_task) && (_wireCount == 0)) { ! 817: UInt rangeIndex; ! 818: kern_return_t rc; ! 819: for(rangeIndex = 0; rangeIndex < _rangesCount; rangeIndex++) { ! 820: ! 821: vm_offset_t srcAlign = trunc_page(_ranges.v[rangeIndex].address); ! 822: IOByteCount srcAlignEnd = trunc_page(_ranges.v[rangeIndex].address + ! 823: _ranges.v[rangeIndex].length + ! 824: page_size - 1); ! 825: rc = vm_map_unwire(get_task_map(_task), srcAlign, ! 826: srcAlignEnd, FALSE); ! 827: if(rc != KERN_SUCCESS) ! 828: IOLog("IOMemoryDescriptor::complete: vm_map_unwire failed: %d\n", rc); ! 829: } ! 830: } ! 831: return kIOReturnSuccess; ! 832: } ! 833: ! 834: IOReturn IOGeneralMemoryDescriptor::doMap( ! 835: task_t addressTask, ! 836: IOVirtualAddress * atAddress, ! 837: IOOptionBits options, ! 838: IOByteCount sourceOffset = 0, ! 839: IOByteCount length = 0 ) ! 840: { ! 841: // could be much better ! 842: if( (addressTask == _task) && (options & kIOMapAnywhere) ! 843: && (1 == _rangesCount) && (0 == sourceOffset) ! 844: && (length <= _ranges.v[0].length) ) { ! 845: *atAddress = _ranges.v[0].address; ! 846: return( kIOReturnSuccess ); ! 847: } ! 848: ! 849: return( super::doMap( addressTask, atAddress, ! 850: options, sourceOffset, length )); ! 851: } ! 852: ! 853: IOReturn IOGeneralMemoryDescriptor::doUnmap( ! 854: task_t addressTask, ! 855: IOVirtualAddress logical, ! 856: IOByteCount length ) ! 857: { ! 858: // could be much better ! 859: if( (addressTask == _task) && (1 == _rangesCount) ! 860: && (logical == _ranges.v[0].address) ! 861: && (length <= _ranges.v[0].length) ) ! 862: return( kIOReturnSuccess ); ! 863: ! 864: return( super::doUnmap( addressTask, logical, length )); ! 865: } ! 866: ! 867: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 868: ! 869: extern "C" { ! 870: // osfmk/device/iokit_rpc.c ! 871: extern kern_return_t IOMapPages(vm_map_t map, vm_offset_t va, vm_offset_t pa, ! 872: vm_size_t length, unsigned int mapFlags); ! 873: }; ! 874: ! 875: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 876: ! 877: static IOLock * gIOMemoryLock; ! 878: ! 879: #define LOCK IOTakeLock( gIOMemoryLock) ! 880: #define UNLOCK IOUnlock( gIOMemoryLock) ! 881: ! 882: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 883: ! 884: OSDefineMetaClass( IOMemoryMap, OSObject ) ! 885: OSDefineAbstractStructors( IOMemoryMap, OSObject ) ! 886: ! 887: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 888: ! 889: class _IOMemoryMap : public IOMemoryMap ! 890: { ! 891: OSDeclareDefaultStructors(_IOMemoryMap) ! 892: ! 893: IOMemoryDescriptor * memory; ! 894: IOMemoryMap * superMap; ! 895: IOByteCount offset; ! 896: IOByteCount length; ! 897: IOVirtualAddress logical; ! 898: task_t addressTask; ! 899: IOOptionBits options; ! 900: ! 901: public: ! 902: virtual void free(); ! 903: ! 904: // IOMemoryMap methods ! 905: virtual IOVirtualAddress getVirtualAddress(); ! 906: virtual IOByteCount getLength(); ! 907: virtual task_t getAddressTask(); ! 908: virtual IOMemoryDescriptor * getMemoryDescriptor(); ! 909: virtual IOOptionBits getMapOptions(); ! 910: ! 911: virtual IOReturn unmap(); ! 912: ! 913: virtual IOPhysicalAddress getPhysicalSegment(IOByteCount offset, ! 914: IOByteCount * length); ! 915: ! 916: // for IOMemoryDescriptor use ! 917: _IOMemoryMap * isCompatible( ! 918: IOMemoryDescriptor * owner, ! 919: task_t task, ! 920: IOVirtualAddress toAddress, ! 921: IOOptionBits options, ! 922: IOByteCount offset, ! 923: IOByteCount length ); ! 924: ! 925: bool _IOMemoryMap::init( ! 926: IOMemoryDescriptor * memory, ! 927: IOMemoryMap * superMap, ! 928: IOByteCount offset, ! 929: IOByteCount length ); ! 930: ! 931: bool _IOMemoryMap::init( ! 932: IOMemoryDescriptor * memory, ! 933: task_t intoTask, ! 934: IOVirtualAddress toAddress, ! 935: IOOptionBits options, ! 936: IOByteCount offset, ! 937: IOByteCount length ); ! 938: }; ! 939: ! 940: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 941: ! 942: #undef super ! 943: #define super IOMemoryMap ! 944: ! 945: OSDefineMetaClassAndStructors(_IOMemoryMap, IOMemoryMap) ! 946: ! 947: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 948: ! 949: bool _IOMemoryMap::init( ! 950: IOMemoryDescriptor * _memory, ! 951: IOMemoryMap * _superMap, ! 952: IOByteCount _offset, ! 953: IOByteCount _length ) ! 954: { ! 955: ! 956: if( !super::init()) ! 957: return( false); ! 958: ! 959: if( (_offset + _length) > _superMap->getLength()) ! 960: return( false); ! 961: ! 962: _memory->retain(); ! 963: memory = _memory; ! 964: _superMap->retain(); ! 965: superMap = _superMap; ! 966: ! 967: offset = _offset; ! 968: if( _length) ! 969: length = _length; ! 970: else ! 971: length = _memory->getLength(); ! 972: ! 973: options = superMap->getMapOptions(); ! 974: addressTask = superMap->getAddressTask(); ! 975: logical = superMap->getVirtualAddress() + offset; ! 976: ! 977: return( true ); ! 978: } ! 979: ! 980: bool _IOMemoryMap::init( ! 981: IOMemoryDescriptor * _memory, ! 982: task_t intoTask, ! 983: IOVirtualAddress toAddress, ! 984: IOOptionBits _options, ! 985: IOByteCount _offset, ! 986: IOByteCount _length ) ! 987: { ! 988: bool ok; ! 989: ! 990: if( (!_memory) || !super::init()) ! 991: return( false); ! 992: ! 993: if( (_offset + _length) > _memory->getLength()) ! 994: return( false); ! 995: ! 996: _memory->retain(); ! 997: memory = _memory; ! 998: ! 999: offset = _offset; ! 1000: if( _length) ! 1001: length = _length; ! 1002: else ! 1003: length = _memory->getLength(); ! 1004: ! 1005: addressTask = intoTask; ! 1006: logical = toAddress; ! 1007: options = _options; ! 1008: ! 1009: if( options & kIOMapStatic) ! 1010: ok = true; ! 1011: else ! 1012: ok = (kIOReturnSuccess == memory->doMap( addressTask, &logical, ! 1013: options, offset, length )); ! 1014: if( !ok) ! 1015: logical = 0; ! 1016: ! 1017: return( ok ); ! 1018: } ! 1019: ! 1020: // documentation lies ! 1021: #define VM_ALLOCATE_ANYWHERE TRUE ! 1022: #define VM_ALLOCATE_RESERVED FALSE ! 1023: ! 1024: IOReturn IOMemoryDescriptor::doMap( ! 1025: task_t addressTask, ! 1026: IOVirtualAddress * atAddress, ! 1027: IOOptionBits options, ! 1028: IOByteCount sourceOffset = 0, ! 1029: IOByteCount length = 0 ) ! 1030: { ! 1031: IOReturn err = kIOReturnSuccess; ! 1032: vm_size_t ourSize; ! 1033: vm_size_t bytes; ! 1034: vm_offset_t mapped; ! 1035: vm_address_t logical; ! 1036: IOByteCount pageOffset; ! 1037: IOPhysicalLength segLen; ! 1038: IOPhysicalAddress physAddr; ! 1039: ! 1040: if( 0 == length) ! 1041: length = getLength(); ! 1042: ! 1043: physAddr = getPhysicalSegment( sourceOffset, &segLen ); ! 1044: assert( physAddr ); ! 1045: ! 1046: pageOffset = physAddr - trunc_page( physAddr ); ! 1047: ourSize = length + pageOffset; ! 1048: physAddr -= pageOffset; ! 1049: ! 1050: logical = *atAddress; ! 1051: if( 0 == (options & kIOMapAnywhere)) { ! 1052: mapped = trunc_page( logical ); ! 1053: if( (logical - mapped) != pageOffset) ! 1054: err = kIOReturnVMError; ! 1055: } ! 1056: if( kIOReturnSuccess == err) ! 1057: err = vm_allocate( get_task_map(addressTask), &mapped, ourSize, ! 1058: (options & kIOMapAnywhere) ! 1059: ? VM_ALLOCATE_ANYWHERE : VM_ALLOCATE_RESERVED); ! 1060: ! 1061: if( err) { ! 1062: kprintf("IOMemoryDescriptor::doMap: vm_allocate()" ! 1063: " returned %08x\n", err); ! 1064: return( err); ! 1065: } ! 1066: logical = mapped; ! 1067: *atAddress = mapped + pageOffset; ! 1068: ! 1069: segLen += pageOffset; ! 1070: bytes = ourSize; ! 1071: do { ! 1072: // in the middle of the loop only map whole pages ! 1073: if( segLen >= bytes) ! 1074: segLen = bytes; ! 1075: else if( segLen != trunc_page( segLen)) ! 1076: err = kIOReturnVMError; ! 1077: if( physAddr != trunc_page( physAddr)) ! 1078: err = kIOReturnBadArgument; ! 1079: ! 1080: #ifdef DEBUG ! 1081: if( kIOLogMapping & gIOKitDebug) ! 1082: kprintf("_IOMemoryMap::map(%x) %08x->%08x:%08x\n", ! 1083: addressTask, mapped + pageOffset, physAddr + pageOffset, ! 1084: segLen - pageOffset); ! 1085: #endif ! 1086: ! 1087: if( kIOReturnSuccess == err) ! 1088: err = IOMapPages( get_task_map(addressTask), mapped, physAddr, segLen, options ); ! 1089: if( err) ! 1090: break; ! 1091: ! 1092: sourceOffset += segLen - pageOffset; ! 1093: mapped += segLen; ! 1094: bytes -= segLen; ! 1095: pageOffset = 0; ! 1096: ! 1097: } while( bytes ! 1098: && (physAddr = getPhysicalSegment( sourceOffset, &segLen ))); ! 1099: ! 1100: if( bytes) ! 1101: err = kIOReturnBadArgument; ! 1102: if( err) ! 1103: doUnmap( addressTask, logical, ourSize ); ! 1104: else ! 1105: mapped = true; ! 1106: ! 1107: return( err ); ! 1108: } ! 1109: ! 1110: IOReturn IOMemoryDescriptor::doUnmap( ! 1111: task_t addressTask, ! 1112: IOVirtualAddress logical, ! 1113: IOByteCount length ) ! 1114: { ! 1115: IOReturn err; ! 1116: ! 1117: #ifdef DEBUG ! 1118: if( kIOLogMapping & gIOKitDebug) ! 1119: kprintf("IOMemoryDescriptor::doUnmap(%x) %08x:%08x\n", ! 1120: addressTask, logical, length ); ! 1121: #endif ! 1122: err = vm_deallocate( get_task_map(addressTask), logical, length ); ! 1123: assert( err == kIOReturnSuccess ); ! 1124: ! 1125: return( err ); ! 1126: } ! 1127: ! 1128: IOReturn _IOMemoryMap::unmap( void ) ! 1129: { ! 1130: IOReturn err; ! 1131: ! 1132: if( logical && (0 == superMap) ! 1133: && (0 == (options & kIOMapStatic))) { ! 1134: ! 1135: err = memory->doUnmap( addressTask, logical, length ); ! 1136: logical = 0; ! 1137: ! 1138: } else ! 1139: err = kIOReturnSuccess; ! 1140: ! 1141: return( err ); ! 1142: } ! 1143: ! 1144: void _IOMemoryMap::free() ! 1145: { ! 1146: unmap(); ! 1147: ! 1148: if( memory) { ! 1149: LOCK; ! 1150: memory->removeMapping( this); ! 1151: UNLOCK; ! 1152: memory->release(); ! 1153: } ! 1154: ! 1155: if( superMap) ! 1156: superMap->release(); ! 1157: ! 1158: super::free(); ! 1159: } ! 1160: ! 1161: IOByteCount _IOMemoryMap::getLength() ! 1162: { ! 1163: return( length ); ! 1164: } ! 1165: ! 1166: IOVirtualAddress _IOMemoryMap::getVirtualAddress() ! 1167: { ! 1168: return( logical); ! 1169: } ! 1170: ! 1171: task_t _IOMemoryMap::getAddressTask() ! 1172: { ! 1173: return( addressTask); ! 1174: } ! 1175: ! 1176: IOOptionBits _IOMemoryMap::getMapOptions() ! 1177: { ! 1178: return( options); ! 1179: } ! 1180: ! 1181: IOMemoryDescriptor * _IOMemoryMap::getMemoryDescriptor() ! 1182: { ! 1183: return( memory ); ! 1184: } ! 1185: ! 1186: _IOMemoryMap * _IOMemoryMap::isCompatible( ! 1187: IOMemoryDescriptor * owner, ! 1188: task_t task, ! 1189: IOVirtualAddress toAddress, ! 1190: IOOptionBits _options, ! 1191: IOByteCount _offset, ! 1192: IOByteCount _length ) ! 1193: { ! 1194: _IOMemoryMap * mapping; ! 1195: ! 1196: if( addressTask != task) ! 1197: return( 0 ); ! 1198: if( (options ^ _options) & (kIOMapCacheMask | kIOMapReadOnly)) ! 1199: return( 0 ); ! 1200: ! 1201: if( (0 == (_options & kIOMapAnywhere)) && (logical != toAddress)) ! 1202: return( 0 ); ! 1203: ! 1204: if( _offset < offset) ! 1205: return( 0 ); ! 1206: ! 1207: _offset -= offset; ! 1208: ! 1209: if( (_offset + _length) > length) ! 1210: return( 0 ); ! 1211: ! 1212: if( (length == _length) && (!_offset)) { ! 1213: retain(); ! 1214: mapping = this; ! 1215: ! 1216: } else { ! 1217: mapping = new _IOMemoryMap; ! 1218: if( mapping ! 1219: && !mapping->init( owner, this, _offset, _length )) { ! 1220: mapping->release(); ! 1221: mapping = 0; ! 1222: } ! 1223: } ! 1224: ! 1225: return( mapping ); ! 1226: } ! 1227: ! 1228: IOPhysicalAddress _IOMemoryMap::getPhysicalSegment( IOByteCount _offset, ! 1229: IOPhysicalLength * length) ! 1230: { ! 1231: IOPhysicalAddress address; ! 1232: ! 1233: LOCK; ! 1234: address = memory->getPhysicalSegment( offset + _offset, length ); ! 1235: UNLOCK; ! 1236: ! 1237: return( address ); ! 1238: } ! 1239: ! 1240: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 1241: ! 1242: #undef super ! 1243: #define super OSObject ! 1244: ! 1245: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 1246: ! 1247: void IOMemoryDescriptor::initialize( void ) ! 1248: { ! 1249: if( 0 == gIOMemoryLock) ! 1250: gIOMemoryLock = IOLockAlloc(); ! 1251: } ! 1252: ! 1253: void IOMemoryDescriptor::free( void ) ! 1254: { ! 1255: if( _mappings) ! 1256: _mappings->release(); ! 1257: ! 1258: super::free(); ! 1259: } ! 1260: ! 1261: IOMemoryMap * IOMemoryDescriptor::setMapping( ! 1262: task_t intoTask, ! 1263: IOVirtualAddress mapAddress, ! 1264: IOOptionBits options = 0 ) ! 1265: { ! 1266: _IOMemoryMap * map; ! 1267: ! 1268: map = new _IOMemoryMap; ! 1269: ! 1270: LOCK; ! 1271: ! 1272: if( map ! 1273: && !map->init( this, intoTask, mapAddress, ! 1274: options | kIOMapStatic, 0, getLength() )) { ! 1275: map->release(); ! 1276: map = 0; ! 1277: } ! 1278: ! 1279: addMapping( map); ! 1280: ! 1281: UNLOCK; ! 1282: ! 1283: return( map); ! 1284: } ! 1285: ! 1286: IOMemoryMap * IOMemoryDescriptor::map( ! 1287: IOOptionBits options = 0 ) ! 1288: { ! 1289: ! 1290: return( makeMapping( this, kernel_task, 0, ! 1291: options | kIOMapAnywhere, ! 1292: 0, getLength() )); ! 1293: } ! 1294: ! 1295: IOMemoryMap * IOMemoryDescriptor::map( ! 1296: task_t intoTask, ! 1297: IOVirtualAddress toAddress, ! 1298: IOOptionBits options, ! 1299: IOByteCount offset = 0, ! 1300: IOByteCount length = 0 ) ! 1301: { ! 1302: if( 0 == length) ! 1303: length = getLength(); ! 1304: ! 1305: return( makeMapping( this, intoTask, toAddress, options, offset, length )); ! 1306: } ! 1307: ! 1308: IOMemoryMap * IOMemoryDescriptor::makeMapping( ! 1309: IOMemoryDescriptor * owner, ! 1310: task_t intoTask, ! 1311: IOVirtualAddress toAddress, ! 1312: IOOptionBits options, ! 1313: IOByteCount offset, ! 1314: IOByteCount length ) ! 1315: { ! 1316: _IOMemoryMap * mapping = 0; ! 1317: OSIterator * iter; ! 1318: ! 1319: LOCK; ! 1320: ! 1321: do { ! 1322: // look for an existing mapping ! 1323: if( (iter = OSCollectionIterator::withCollection( _mappings))) { ! 1324: ! 1325: while( (mapping = (_IOMemoryMap *) iter->getNextObject())) { ! 1326: ! 1327: if( (mapping = mapping->isCompatible( ! 1328: owner, intoTask, toAddress, ! 1329: options | kIOMapReference, ! 1330: offset, length ))) ! 1331: break; ! 1332: } ! 1333: iter->release(); ! 1334: if( mapping) ! 1335: continue; ! 1336: } ! 1337: ! 1338: ! 1339: if( mapping || (options & kIOMapReference)) ! 1340: continue; ! 1341: ! 1342: owner = this; ! 1343: ! 1344: mapping = new _IOMemoryMap; ! 1345: if( mapping ! 1346: && !mapping->init( owner, intoTask, toAddress, options, ! 1347: offset, length )) { ! 1348: ! 1349: IOLog("Didn't make map %08lx : %08lx\n", offset, length ); ! 1350: mapping->release(); ! 1351: mapping = 0; ! 1352: } ! 1353: ! 1354: } while( false ); ! 1355: ! 1356: owner->addMapping( mapping); ! 1357: ! 1358: UNLOCK; ! 1359: ! 1360: return( mapping); ! 1361: } ! 1362: ! 1363: void IOMemoryDescriptor::addMapping( ! 1364: IOMemoryMap * mapping ) ! 1365: { ! 1366: if( mapping) { ! 1367: if( 0 == _mappings) ! 1368: _mappings = OSSet::withCapacity(1); ! 1369: if( _mappings && _mappings->setObject( mapping )) ! 1370: mapping->release(); /* really */ ! 1371: } ! 1372: } ! 1373: ! 1374: void IOMemoryDescriptor::removeMapping( ! 1375: IOMemoryMap * mapping ) ! 1376: { ! 1377: ! 1378: assert( _mappings ); ! 1379: assert( _mappings->containsObject( mapping ) ); ! 1380: ! 1381: mapping->retain(); ! 1382: mapping->retain(); ! 1383: if( _mappings) ! 1384: _mappings->removeObject( mapping); ! 1385: } ! 1386: ! 1387: // a minimalist serializer ! 1388: bool IOMemoryDescriptor::serialize(OSSerialize *s) const ! 1389: { ! 1390: IOMemoryDescriptor * self = (IOMemoryDescriptor *) this; ! 1391: OSNumber * off; ! 1392: bool ok = false; ! 1393: ! 1394: if( s->previouslySerialized(this)) return true; ! 1395: ! 1396: off = OSNumber::withNumber(self->getPhysicalAddress(), IOPhysSize); ! 1397: if( off) ! 1398: ok = off->serialize(s); ! 1399: if (off) ! 1400: off->release(); ! 1401: ! 1402: return ok; ! 1403: } ! 1404: ! 1405: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 1406: ! 1407: #undef super ! 1408: #define super IOMemoryDescriptor ! 1409: ! 1410: OSDefineMetaClassAndStructors(IOSubMemoryDescriptor, IOMemoryDescriptor) ! 1411: ! 1412: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 1413: ! 1414: bool IOSubMemoryDescriptor::initSubRange( IOMemoryDescriptor * parent, ! 1415: IOByteCount offset, IOByteCount length, ! 1416: IODirection withDirection ) ! 1417: { ! 1418: if( !super::init()) ! 1419: return( false ); ! 1420: ! 1421: if( !parent) ! 1422: return( false); ! 1423: ! 1424: if( (offset + length) > parent->getLength()) ! 1425: return( false); ! 1426: ! 1427: parent->retain(); ! 1428: _parent = parent; ! 1429: _start = offset; ! 1430: _length = length; ! 1431: _direction = withDirection; ! 1432: _tag = parent->getTag(); ! 1433: ! 1434: return( true ); ! 1435: } ! 1436: ! 1437: void IOSubMemoryDescriptor::free( void ) ! 1438: { ! 1439: if( _parent) ! 1440: _parent->release(); ! 1441: ! 1442: super::free(); ! 1443: } ! 1444: ! 1445: ! 1446: IOPhysicalAddress IOSubMemoryDescriptor::getPhysicalSegment( IOByteCount offset, ! 1447: IOByteCount * length ) ! 1448: { ! 1449: IOPhysicalAddress address; ! 1450: IOByteCount actualLength; ! 1451: ! 1452: assert(offset <= _length); ! 1453: ! 1454: if( length) ! 1455: *length = 0; ! 1456: ! 1457: if( offset >= _length) ! 1458: return( 0 ); ! 1459: ! 1460: address = _parent->getPhysicalSegment( offset + _start, &actualLength ); ! 1461: ! 1462: if( address && length) ! 1463: *length = min( _length - offset, actualLength ); ! 1464: ! 1465: return( address ); ! 1466: } ! 1467: ! 1468: void * IOSubMemoryDescriptor::getVirtualSegment(IOByteCount offset, ! 1469: IOByteCount * lengthOfSegment) ! 1470: { ! 1471: return( 0 ); ! 1472: } ! 1473: ! 1474: IOByteCount IOSubMemoryDescriptor::readBytes(IOByteCount offset, ! 1475: void * bytes, IOByteCount withLength) ! 1476: { ! 1477: IOByteCount byteCount; ! 1478: ! 1479: assert(offset <= _length); ! 1480: ! 1481: if( offset >= _length) ! 1482: return( 0 ); ! 1483: ! 1484: LOCK; ! 1485: byteCount = _parent->readBytes( _start + offset, bytes, ! 1486: min(withLength, _length - offset) ); ! 1487: UNLOCK; ! 1488: ! 1489: return( byteCount ); ! 1490: } ! 1491: ! 1492: IOByteCount IOSubMemoryDescriptor::writeBytes(IOByteCount offset, ! 1493: const void* bytes, IOByteCount withLength) ! 1494: { ! 1495: IOByteCount byteCount; ! 1496: ! 1497: assert(offset <= _length); ! 1498: ! 1499: if( offset >= _length) ! 1500: return( 0 ); ! 1501: ! 1502: LOCK; ! 1503: byteCount = _parent->writeBytes( _start + offset, bytes, ! 1504: min(withLength, _length - offset) ); ! 1505: UNLOCK; ! 1506: ! 1507: return( byteCount ); ! 1508: } ! 1509: ! 1510: IOReturn IOSubMemoryDescriptor::prepare( ! 1511: IODirection forDirection = kIODirectionNone) ! 1512: { ! 1513: IOReturn err; ! 1514: ! 1515: LOCK; ! 1516: err = _parent->prepare( forDirection); ! 1517: UNLOCK; ! 1518: ! 1519: return( err ); ! 1520: } ! 1521: ! 1522: IOReturn IOSubMemoryDescriptor::complete( ! 1523: IODirection forDirection = kIODirectionNone) ! 1524: { ! 1525: IOReturn err; ! 1526: ! 1527: LOCK; ! 1528: err = _parent->complete( forDirection); ! 1529: UNLOCK; ! 1530: ! 1531: return( err ); ! 1532: } ! 1533: ! 1534: IOMemoryMap * IOSubMemoryDescriptor::makeMapping( ! 1535: IOMemoryDescriptor * owner, ! 1536: task_t intoTask, ! 1537: IOVirtualAddress toAddress, ! 1538: IOOptionBits options, ! 1539: IOByteCount offset, ! 1540: IOByteCount length ) ! 1541: { ! 1542: IOMemoryMap * mapping; ! 1543: ! 1544: mapping = (IOMemoryMap *) _parent->makeMapping( ! 1545: _parent, intoTask, ! 1546: toAddress - (_start + offset), ! 1547: options | kIOMapReference, ! 1548: _start + offset, length ); ! 1549: ! 1550: if( !mapping) ! 1551: mapping = super::makeMapping( owner, intoTask, toAddress, options, ! 1552: offset, length ); ! 1553: ! 1554: return( mapping ); ! 1555: } ! 1556: ! 1557: /* ick */ ! 1558: ! 1559: bool ! 1560: IOSubMemoryDescriptor::initWithAddress(void * address, ! 1561: IOByteCount withLength, ! 1562: IODirection withDirection) ! 1563: { ! 1564: return( false ); ! 1565: } ! 1566: ! 1567: bool ! 1568: IOSubMemoryDescriptor::initWithAddress(vm_address_t address, ! 1569: IOByteCount withLength, ! 1570: IODirection withDirection, ! 1571: task_t withTask) ! 1572: { ! 1573: return( false ); ! 1574: } ! 1575: ! 1576: bool ! 1577: IOSubMemoryDescriptor::initWithPhysicalAddress( ! 1578: IOPhysicalAddress address, ! 1579: IOByteCount withLength, ! 1580: IODirection withDirection ) ! 1581: { ! 1582: return( false ); ! 1583: } ! 1584: ! 1585: bool ! 1586: IOSubMemoryDescriptor::initWithRanges( ! 1587: IOVirtualRange * ranges, ! 1588: UInt32 withCount, ! 1589: IODirection withDirection, ! 1590: task_t withTask, ! 1591: bool asReference = false) ! 1592: { ! 1593: return( false ); ! 1594: } ! 1595: ! 1596: bool ! 1597: IOSubMemoryDescriptor::initWithPhysicalRanges( IOPhysicalRange * ranges, ! 1598: UInt32 withCount, ! 1599: IODirection withDirection, ! 1600: bool asReference = false) ! 1601: { ! 1602: return( false ); ! 1603: } ! 1604: ! 1605: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.