1/* 2 * IOFireWireLibNuDCL.cpp 3 * IOFireWireFamily 4 * 5 * Created by Niels on Thu Feb 27 2003. 6 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. 7 * 8 * $ Log:IOFireWireLibNuDCL.cpp,v $ 9 */ 10 11 12#import "IOFireWireLibPriv.h" 13#import "IOFireWireLibNuDCL.h" 14#import "IOFireWireLibNuDCLPool.h" 15#import "IOFireWireLibDevice.h" 16#import "IOFireWireLibCoalesceTree.h" 17#import <System/libkern/OSCrossEndian.h> 18 19namespace IOFireWireLib { 20 21 static IOByteCount 22 findOffsetInRanges ( IOVirtualAddress address, IOVirtualRange ranges[], unsigned rangeCount ) 23 { 24 UInt32 index = 0 ; 25 IOByteCount distanceInRange ; 26 IOByteCount offset = 0 ; 27 28 { 29 bool found = false ; 30 while ( !found && index < rangeCount ) 31 { 32 distanceInRange = address - ranges[index].address ; 33 if ( found = ( distanceInRange < ranges[ index ].length ) ) 34 offset += distanceInRange ; 35 else 36 offset += ranges[ index ].length ; 37 38 ++index ; 39 } 40 } 41 42 return offset ; 43 } 44 45 #undef Class 46 #define Class NuDCL 47 48 NuDCL::NuDCL( NuDCLPool & pool, UInt32 numRanges, IOVirtualRange ranges[], NuDCLSharedData::Type type ) 49 : fData( type ) 50 , fPool( pool ) 51 { 52 if ( numRanges > 6 ) 53 throw kIOReturnBadArgument ; 54 55 // copy passed in ranges to our ranges array 56 bcopy( ranges, fData.ranges, numRanges * sizeof( IOVirtualRange ) ) ; 57 fData.rangeCount = numRanges ; 58 } 59 60 NuDCL::~NuDCL() 61 { 62 } 63 64 IOReturn 65 NuDCL::AppendRanges ( UInt32 numRanges, IOVirtualRange ranges[] ) 66 { 67 if ( fData.rangeCount + numRanges > 6 ) 68 return kIOReturnOverrun ; 69 70 bcopy( ranges, & fData.ranges[ fData.rangeCount ], numRanges * sizeof(IOVirtualRange) ) ; 71 fData.rangeCount += numRanges ; 72 73 return kIOReturnSuccess ; 74 } 75 76 IOReturn 77 NuDCL::SetRanges ( UInt32 numRanges, IOVirtualRange ranges[] ) 78 { 79 fData.rangeCount = numRanges ; 80 bcopy( ranges, fData.ranges, numRanges * sizeof( IOVirtualRange ) ) ; 81 82 return kIOReturnSuccess ; 83 } 84 85 UInt32 86 NuDCL::GetRanges( UInt32 maxRanges, IOVirtualRange ranges[] ) const 87 { 88 unsigned count = MIN( maxRanges, fData.rangeCount ) ; 89 bcopy( fData.ranges, ranges, count * sizeof( IOVirtualRange ) ) ; 90 91 return count ; 92 } 93 94 IOReturn 95 NuDCL::GetSpan( IOVirtualRange& result ) const 96 { 97 if ( fData.rangeCount ) 98 { 99 result.address = fData.ranges[0].address ; 100 IOVirtualAddress end = result.address + fData.ranges[0].length ; 101 102 for( unsigned index=2; index < fData.rangeCount; ++index ) 103 { 104 result.address = MIN( result.address, fData.ranges[index].address ) ; 105 end = MAX( end, fData.ranges[index].address + fData.ranges[index].length ) ; 106 } 107 108 result.length = end - result.address ; 109 } 110 else 111 { 112 result = IOVirtualRangeMake( 0, 0 ) ; 113 } 114 115 return kIOReturnSuccess ; 116 } 117 118 IOByteCount 119 NuDCL::GetSize() const 120 { 121 IOByteCount result = 0 ; 122 123 for( unsigned index=0; index < fData.rangeCount; ++index ) 124 result += fData.ranges[index].length ; 125 126 return result ; 127 } 128 129 IOReturn 130 NuDCL::AppendUpdateList( NuDCL* updateDCL ) 131 { 132 if ( !fData.update.set ) 133 fData.update.set = ::CFSetCreateMutable( kCFAllocatorDefault, 1, nil ) ; 134 135 if ( !fData.update.set ) 136 return kIOReturnNoMemory ; 137 138 ::CFSetSetValue( fData.update.set, updateDCL ) ; 139 140 return kIOReturnSuccess ; 141 } 142 143 IOReturn 144 NuDCL::SetUpdateList( CFSetRef updateList ) 145 { 146 if ( fData.update.set ) 147 ::CFRelease( fData.update.set ) ; 148 149 if ( updateList ) 150 { 151 fData.update.set = ::CFSetCreateMutableCopy( kCFAllocatorDefault, ::CFSetGetCount( updateList ), updateList ) ; 152 153 if ( !fData.update.set ) 154 return kIOReturnNoMemory ; 155 } 156 157 return kIOReturnSuccess ; 158 } 159 160 void 161 NuDCL::EmptyUpdateList() 162 { 163 if ( fData.update.set ) 164 ::CFSetRemoveAllValues( fData.update.set ) ; 165 } 166 167 void 168 NuDCL::Print( FILE* file ) const 169 { 170 if ( fData.rangeCount > 0 ) 171 { 172 fprintf( file, "\t\t\tranges:\n" ) ; 173 for( unsigned index=0; index < fData.rangeCount; ++index ) 174 { 175#ifdef __LP64__ 176 fprintf( file, "\t\t\t\t%u: < %llx, %u >\n", index, fData.ranges[index].address, fData.ranges[index].length ) ; 177#else 178 fprintf( file, "\t\t\t\t%u: < %x, %lu >\n", index, fData.ranges[index].address, fData.ranges[index].length ) ; 179#endif 180 } 181 } 182 if ( fData.branch.dcl ) 183 fprintf( file, "\t\t\tbranch --> %p\n", fData.branch.dcl ) ; 184 if ( fData.callback ) 185 fprintf( file, "\t\t\tcallback @%p\n", fData.callback ) ; 186 if ( fData.timeStamp.ptr ) 187 fprintf( file, "\t\t\ttime stamp %p\n", fData.timeStamp.ptr ) ; 188 if ( fData.update.set ) 189 { 190 CFIndex count = ::CFSetGetCount( fData.update.set ) ; 191 if ( count > 0 ) 192 { 193 fprintf( file, "\t\t\tupdate {" ) ; 194 195 const void* values[ count ] ; 196 ::CFSetGetValues( fData.update.set, values ) ; 197 198 for( CFIndex index=0; index < count; ++index ) 199 fprintf( file, " %p", values[ index ] ) ; 200 201 fprintf( file, " }\n") ; 202 } 203 } 204 if ( fData.status.ptr ) 205 fprintf( file, "\t\t\tstatus ptr %p\n", fData.status.ptr ) ; 206 fprintf( file, "\t\t\trefcon %p\n", fData.refcon ) ; 207 } 208 209 void 210 NuDCL::CoalesceBuffers( CoalesceTree & tree ) const 211 { 212 for( unsigned index=0; index < fData.rangeCount; ++index ) 213 { 214 tree.CoalesceRange( fData.ranges[ index ] ) ; 215 } 216 217 if ( fData.timeStamp.ptr ) 218 { 219 tree.CoalesceRange( IOVirtualRangeMake( (IOVirtualAddress) fData.timeStamp.ptr, sizeof( *fData.timeStamp.ptr ) ) ) ; 220 } 221 222 if ( fData.status.ptr ) 223 { 224 tree.CoalesceRange( IOVirtualRangeMake( (IOVirtualAddress) fData.status.ptr, sizeof( *fData.status.ptr ) ) ) ; 225 } 226 } 227 228 IOByteCount 229 NuDCL::Export ( 230 IOVirtualAddress * where, 231 IOVirtualRange bufferRanges[], 232 unsigned bufferRangeCount ) const 233 { 234 235 if (where) 236 { 237 unsigned updateSetCount = 0 ; 238 NuDCLExportData * exportedData = reinterpret_cast<NuDCLExportData *>( *where ) ; 239 *where += sizeof( NuDCLExportData ); 240 241 exportedData->type = (UInt32) fData.type; 242 exportedData->refcon = (mach_vm_address_t) fData.refcon; 243 exportedData->flags = fData.flags; 244 exportedData->callback = (mach_vm_address_t) fData.callback; 245 246 // export buffer ranges 247 exportedData->rangeCount = fData.rangeCount; 248 for( unsigned index=0; index < exportedData->rangeCount; ++index ) 249 { 250 exportedData->ranges[ index ].address = findOffsetInRanges( fData.ranges[ index ].address, bufferRanges, bufferRangeCount ) ; 251 exportedData->ranges[ index ].length = fData.ranges[ index ].length; 252 } 253 254 // export update list 255 uint64_t * exportList = NULL ; 256 if( fData.update.set ) 257 { 258 259 updateSetCount = ::CFSetGetCount( fData.update.set ) ; 260 exportList = reinterpret_cast<uint64_t *>( *where ) ; 261 *where += sizeof( uint64_t) * updateSetCount ; 262 263 264 // We need to read the values out of the CFSet and into a buffer. 265 // For 64-bit mode, we just read directly into the export buffer. 266 // For 32-bit mode, we offset half way into the list portion of the export buffer as a temporary storage space 267#ifdef __LP64__ 268 uint64_t *pDCLUpdateSetPointers = exportList; 269#else 270 UInt32 *pDCLUpdateSetPointers = (UInt32 *) &exportList[updateSetCount/2]; 271#endif 272 273 // copy contents of update list to export data as array of NuDCL* 274 ::CFSetGetValues( fData.update.set, reinterpret_cast<const void **>( pDCLUpdateSetPointers ) ) ; 275 276 // for each NuDCL* in update list in export data, change NuDCL* to corresponding NuDCL's fData->exportIndex 277 // field value 278 for( unsigned index=0; index < updateSetCount; ++index ) 279 { 280 exportList[ index ] = ((NuDCL*)pDCLUpdateSetPointers[ index ])->GetExportIndex() ; 281 } 282 283 // stuff update list field in exported data with number of DCLs in update list 284 exportedData->updateCount = updateSetCount ; 285 } 286 287 // export user timestamp 288 if ( fData.timeStamp.ptr ) 289 exportedData->timeStampOffset = findOffsetInRanges( (IOVirtualAddress)fData.timeStamp.ptr, bufferRanges, bufferRangeCount ) + 1 ; 290 else 291 exportedData->timeStampOffset = 0; 292 293 // export user status field 294 if ( fData.status.ptr ) 295 exportedData->statusOffset = findOffsetInRanges( (IOVirtualAddress)fData.status.ptr, bufferRanges, bufferRangeCount ) + 1 ; 296 else 297 exportedData->statusOffset = 0; 298 299 // export branch 300 exportedData->branchIndex = fData.branch.dcl ? fData.branch.dcl->GetExportIndex() : 0 ; 301 302#ifndef __LP64__ 303 ROSETTA_ONLY( 304 { 305 for( unsigned index=0; index < exportedData->rangeCount; ++index ) 306 { 307 exportedData->ranges[ index ].address = CFSwapInt64( exportedData->ranges[ index ].address ) ; 308 exportedData->ranges[ index ].length = CFSwapInt64( exportedData->ranges[ index ].length ) ; 309 } 310 311 for( unsigned index=0; index < updateSetCount; ++index ) 312 { 313 exportList[ index ] = CFSwapInt64( exportList[ index ] ) ; 314 } 315 exportedData->updateCount = CFSwapInt64( exportedData->updateCount ) ; 316 exportedData->timeStampOffset = CFSwapInt64( exportedData->timeStampOffset ) ; 317 exportedData->statusOffset = CFSwapInt64( exportedData->statusOffset ) ; 318 exportedData->type = (NuDCLSharedData::Type)CFSwapInt32( exportedData->type ) ; 319 exportedData->callback = (mach_vm_address_t)CFSwapInt64(exportedData->callback ) ; 320 exportedData->refcon = (mach_vm_address_t)CFSwapInt64(exportedData->refcon) ; 321 exportedData->flags = CFSwapInt32( exportedData->flags | BIT(19) ) ; 322 exportedData->rangeCount = CFSwapInt32( exportedData->rangeCount ) ; 323 exportedData->branchIndex = CFSwapInt64( exportedData->branchIndex ) ; 324 } 325 ) ; 326#endif 327 } 328 329 return sizeof( NuDCLExportData ) + ( fData.update.set ? ::CFSetGetCount( fData.update.set ) * sizeof( uint64_t ) : 0 ) ; 330 } 331 332#pragma mark - 333 334 #undef super 335 #define super NuDCL 336 337 ReceiveNuDCL::ReceiveNuDCL( NuDCLPool & pool, UInt8 headerBytes, UInt32 numRanges, IOVirtualRange ranges[] ) 338 : NuDCL( pool, numRanges, ranges, NuDCLSharedData::kReceiveType ), 339 fReceiveData() 340 { 341 fReceiveData.headerBytes = headerBytes ; 342 } 343 344 IOReturn 345 ReceiveNuDCL::SetWaitControl ( bool wait ) 346 { 347 fReceiveData.wait = wait ; 348 349 return kIOReturnSuccess ; 350 } 351 352 void 353 ReceiveNuDCL::Print( FILE* file ) const 354 { 355 fprintf( file, "\tRCV %p\thdr bytes=%d, wait=%s", this, fReceiveData.headerBytes, fReceiveData.wait ? "YES" : "NO" ) ; 356 if ( fReceiveData.wait ) 357 fprintf( file, " (wait)" ) ; 358 fprintf( file, "\n" ) ; 359 360 super::Print( file ) ; 361 } 362 363 IOByteCount 364 ReceiveNuDCL::Export ( 365 IOVirtualAddress * where, 366 IOVirtualRange bufferRanges[], 367 unsigned bufferRangeCount ) const 368 { 369 IOByteCount size = NuDCL::Export( where, bufferRanges, bufferRangeCount ) ; 370 371 if ( where ) 372 { 373 ReceiveNuDCLExportData * exportedData = reinterpret_cast<ReceiveNuDCLExportData *>( *where ) ; 374 *where += sizeof( ReceiveNuDCLExportData ); 375 376 exportedData->headerBytes = fReceiveData.headerBytes; 377 exportedData->wait = fReceiveData.wait; 378 } 379 380 return size + sizeof( ReceiveNuDCLExportData ); 381 } 382 383 384#pragma mark - 385 386 #undef super 387 #define super NuDCL 388 389 SendNuDCL::SendNuDCL( NuDCLPool & pool, UInt32 numRanges, IOVirtualRange ranges[] ) 390 : NuDCL( pool, numRanges, ranges, NuDCLSharedData::kSendType ) 391 , fSendData() 392 { 393 } 394 395 void 396 SendNuDCL::Print( FILE* file ) const 397 { 398 fprintf( file, "\tSEND %p\thdr=", this ) ; 399 if ( fSendData.userHeader.ptr ) 400 { 401 fprintf( file, "user @ %p, mask @ %p\n", fSendData.userHeader.ptr, fSendData.userHeaderMask.ptr ) ; 402 } 403 else 404 { 405 fprintf( file, "auto\n" ) ; 406 } 407 408 if ( fSendData.skipBranch.dcl ) 409 { 410 fprintf( file, "\t\t\tskip --> %p\n", fSendData.skipBranch.dcl ) ; 411 } 412 413 if ( fSendData.skipCallback ) 414 { 415 fprintf( file, "\t\t\tskip callback:%p refcon:%p\n", fSendData.skipCallback, fSendData.skipRefcon ) ; 416 } 417 418 super::Print( file ) ; 419 } 420 421 IOByteCount 422 SendNuDCL::Export ( 423 IOVirtualAddress * where, 424 IOVirtualRange bufferRanges[], 425 unsigned bufferRangeCount ) const 426 { 427 IOByteCount size = NuDCL::Export( where, bufferRanges, bufferRangeCount ) ; 428 429 if ( where ) 430 { 431 SendNuDCLExportData * exportedData = reinterpret_cast<SendNuDCLExportData *>( *where ) ; 432 *where += sizeof(SendNuDCLExportData); 433 434 exportedData->tagBits = fSendData.tagBits; 435 exportedData->syncBits = fSendData.syncBits; 436 exportedData->skipCallback = (mach_vm_address_t)fSendData.skipCallback; 437 exportedData->skipRefcon = (mach_vm_address_t)fSendData.skipRefcon; 438 439 if ( fSendData.skipBranch.dcl ) 440 exportedData->skipBranchIndex = fSendData.skipBranch.dcl->GetExportIndex() ; 441 else 442 exportedData->skipBranchIndex = 0 ; 443 444 if ( fSendData.userHeader.ptr ) 445 exportedData->userHeaderOffset = findOffsetInRanges( (IOVirtualAddress)fSendData.userHeader.ptr, bufferRanges, bufferRangeCount ) + 1 ; 446 else 447 exportedData->userHeaderOffset = 0; 448 449 if ( fSendData.userHeaderMask.ptr ) 450 exportedData->userHeaderMaskOffset = findOffsetInRanges( (IOVirtualAddress)fSendData.userHeaderMask.ptr, bufferRanges, bufferRangeCount ) + 1; 451 else 452 exportedData->userHeaderMaskOffset = 0; 453 454#ifndef __LP64__ 455 ROSETTA_ONLY( 456 { 457 exportedData->skipBranchIndex = CFSwapInt64( exportedData->skipBranchIndex ) ; 458 exportedData->skipCallback = (mach_vm_address_t)CFSwapInt64(exportedData->skipCallback ) ; 459 exportedData->skipRefcon = (mach_vm_address_t)CFSwapInt64( (UInt32)exportedData->skipRefcon ) ; 460 exportedData->userHeaderOffset = CFSwapInt64( exportedData->userHeaderOffset ) ; 461 exportedData->userHeaderMaskOffset = CFSwapInt64( exportedData->userHeaderMaskOffset ) ; 462 } 463 ) ; 464#endif 465 466 } 467 468 return size + sizeof( SendNuDCLExportData ); 469 } 470 471#pragma mark - 472 473 #undef super 474 #define super NuDCL 475 476 void 477 SkipCycleNuDCL::Print( FILE* file ) const 478 { 479 fprintf( file, "\tSKIP %p\n", this ) ; 480 481 super::Print( file ) ; 482 } 483 484} // namespace 485