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 __BEGIN_DECLS 29 void ipc_port_release_send(ipc_port_t port); 30 __END_DECLS 31 32 extern "C" vm_map_t IOPageableMapForAddress( vm_address_t address ); 33 34 #define super IOGeneralMemoryDescriptor 35 OSDefineMetaClassAndStructors(IOBufferMemoryDescriptor, 36 IOGeneralMemoryDescriptor); 37 38 bool IOBufferMemoryDescriptor::initWithAddress( 39 void * /* address */ , 40 IOByteCount /* withLength */ , 41 IODirection /* withDirection */ ) 42 { 43 return false; 44 } 45 46 bool IOBufferMemoryDescriptor::initWithAddress( 47 vm_address_t /* address */ , 48 IOByteCount /* withLength */ , 49 IODirection /* withDirection */ , 50 task_t /* withTask */ ) 51 { 52 return false; 53 } 54 55 bool IOBufferMemoryDescriptor::initWithPhysicalAddress( 56 IOPhysicalAddress /* address */ , 57 IOByteCount /* withLength */ , 58 IODirection /* withDirection */ ) 59 { 60 return false; 61 } 62 63 bool IOBufferMemoryDescriptor::initWithPhysicalRanges( 64 IOPhysicalRange * /* ranges */ , 65 UInt32 /* withCount */ , 66 IODirection /* withDirection */ , 67 bool /* asReference */ ) 68 { 69 return false; 70 } 71 72 bool IOBufferMemoryDescriptor::initWithRanges( 73 IOVirtualRange * /* ranges */ , 74 UInt32 /* withCount */ , 75 IODirection /* withDirection */ , 76 task_t /* withTask */ , 77 bool /* asReference */ ) 78 { 79 return false; 80 } 81 82 bool IOBufferMemoryDescriptor::initWithOptions( 83 IOOptionBits options, 84 vm_size_t capacity, 85 vm_offset_t alignment) 86 { 87 if (!capacity) 88 return false; 89 90 _options = options; 91 _capacity = capacity; 92 _physAddrs = 0; 93 _physSegCount = 0; 94 _buffer = 0; 95 96 if ((options & kIOMemorySharingTypeMask) && (alignment < page_size)) 97 alignment = page_size; 98 99 _alignment = alignment; 100 if (options & kIOMemoryPageable) 101 /* Allocate some kernel address space. */ 102 _buffer = IOMallocPageable(capacity, alignment); 103 /* Allocate a wired-down buffer inside kernel space. */ 104 else if (options & kIOMemoryPhysicallyContiguous) 105 _buffer = IOMallocContiguous(capacity, alignment, 0); 106 else if (alignment > 1) 107 _buffer = IOMallocAligned(capacity, alignment); 108 else 109 _buffer = IOMalloc(capacity); 110 111 if (!_buffer) 112 return false; 113 114 _singleRange.v.address = (vm_address_t) _buffer; 115 _singleRange.v.length = capacity; 116 117 if (!super::initWithRanges(&_singleRange.v, 1, 118 (IODirection) (options & kIOMemoryDirectionMask), 119 kernel_task, true)) 120 return false; 121 122 if (options & kIOMemoryPageable) { 123 _flags |= kIOMemoryRequiresWire; 124 125 kern_return_t kr; 126 ipc_port_t sharedMem = (ipc_port_t) _memEntry; 127 vm_size_t size = round_page(_ranges.v[0].length); 128 129 // must create the entry before any pages are allocated 130 if( 0 == sharedMem) { 131 kr = mach_make_memory_entry( IOPageableMapForAddress( _ranges.v[0].address ), 132 &size, _ranges.v[0].address, 133 VM_PROT_READ | VM_PROT_WRITE, &sharedMem, 134 NULL ); 135 if( (KERN_SUCCESS == kr) && (size != round_page(_ranges.v[0].length))) { 136 ipc_port_release_send( sharedMem ); 137 kr = kIOReturnVMError; 138 } 139 if( KERN_SUCCESS != kr) 140 sharedMem = 0; 141 _memEntry = (void *) sharedMem; 142 } 143 144 } else { 145 /* Precompute virtual-to-physical page mappings. */ 146 vm_address_t inBuffer = (vm_address_t) _buffer; 147 _physSegCount = atop(trunc_page(inBuffer + capacity - 1) - 148 trunc_page(inBuffer)) + 1; 149 _physAddrs = IONew(IOPhysicalAddress, _physSegCount); 150 if (!_physAddrs) 151 return false; 152 153 inBuffer = trunc_page(inBuffer); 154 for (unsigned i = 0; i < _physSegCount; i++) { 155 _physAddrs[i] = pmap_extract(get_task_pmap(kernel_task), inBuffer); 156 assert(_physAddrs[i]); /* supposed to be wired */ 157 inBuffer += page_size; 158 } 159 } 160 161 setLength(capacity); 162 163 return true; 164 } 165 166 IOBufferMemoryDescriptor * IOBufferMemoryDescriptor::withOptions( 167 IOOptionBits options, 168 vm_size_t capacity, 169 vm_offset_t alignment = 1) 170 { 171 IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; 172 173 if (me && !me->initWithOptions(options, capacity, alignment)) { 174 me->release(); 175 me = 0; 176 } 177 return me; 178 } 179 180 181 /* 182 * withCapacity: 183 * 184 * Returns a new IOBufferMemoryDescriptor with a buffer large enough to 185 * hold capacity bytes. The descriptor's length is initially set to the capacity. 186 */ 187 IOBufferMemoryDescriptor * 188 IOBufferMemoryDescriptor::withCapacity(vm_size_t inCapacity, 189 IODirection inDirection, 190 bool inContiguous) 191 { 192 return( IOBufferMemoryDescriptor::withOptions( 193 inDirection | kIOMemoryUnshared 194 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0), 195 inCapacity, inContiguous ? inCapacity : 1 )); 196 } 197 198 /* 199 * initWithBytes: 200 * 201 * Initialize a new IOBufferMemoryDescriptor preloaded with bytes (copied). 202 * The descriptor's length and capacity are set to the input buffer's size. 203 */ 204 bool IOBufferMemoryDescriptor::initWithBytes(const void * inBytes, 205 vm_size_t inLength, 206 IODirection inDirection, 207 bool inContiguous) 208 { 209 if (!initWithOptions( 210 inDirection | kIOMemoryUnshared 211 | (inContiguous ? kIOMemoryPhysicallyContiguous : 0), 212 inLength, inLength )) 213 return false; 214 215 // start out with no data 216 setLength(0); 217 218 if (!appendBytes(inBytes, inLength)) 219 return false; 220 221 return true; 222 } 223 224 /* 225 * withBytes: 226 * 227 * Returns a new IOBufferMemoryDescriptor preloaded with bytes (copied). 228 * The descriptor's length and capacity are set to the input buffer's size. 229 */ 230 IOBufferMemoryDescriptor * 231 IOBufferMemoryDescriptor::withBytes(const void * inBytes, 232 vm_size_t inLength, 233 IODirection inDirection, 234 bool inContiguous) 235 { 236 IOBufferMemoryDescriptor *me = new IOBufferMemoryDescriptor; 237 238 if (me && !me->initWithBytes(inBytes, inLength, inDirection, inContiguous)){ 239 me->release(); 240 me = 0; 241 } 242 return me; 243 } 244 245 /* 246 * free: 247 * 248 * Free resources 249 */ 250 void IOBufferMemoryDescriptor::free() 251 { 252 IOOptionBits options = _options; 253 vm_size_t size = _capacity; 254 void * buffer = _buffer; 255 vm_offset_t alignment = _alignment; 256 257 if (_physAddrs) 258 IODelete(_physAddrs, IOPhysicalAddress, _physSegCount); 259 260 /* super::free may unwire - deallocate buffer afterwards */ 261 super::free(); 262 263 if (buffer) { 264 if (options & kIOMemoryPageable) 265 IOFreePageable(buffer, size); 266 else { 267 if (options & kIOMemoryPhysicallyContiguous) 268 IOFreeContiguous(buffer, size); 269 else if (alignment > 1) 270 IOFreeAligned(buffer, size); 271 else 272 IOFree(buffer, size); 273 } 274 } 275 } 276 277 /* 278 * getCapacity: 279 * 280 * Get the buffer capacity 281 */ 282 vm_size_t IOBufferMemoryDescriptor::getCapacity() const 283 { 284 return _capacity; 285 } 286 287 /* 288 * setLength: 289 * 290 * Change the buffer length of the memory descriptor. When a new buffer 291 * is created, the initial length of the buffer is set to be the same as 292 * the capacity. The length can be adjusted via setLength for a shorter 293 * transfer (there is no need to create more buffer descriptors when you 294 * can reuse an existing one, even for different transfer sizes). Note 295 * that the specified length must not exceed the capacity of the buffer. 296 */ 297 void IOBufferMemoryDescriptor::setLength(vm_size_t length) 298 { 299 assert(length <= _capacity); 300 301 _length = length; 302 _singleRange.v.length = length; 303 } 304 305 /* 306 * setDirection: 307 * 308 * Change the direction of the transfer. This method allows one to redirect 309 * the descriptor's transfer direction. This eliminates the need to destroy 310 * and create new buffers when different transfer directions are needed. 311 */ 312 void IOBufferMemoryDescriptor::setDirection(IODirection direction) 313 { 314 _direction = direction; 315 } 316 317 /* 318 * appendBytes: 319 * 320 * Add some data to the end of the buffer. This method automatically 321 * maintains the memory descriptor buffer length. Note that appendBytes 322 * will not copy past the end of the memory descriptor's current capacity. 323 */ 324 bool 325 IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength) 326 { 327 vm_size_t actualBytesToCopy = min(withLength, _capacity - _length); 328 329 assert(_length <= _capacity); 330 bcopy(/* from */ bytes, (void *)(_singleRange.v.address + _length), 331 actualBytesToCopy); 332 _length += actualBytesToCopy; 333 _singleRange.v.length += actualBytesToCopy; 334 335 return true; 336 } 337 338 /* 339 * getBytesNoCopy: 340 * 341 * Return the virtual address of the beginning of the buffer 342 */ 343 void * IOBufferMemoryDescriptor::getBytesNoCopy() 344 { 345 return (void *)_singleRange.v.address; 346 } 347 348 /* 349 * getBytesNoCopy: 350 * 351 * Return the virtual address of an offset from the beginning of the buffer 352 */ 353 void * 354 IOBufferMemoryDescriptor::getBytesNoCopy(vm_size_t start, vm_size_t withLength) 355 { 356 if (start < _length && (start + withLength) <= _length) 357 return (void *)(_singleRange.v.address + start); 358 return 0; 359 } 360 361 /* 362 * getPhysicalSegment: 363 * 364 * Get the physical address of the buffer, relative to the current position. 365 * If the current position is at the end of the buffer, a zero is returned. 366 */ 367 IOPhysicalAddress 368 IOBufferMemoryDescriptor::getPhysicalSegment(IOByteCount offset, 369 IOByteCount * lengthOfSegment) 370 { 371 IOPhysicalAddress physAddr; 372 373 if( offset != _position) 374 setPosition( offset ); 375 376 assert(_position <= _length); 377 378 /* Fail gracefully if the position is at (or past) the end-of-buffer. */ 379 if (_position >= _length) { 380 *lengthOfSegment = 0; 381 return 0; 382 } 383 384 if (_options & kIOMemoryPageable) { 385 physAddr = super::getPhysicalSegment(offset, lengthOfSegment); 386 387 } else { 388 /* Compute the largest contiguous physical length possible. */ 389 vm_address_t actualPos = _singleRange.v.address + _position; 390 vm_address_t actualPage = trunc_page(actualPos); 391 unsigned physInd = atop(actualPage-trunc_page(_singleRange.v.address)); 392 393 vm_size_t physicalLength = actualPage + page_size - actualPos; 394 for (unsigned index = physInd + 1; index < _physSegCount && 395 _physAddrs[index] == _physAddrs[index-1] + page_size; index++) { 396 physicalLength += page_size; 397 } 398 399 /* Clip contiguous physical length at the end-of-buffer. */ 400 if (physicalLength > _length - _position) 401 physicalLength = _length - _position; 402 403 *lengthOfSegment = physicalLength; 404 physAddr = _physAddrs[physInd] + (actualPos - actualPage); 405 } 406 407 return physAddr; 408 } 409 410 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 0); 411 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 1); 412 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 2); 413 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 3); 414 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 4); 415 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 5); 416 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 6); 417 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 7); 418 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 8); 419 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 9); 420 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 10); 421 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 11); 422 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 12); 423 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 13); 424 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 14); 425 OSMetaClassDefineReservedUnused(IOBufferMemoryDescriptor, 15); 426