|
|
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: #include <IOKit/assert.h> ! 23: #include <IOKit/system.h> ! 24: ! 25: #include <IOKit/IOLib.h> ! 26: #include <IOKit/IOBufferMemoryDescriptor.h> ! 27: ! 28: #define super IOGeneralMemoryDescriptor ! 29: OSDefineMetaClassAndStructors(IOBufferMemoryDescriptor, ! 30: IOGeneralMemoryDescriptor); ! 31: ! 32: /* ! 33: * initWithCapacity: ! 34: * ! 35: * Initialize a new IOBufferMemoryDescriptor with a buffer large enough to ! 36: * hold capacity bytes. The descriptor's length is initially set to zero. ! 37: */ ! 38: bool IOBufferMemoryDescriptor::initWithCapacity(vm_size_t inCapacity, ! 39: IODirection inDirection, ! 40: bool inContiguous) ! 41: { ! 42: if (!inCapacity) ! 43: return false; ! 44: ! 45: /* Allocate a wired-down buffer inside kernel space. */ ! 46: _buffer = (inContiguous) ? ! 47: IOMallocContiguous(inCapacity, inCapacity, 0) : ! 48: IOMalloc(inCapacity); ! 49: _contiguous = inContiguous; ! 50: _capacity = inCapacity; ! 51: _physAddrs = 0; ! 52: _physSegCount = 0; ! 53: ! 54: if (!_buffer) ! 55: return false; ! 56: ! 57: if (!super::initWithAddress(_buffer, inCapacity, inDirection)) ! 58: return false; ! 59: ! 60: /* Precompute virtual-to-physical page mappings. */ ! 61: vm_address_t inBuffer = (vm_address_t) _buffer; ! 62: _physSegCount = atop(trunc_page(inBuffer + inCapacity - 1) - ! 63: trunc_page(inBuffer)) + 1; ! 64: _physAddrs = IONew(IOPhysicalAddress, _physSegCount); ! 65: if (!_physAddrs) ! 66: return false; ! 67: ! 68: inBuffer = trunc_page(inBuffer); ! 69: for (unsigned i = 0; i < _physSegCount; i++) { ! 70: _physAddrs[i] = pmap_extract(get_task_pmap(kernel_task), inBuffer); ! 71: assert(_physAddrs[i]); /* supposed to be wired */ ! 72: inBuffer += page_size; ! 73: } ! 74: ! 75: // start out with no data ! 76: setLength(0); ! 77: ! 78: return true; ! 79: } ! 80: ! 81: /* ! 82: * withCapacity: ! 83: * ! 84: * Returns a new IOBufferMemoryDescriptor with a buffer large enough to ! 85: * hold capacity bytes. The descriptor's length is initially set to zero. ! 86: */ ! 87: IOBufferMemoryDescriptor * ! 88: IOBufferMemoryDescriptor::withCapacity(vm_size_t inCapacity, ! 89: IODirection inDirection, ! 90: bool inContiguous) ! 91: { ! 92: IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; ! 93: ! 94: if (me && !me->initWithCapacity(inCapacity, inDirection, inContiguous)) { ! 95: me->release(); ! 96: me = 0; ! 97: } ! 98: return me; ! 99: } ! 100: ! 101: /* ! 102: * initWithBytes: ! 103: * ! 104: * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied). ! 105: * The descriptor's length and capacity are set to the input buffer's size. ! 106: */ ! 107: bool IOBufferMemoryDescriptor::initWithBytes(const void * inBytes, ! 108: vm_size_t inLength, ! 109: IODirection inDirection, ! 110: bool inContiguous) ! 111: { ! 112: if (!initWithCapacity(inLength, inDirection, inContiguous)) ! 113: return false; ! 114: ! 115: if (!appendBytes(inBytes, inLength)) ! 116: return false; ! 117: ! 118: return true; ! 119: } ! 120: ! 121: /* ! 122: * withBytes: ! 123: * ! 124: * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied). ! 125: * The descriptor's length and capacity are set to the input buffer's size. ! 126: */ ! 127: IOBufferMemoryDescriptor * ! 128: IOBufferMemoryDescriptor::withBytes(const void * inBytes, ! 129: vm_size_t inLength, ! 130: IODirection inDirection, ! 131: bool inContiguous) ! 132: { ! 133: IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; ! 134: ! 135: if (me && !me->initWithBytes(inBytes, inLength, inDirection, inContiguous)){ ! 136: me->release(); ! 137: me = 0; ! 138: } ! 139: return me; ! 140: } ! 141: ! 142: /* ! 143: * free: ! 144: * ! 145: * Free resources ! 146: */ ! 147: void IOBufferMemoryDescriptor::free() ! 148: { ! 149: if (_physAddrs) ! 150: IODelete(_physAddrs, IOPhysicalAddress, _physSegCount); ! 151: ! 152: super::free(); ! 153: ! 154: if (_buffer) { ! 155: if (_contiguous) ! 156: IOFreeContiguous(_buffer, _capacity); ! 157: else ! 158: IOFree(_buffer, _capacity); ! 159: } ! 160: } ! 161: ! 162: /* ! 163: * getCapacity: ! 164: * ! 165: * Get the buffer capacity ! 166: */ ! 167: vm_size_t IOBufferMemoryDescriptor::getCapacity() const ! 168: { ! 169: return _capacity; ! 170: } ! 171: ! 172: /* ! 173: * setLength: ! 174: * ! 175: * Change the buffer length of the memory descriptor. When a new buffer is ! 176: * created with initWithBytes, the descriptor's length is set to capacity, ! 177: * or its length is initially zero. This method allows one to resize the ! 178: * buffer length up to capacity or less. This eliminates the need to ! 179: * destroy and create new buffers when different sizes are needed. The ! 180: * descriptor position is implicitly reset to zero as a result of this call. ! 181: */ ! 182: void IOBufferMemoryDescriptor::setLength(vm_size_t length) ! 183: { ! 184: assert(length <= _capacity); ! 185: ! 186: _length = length; ! 187: _singleRange.v.length = length; ! 188: } ! 189: ! 190: /* ! 191: * setDirection: ! 192: * ! 193: * Change the direction of the transfer. This method allows one to redirect ! 194: * the descriptor's transfer direction. This eliminates the need to destroy ! 195: * and create new buffers when different transfer directions are needed. ! 196: */ ! 197: void IOBufferMemoryDescriptor::setDirection(IODirection direction) ! 198: { ! 199: _direction = direction; ! 200: } ! 201: ! 202: /* ! 203: * appendBytes: ! 204: * ! 205: * Add some data to the end of the buffer. This method automatically ! 206: * maintains the memory descriptor buffer length. Note that appendBytes ! 207: * will not copy past the end of the memory descriptor's current capacity. ! 208: */ ! 209: bool ! 210: IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength) ! 211: { ! 212: vm_size_t actualBytesToCopy = min(withLength, _capacity - _length); ! 213: ! 214: assert(_length <= _capacity); ! 215: bcopy(/* from */ bytes, (void *)(_singleRange.v.address + _length), ! 216: actualBytesToCopy); ! 217: _length += actualBytesToCopy; ! 218: _singleRange.v.length += actualBytesToCopy; ! 219: ! 220: return true; ! 221: } ! 222: ! 223: /* ! 224: * getBytesNoCopy: ! 225: * ! 226: * Return the virtual address of the beginning of the buffer ! 227: */ ! 228: void * IOBufferMemoryDescriptor::getBytesNoCopy() ! 229: { ! 230: return (void *)_singleRange.v.address; ! 231: } ! 232: ! 233: /* ! 234: * getBytesNoCopy: ! 235: * ! 236: * Return the virtual address of an offset from the beginning of the buffer ! 237: */ ! 238: void * ! 239: IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength) ! 240: { ! 241: if (start < _length && (start + withLength) <= _length) ! 242: return (void *)(_singleRange.v.address + start); ! 243: return 0; ! 244: } ! 245: ! 246: /* ! 247: * getPhysicalSegment: ! 248: * ! 249: * Get the physical address of the buffer, relative to the current position. ! 250: * If the current position is at the end of the buffer, a zero is returned. ! 251: */ ! 252: IOPhysicalAddress ! 253: IOBufferMemoryDescriptor::getPhysicalSegment(IOByteCount offset, ! 254: IOPhysicalLength * lengthOfSegment) ! 255: { ! 256: if( offset != _position) ! 257: setPosition( offset ); ! 258: ! 259: assert(_position <= _length); ! 260: ! 261: /* Fail gracefully if the position is at (or past) the end-of-buffer. */ ! 262: if (_position >= _length) { ! 263: *lengthOfSegment = 0; ! 264: return 0; ! 265: } ! 266: ! 267: /* Compute the largest contiguous physical length possible. */ ! 268: vm_address_t actualPos = _singleRange.v.address + _position; ! 269: vm_address_t actualPage = trunc_page(actualPos); ! 270: unsigned physInd = atop(actualPage-trunc_page(_singleRange.v.address)); ! 271: ! 272: vm_size_t physicalLength = actualPage + page_size - actualPos; ! 273: for (unsigned index = physInd + 1; index < _physSegCount && ! 274: _physAddrs[index] == _physAddrs[index-1] + page_size; index++) { ! 275: physicalLength += page_size; ! 276: } ! 277: ! 278: /* Clip contiguous physical length at the end-of-buffer. */ ! 279: if (physicalLength > _length - _position) ! 280: physicalLength = _length - _position; ! 281: ! 282: *lengthOfSegment = physicalLength; ! 283: return _physAddrs[physInd] + (actualPos - actualPage); ! 284: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.