IOFWUserIsochPort.cpp [plain text]
#import <IOKit/firewire/IOFireWireDevice.h>
#import <IOKit/firewire/IOFireWireController.h>
#import <IOKit/firewire/IOFWLocalIsochPort.h>
#import <IOKit/firewire/IOFWDCLTranslator.h>
#import <IOKit/firewire/IOFWDCLPool.h>
#import <IOKit/firewire/IOFWDCL.h>
#import <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOKitKeysPrivate.h>
#include <IOKit/IODMACommand.h>
#import <IOKit/firewire/IOFireWireLink.h>
#import "IOFireWireUserClient.h"
#import "IOFWUserIsochPort.h"
#if 0
class DebugThing
{
public :
io_user_reference_t * asyncRef ;
IOFWUserLocalIsochPort * port;
} ;
#endif
extern bool findOffsetInRanges ( mach_vm_address_t address, unsigned rangeCount, IOAddressRange ranges[], IOByteCount & outOffset ) ;
static bool
getDCLDataBuffer(
const UserExportDCLCommand *dcl,
mach_vm_address_t & outDataBuffer,
mach_vm_size_t & outDataLength )
{
Boolean result = false ;
switch ( dcl->opcode & ~kFWDCLOpFlagMask )
{
case kDCLSendPacketStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
outDataBuffer = ( (UserExportDCLTransferPacket*)dcl )->buffer ;
outDataLength = ( (UserExportDCLTransferPacket *)dcl )->size ;
result = true ;
break ;
case kDCLPtrTimeStampOp:
outDataBuffer = ( (UserExportDCLPtrTimeStamp *) dcl )->timeStampPtr ;
outDataLength = sizeof ( mach_vm_address_t ) ;
result = true ;
break ;
default:
break ;
}
return result ;
}
static void
setDCLDataBuffer (
DCLCommand* inDCL,
mach_vm_address_t inDataBuffer,
mach_vm_size_t inDataLength )
{
switch(inDCL->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
((DCLTransferPacket*)inDCL)->buffer = (void*) inDataBuffer ;
((DCLTransferPacket*)inDCL)->size = inDataLength ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
break ;
case kDCLPtrTimeStampOp:
((DCLPtrTimeStamp*)inDCL)->timeStampPtr = (UInt32*)inDataBuffer ;
break ;
default:
break ;
}
}
static IOByteCount
getDCLSize ( UserExportDCLCommand* dcl )
{
IOByteCount result = 0 ;
switch(dcl->opcode & ~kFWDCLOpFlagMask)
{
case kDCLSendPacketStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
result = sizeof(UserExportDCLTransferPacket) ;
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
result = sizeof(UserExportDCLTransferBuffer) ;
break ;
case kDCLCallProcOp:
result = sizeof(UserExportDCLCallProc) ;
break ;
case kDCLLabelOp:
result = sizeof(UserExportDCLLabel) ;
break ;
case kDCLJumpOp:
result = sizeof(UserExportDCLJump) ;
break ;
case kDCLSetTagSyncBitsOp:
result = sizeof(UserExportDCLSetTagSyncBits) ;
break ;
case kDCLUpdateDCLListOp:
result = sizeof(UserExportDCLUpdateDCLList) ;
break ;
case kDCLPtrTimeStampOp:
result = sizeof(UserExportDCLPtrTimeStamp) ;
break;
case kDCLSkipCycleOp:
result = sizeof(UserExportDCLCommand) ;
break;
}
return result ;
}
#pragma mark -
#undef super
#define super IOFWLocalIsochPort
OSDefineMetaClassAndStructors ( IOFWUserLocalIsochPort, super )
#if 0
{}
#endif
#if IOFIREWIREDEBUG > 0
bool
IOFWUserLocalIsochPort::serialize( OSSerialize * s ) const
{
const OSString * keys[ 1 ] =
{
OSString::withCString( "program" )
} ;
const OSObject * objects[ 1 ] =
{
fProgram ? (const OSObject*)fProgram : (const OSObject*)OSString::withCString( "(null)" )
} ;
OSDictionary * dict = OSDictionary::withObjects( objects, keys, sizeof( keys )/sizeof( OSObject* ) ) ;
if ( !dict )
return false ;
bool result = dict->serialize( s ) ;
dict->release() ;
return result ;
}
#endif // IOFIREWIREDEBUG > 0
void
IOFWUserLocalIsochPort::free()
{
if ( fDCLPool )
{
fDCLPool->release() ;
fDCLPool = NULL ;
}
delete [] (UInt8*)fProgramBuffer ;
fProgramBuffer = NULL ;
if ( fLock )
{
IORecursiveLockFree( fLock ) ;
}
delete[] fDCLTable ;
fDCLTable = NULL ;
super::free() ;
}
#if 0
IOReturn checkMemoryInRange( IOMemoryDescriptor * memory, UInt64 mask )
{
IOReturn status = kIOReturnSuccess;
if( memory == NULL )
{
status = kIOReturnBadArgument;
}
bool memory_prepared = false;
if( status == kIOReturnSuccess )
{
status = memory->prepare( kIODirectionInOut );
}
if( status == kIOReturnSuccess )
{
memory_prepared = true;
}
UInt64 length = 0;
IODMACommand * dma_command = NULL;
if( status == kIOReturnSuccess )
{
length = memory->getLength();
dma_command = IODMACommand::withSpecification(
kIODMACommandOutputHost64, 64, length, IODMACommand::kMapped | IODMACommand::kIterateOnly, length, 0, NULL, NULL ); if( dma_command == NULL )
status = kIOReturnError;
}
if( status == kIOReturnSuccess )
{
status = dma_command->setMemoryDescriptor( memory, false );
}
bool dma_command_prepared = false;
if( status == kIOReturnSuccess )
{
status = dma_command->prepare( 0, length, true );
}
if( status == kIOReturnSuccess )
{
dma_command_prepared = true;
}
if( status == kIOReturnSuccess )
{
UInt64 offset = 0;
while( (offset < length) && (status == kIOReturnSuccess) )
{
IODMACommand::Segment64 segments[10];
UInt32 num_segments = 10;
status = dma_command->gen64IOVMSegments( &offset, segments, &num_segments );
if( status == kIOReturnSuccess )
{
for( UInt32 i = 0; i < num_segments; i++ )
{
if( (segments[i].fIOVMAddr & (~mask)) )
{
IOLog( "checkSegmentsFailed - 0x%016llx & 0x%016llx\n", segments[i].fIOVMAddr, mask );
status = kIOReturnNotPermitted;
break;
}
}
}
}
}
if( dma_command_prepared )
{
dma_command->complete();
dma_command_prepared = false;
}
if( dma_command )
{
dma_command->clearMemoryDescriptor();
dma_command->release();
dma_command = NULL;
}
if( memory_prepared )
{
memory->complete();
memory_prepared = false;
}
return status;
}
#endif
bool
IOFWUserLocalIsochPort::initWithUserDCLProgram (
AllocateParams * params,
IOFireWireUserClient & userclient,
IOFireWireController & controller )
{
if ( params->programExportBytes == 0 )
{
ErrorLog ( "No program!" ) ;
return false ;
}
fLock = IORecursiveLockAlloc () ;
if ( ! fLock )
{
ErrorLog ( "Couldn't allocate recursive lock\n" ) ;
return false ;
}
fUserObj = params->userObj ;
fUserClient = & userclient ;
fDCLPool = NULL ;
fProgramCount = 0;
fStarted = false ;
IOReturn error = kIOReturnSuccess ;
IOAddressRange * bufferRanges = new IOAddressRange[ params->bufferRangeCount ] ;
if ( !bufferRanges )
{
error = kIOReturnNoMemory ;
}
if ( !error )
{
error = fUserClient->copyUserData(params->bufferRanges,(mach_vm_address_t)bufferRanges, sizeof ( IOAddressRange ) * params->bufferRangeCount ) ;
}
IOMemoryDescriptor * bufferDesc = NULL ;
if ( ! error )
{
IOByteCount length = 0 ;
for ( unsigned index = 0; index < params->bufferRangeCount; ++index )
{
length += bufferRanges[ index ].length ;
}
bufferDesc = IOMemoryDescriptor::withAddressRanges ( bufferRanges, params->bufferRangeCount, kIODirectionOutIn,
fUserClient->getOwningTask() ) ;
if ( ! bufferDesc )
{
error = kIOReturnNoMemory ;
}
else
{
error = bufferDesc->prepare( kIODirectionPrepareToPhys32 ) ;
FWTrace( kFWTIsoch, kTPIsochPortUserInitWithUserDCLProgram, (uintptr_t)(fUserClient->getOwner()->getController()->getLink()), error, length, 0 );
}
}
IOMemoryMap * bufferMap = NULL ;
if ( !error )
{
bufferMap = bufferDesc->map() ;
if ( !bufferMap )
{
DebugLog( "Couldn't map program buffers\n" ) ;
error = kIOReturnVMError ;
}
bufferDesc->release() ;
}
IOMemoryDescriptor * userProgramExportDesc = NULL ;
if ( !error )
{
userProgramExportDesc = IOMemoryDescriptor::withAddressRange(
params->programData,
params->programExportBytes,
kIODirectionOut,
fUserClient->getOwningTask() ) ;
}
if ( userProgramExportDesc )
{
error = userProgramExportDesc->prepare() ;
}
if ( !error )
{
DCLCommand * opcodes = NULL ;
switch ( params->version )
{
case kDCLExportDataLegacyVersion :
error = importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
ErrorLogCond( error, "importUserProgram returned %x\n", error ) ;
if ( ! error )
{
opcodes = (DCLCommand*)fProgramBuffer ;
}
break ;
case kDCLExportDataNuDCLRosettaVersion :
fDCLPool = fUserClient->getOwner()->getBus()->createDCLPool() ;
if ( ! fDCLPool )
{
error = kIOReturnNoMemory ;
}
if ( !error )
{
error = fDCLPool->importUserProgram( userProgramExportDesc, params->bufferRangeCount, bufferRanges, bufferMap ) ;
}
fProgramBuffer = new UInt8[ sizeof( DCLNuDCLLeader ) ] ;
{
DCLNuDCLLeader * leader = (DCLNuDCLLeader*)fProgramBuffer ;
{
leader->pNextDCLCommand = NULL ; leader->opcode = kDCLNuDCLLeaderOp ;
leader->program = fDCLPool ;
}
opcodes = (DCLCommand*)leader ;
}
break ;
default :
ErrorLog ( "unsupported DCL program type\n" ) ;
error = kIOReturnBadArgument ;
break ;
}
ErrorLogCond( !opcodes, "Couldn't get opcodes\n" ) ;
IODCLProgram * program = NULL ;
if ( opcodes )
{
IOFireWireBus::DCLTaskInfoAux infoAux ;
{
infoAux.version = 2 ;
infoAux.u.v2.bufferMemoryMap = bufferMap ;
infoAux.u.v2.workloop = params->options & kFWIsochPortUseSeparateKernelThread ? createRealtimeThread() : NULL ;
infoAux.u.v2.options = (IOFWIsochPortOptions)params->options ;
}
IOFireWireBus::DCLTaskInfo info = { 0, 0, 0, 0, 0, 0, & infoAux } ;
program = fUserClient->getOwner()->getController()->getLink()->createDCLProgram( params->talking,
opcodes,
& info,
params->startEvent,
params->startState,
params->startMask ) ;
bufferMap->release() ; bufferMap = NULL ;
if ( infoAux.u.v2.workloop )
{
infoAux.u.v2.workloop->release() ;
}
DebugLogCond( !program, "createDCLProgram returned nil\n" ) ;
}
if ( program )
{
if ( ! super::init( program, & controller ) )
{
ErrorLog ( "IOFWUserIsochPort::init failed\n" ) ;
error = kIOReturnError ;
}
}
else
{
DebugLog ( "Couldn't create DCL program\n" ) ;
error = kIOReturnNoMemory ;
}
userProgramExportDesc->complete() ;
userProgramExportDesc->release() ;
userProgramExportDesc = NULL ;
}
delete [] bufferRanges ;
InfoLog( "-IOFWUserLocalIsochPort::initWithUserDCLProgram error=%x (build date "__TIME__" "__DATE__")\n", error ) ;
return ( ! error ) ;
}
IOReturn
IOFWUserLocalIsochPort::importUserProgram (
IOMemoryDescriptor * userExportDesc,
unsigned userBufferRangeCount,
IOAddressRange userBufferRanges[],
IOMemoryMap * bufferMap )
{
IOReturn error = kIOReturnSuccess ;
UInt8 *pUserImportProgramBuffer;
if ( ! error )
{
pUserImportProgramBuffer = new UInt8[ userExportDesc->getLength() ] ;
if ( !pUserImportProgramBuffer )
{
error = kIOReturnNoMemory ;
}
}
if ( !error )
{
unsigned byteCount = userExportDesc->readBytes( 0, (void*)pUserImportProgramBuffer, userExportDesc->getLength() ) ;
if ( byteCount < userExportDesc->getLength() )
{
error = kIOReturnVMError ;
}
}
if ( ! error )
{
fProgramBuffer = new UInt8[ userExportDesc->getLength() ] ;
if ( !fProgramBuffer )
{
error = kIOReturnNoMemory ;
}
}
DCLCommand *pCurrentDCL;
UserExportDCLCommand *pExportDCL;
UInt32 nextUserExportDCLOffset = 0;
DCLCommand *pLastDCL = NULL;
unsigned size;
do
{
pExportDCL = (UserExportDCLCommand*)(pUserImportProgramBuffer + nextUserExportDCLOffset);
pCurrentDCL = (DCLCommand*)(fProgramBuffer + nextUserExportDCLOffset);
UInt32 opcode = pExportDCL->opcode & ~kFWDCLOpFlagMask;
if ( opcode > 15 && opcode != 20 )
{
DebugLog("found invalid DCL in export data\n") ;
error = kIOFireWireBogusDCLProgram ;
break ;
}
size = getDCLSize( pExportDCL ) ;
if (pLastDCL != NULL)
pLastDCL->pNextDCLCommand = pCurrentDCL;
pLastDCL = pCurrentDCL;
switch ( opcode )
{
case kDCLSendPacketStartOp:
case kDCLSendPacketOp:
case kDCLReceivePacketStartOp:
case kDCLReceivePacketOp:
{
DCLTransferPacket *pDCLTransferPacket = (DCLTransferPacket*) pCurrentDCL;
pDCLTransferPacket->opcode = pExportDCL->opcode;
pDCLTransferPacket->compilerData = 0;
}
break ;
case kDCLSendBufferOp:
case kDCLReceiveBufferOp:
{
DCLTransferBuffer *pDCLTransferBuffer = (DCLTransferBuffer*) pCurrentDCL;
pDCLTransferBuffer->opcode = pExportDCL->opcode;
pDCLTransferBuffer->compilerData = 0;
pDCLTransferBuffer->packetSize = ((UserExportDCLTransferBuffer*)pExportDCL)->packetSize;
pDCLTransferBuffer->reserved = ((UserExportDCLTransferBuffer*)pExportDCL)->reserved;
pDCLTransferBuffer->bufferOffset = ((UserExportDCLTransferBuffer*)pExportDCL)->bufferOffset;
}
break ;
case kDCLCallProcOp:
{
DCLCallProc *pDCLCallProc = (DCLCallProc*) pCurrentDCL;
pDCLCallProc->opcode = pExportDCL->opcode;
pDCLCallProc->compilerData = 0;
size += sizeof( uint64_t[kOSAsyncRef64Count] ) ;
error = convertToKernelDCL( ((UserExportDCLCallProc*)pExportDCL), pDCLCallProc ) ;
}
break ;
case kDCLLabelOp:
{
DCLLabel *pDCLLabel = (DCLLabel*) pCurrentDCL;
pDCLLabel->opcode = pExportDCL->opcode;
pDCLLabel->compilerData = 0;
}
break ;
case kDCLJumpOp:
{
DCLJump *pDCLJump = (DCLJump*) pCurrentDCL;
pDCLJump->opcode = pExportDCL->opcode;
pDCLJump->compilerData = 0;
error = convertToKernelDCL( ((UserExportDCLJump*)pExportDCL), pDCLJump ) ;
}
break ;
case kDCLSetTagSyncBitsOp:
{
DCLSetTagSyncBits *pDCLSetTagSyncBits = (DCLSetTagSyncBits*) pCurrentDCL;
pDCLSetTagSyncBits->opcode = pExportDCL->opcode;
pDCLSetTagSyncBits->compilerData = 0;
pDCLSetTagSyncBits->tagBits = ((UserExportDCLSetTagSyncBits*)pExportDCL)->tagBits;
pDCLSetTagSyncBits->syncBits = ((UserExportDCLSetTagSyncBits*)pExportDCL)->syncBits;
}
break ;
case kDCLUpdateDCLListOp:
{
DCLUpdateDCLList *pDCLUpdateDCLList = (DCLUpdateDCLList*) pCurrentDCL;
pDCLUpdateDCLList->opcode = pExportDCL->opcode;
pDCLUpdateDCLList->compilerData = 0;
pDCLUpdateDCLList->numDCLCommands = ((UserExportDCLUpdateDCLList*)pExportDCL)->numDCLCommands;
size += sizeof( mach_vm_address_t ) * ((UserExportDCLUpdateDCLList*)pExportDCL)->numDCLCommands ;
error = convertToKernelDCL( ((UserExportDCLUpdateDCLList*)pExportDCL), pDCLUpdateDCLList ) ;
}
break ;
case kDCLPtrTimeStampOp:
{
DCLPtrTimeStamp *pDCLPtrTimeStamp = (DCLPtrTimeStamp*) pCurrentDCL;
pDCLPtrTimeStamp->opcode = pExportDCL->opcode;
pDCLPtrTimeStamp->compilerData = 0;
}
break ;
case kDCLSkipCycleOp:
{
DCLCommand *pDCLCommand = (DCLCommand*) pCurrentDCL;
pDCLCommand->opcode = pExportDCL->opcode;
pDCLCommand->compilerData = 0;
pDCLCommand->operands[0] = ((UserExportDCLCommand*)pExportDCL)->operands[0];
}
break ;
}
if (error)
break;
IOAddressRange tempRange ;
tempRange.address = 0; tempRange.length = 0; if ( getDCLDataBuffer ( pExportDCL, tempRange.address, tempRange.length ) )
{
if ( tempRange.address != NULL && tempRange.length > 0 )
{
IOByteCount offset ;
if ( ! findOffsetInRanges ( tempRange.address, userBufferRangeCount, userBufferRanges, offset ) )
{
DebugLog( "IOFWUserLocalIsochPort::initWithUserDCLProgram: couldn't find DCL data buffer in buffer ranges") ;
error = kIOReturnError;
break;
}
setDCLDataBuffer ( pCurrentDCL, bufferMap->getVirtualAddress() + offset, tempRange.length ) ;
}
}
++fProgramCount ;
if (pExportDCL->pNextDCLCommand == NULL)
break;
else
nextUserExportDCLOffset += size;
if (nextUserExportDCLOffset >= userExportDesc->getLength())
{
error = kIOReturnError;
break;
}
}while(1);
if ( ! error )
{
pLastDCL->pNextDCLCommand = NULL;
fDCLTable = new DCLCommand*[ fProgramCount ] ;
InfoLog( "made DCL table, %d entries\n", fProgramCount ) ;
if ( !fDCLTable )
error = kIOReturnNoMemory ;
if ( !error )
{
unsigned index = 0 ;
for( DCLCommand * dcl = (DCLCommand*)fProgramBuffer; dcl != NULL; dcl = dcl->pNextDCLCommand )
{
if ( index >= fProgramCount )
panic("dcl table out of bounds\n") ;
fDCLTable[ index++ ] = dcl ;
}
}
}
if (pUserImportProgramBuffer)
delete [] pUserImportProgramBuffer;
return error ;
}
#if 0
IOReturn
IOFWUserLocalIsochPort::releasePort ()
{
return super::releasePort () ;
}
#endif
IOReturn
IOFWUserLocalIsochPort::start()
{
IOReturn error = super::start() ;
fStarted = (!error) ;
return error ;
}
IOReturn
IOFWUserLocalIsochPort::stop()
{
IOReturn error ;
error = super::stop() ;
if ( fStarted )
{
error = IOFireWireUserClient::sendAsyncResult64( fStopTokenAsyncRef, kIOFireWireLastDCLToken, NULL, 0 ) ;
fStarted = false ;
}
return error ;
}
void
IOFWUserLocalIsochPort::s_dclCallProcHandler( DCLCallProc * dcl )
{
#if 0
#if IOFIREWIREUSERCLIENTDEBUG > 0
IOFWUserLocalIsochPort * me = (IOFWUserLocalIsochPort *) holder->obj ;
DebugLog("+IOFWUserLocalIsochPort::s_dclCallProcHandler, holder=%p, (holder->asyncRef)[0]=0x%x\n", holder, (holder->asyncRef)[0]) ;
me->fUserClient->getStatistics()->getIsochCallbackCounter()->addValue( 1 ) ;
#endif
#endif
if ( dcl->procData )
{
#if 0
DebugThing * debugThing = (DebugThing*)dcl->procData ;
IOFireWireUserClient::sendAsyncResult64( (io_user_reference_t*)debugThing->asyncRef, kIOReturnSuccess, NULL, 0 ) ;
DebugLog("send callback port=%p\n", debugThing->port ) ;
#else
IOFireWireUserClient::sendAsyncResult64( (io_user_reference_t *)dcl->procData, kIOReturnSuccess, NULL, 0 ) ;
#endif
}
}
void
IOFWUserLocalIsochPort::s_nuDCLCallout( void * refcon )
{
io_user_reference_t * asyncRef = (io_user_reference_t *)refcon ;
IOFireWireUserClient::sendAsyncResult64( asyncRef, kIOReturnSuccess, NULL, 0 ) ;
}
IOReturn
IOFWUserLocalIsochPort::setAsyncRef_DCLCallProc( OSAsyncReference64 asyncRef )
{
bcopy( asyncRef, fStopTokenAsyncRef, sizeof( OSAsyncReference64 ) ) ;
if ( fDCLPool )
{
const OSArray * program = fDCLPool->getProgramRef() ;
for( unsigned index = 0, count = program->getCount(); index < count; ++index )
{
IOFWDCL * dcl = reinterpret_cast< IOFWDCL * >( program->getObject( index ) ) ;
if ( dcl->getCallback() )
{
io_user_reference_t * dclAsyncRef = (io_user_reference_t*)dcl->getRefcon() ;
if ( asyncRef )
{
bcopy( asyncRef, dclAsyncRef, sizeof( io_user_reference_t ) * kIOAsyncReservedCount ) ;
}
}
}
program->release() ;
}
else
{
for( unsigned index=0; index < fProgramCount; ++index )
{
DCLCommand * dcl = fDCLTable[ index ] ;
if ( ( dcl->opcode & ~kFWDCLOpFlagMask ) == kDCLCallProcOp )
{
#if 0
if ( ((DCLCallProc*)dcl)->proc && ((DCLCallProc*)dcl)->procData )
{
((DebugThing*)((DCLCallProc*)dcl)->procData)->asyncRef[0] = asyncRef[0] ;
}
#else
{
((io_user_reference_t*)((DCLCallProc*)dcl)->procData)[ 0 ] = asyncRef[ 0 ] ;
}
#endif
}
dcl = dcl->pNextDCLCommand ;
}
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort::modifyJumpDCL ( UInt32 inJumpDCLCompilerData, UInt32 inLabelDCLCompilerData)
{
if ( !fProgram )
{
ErrorLog("no program!\n") ;
return kIOReturnError ;
}
--inJumpDCLCompilerData ;
--inLabelDCLCompilerData ;
if ( inJumpDCLCompilerData > fProgramCount || inLabelDCLCompilerData > fProgramCount )
{
DebugLog( "IOFWUserLocalIsochPort::modifyJumpDCL: DCL index (inJumpDCLCompilerData=%u, inLabelDCLCompilerData=%u) past end of lookup table (length=%u)\n",
(uint32_t)inJumpDCLCompilerData,
(uint32_t)inLabelDCLCompilerData,
fProgramCount ) ;
return kIOReturnBadArgument ;
}
DCLJump * jumpDCL = (DCLJump *) fDCLTable[ inJumpDCLCompilerData ] ;
DCLLabel * labelDCL = (DCLLabel *) fDCLTable[ inLabelDCLCompilerData ] ;
if ( ( jumpDCL->opcode & ~kFWDCLOpFlagMask ) != kDCLJumpOp || ( labelDCL->opcode & ~kFWDCLOpFlagMask ) != kDCLLabelOp )
{
DebugLog("IOFWUserLocalIsochPort::modifyJumpDCL: modifying non-jump (%p, %d) or pointing jump to non-label (%p, %d)\n", jumpDCL, (int)inJumpDCLCompilerData, jumpDCL->pJumpDCLLabel, (int)inLabelDCLCompilerData ) ;
return kIOReturnBadArgument ;
}
jumpDCL->pJumpDCLLabel = labelDCL ;
fProgram->closeGate() ;
IOReturn error = notify ( kFWDCLModifyNotification, (DCLCommand**) & jumpDCL, 1 ) ;
fProgram->openGate() ;
return error ;
}
IOReturn
IOFWUserLocalIsochPort::modifyDCLSize ( UInt32 dclCompilerData, IOByteCount newSize )
{
return kIOReturnUnsupported ;
#if 0
--dclCompilerData ;
if ( dclCompilerData > fUserToKernelDCLLookupTableLength )
{
DebugLog("IOFWUserLocalIsochPort::modifyJumpDCLSize: DCL index (dclCompilerData=%lu) past end of lookup table (length=%lu)\n",
dclCompilerData, fUserToKernelDCLLookupTableLength ) ;
return kIOReturnBadArgument ;
}
DCLTransferPacket* dcl = (DCLTransferPacket*)( fUserToKernelDCLLookupTable[ dclCompilerData ] ) ;
IOReturn result = kIOReturnSuccess ;
lock() ;
if (fPort)
result = ((IOFWLocalIsochPort*)fPort)->notify(kFWDCLModifyNotification, (DCLCommand**)&dcl, 1) ;
unlock() ;
return result ;
#endif
}
IOReturn
IOFWUserLocalIsochPort::convertToKernelDCL (UserExportDCLUpdateDCLList *pUserExportDCL, DCLUpdateDCLList *dcl)
{
UInt8 *pListAddress = (UInt8 *)pUserExportDCL;
pListAddress += sizeof(UserExportDCLUpdateDCLList);
mach_vm_address_t *pExportListItem = (mach_vm_address_t*)pListAddress;
dcl->dclCommandList = (DCLCommand**)(dcl + 1) ;
for( unsigned index = 0 ; index < dcl->numDCLCommands; ++index )
{
dcl->dclCommandList[ index ] = (DCLCommand*)( fProgramBuffer + pExportListItem[index]) ;
{
unsigned opcode = dcl->dclCommandList[ index ]->opcode & ~kFWDCLOpFlagMask ;
if ( opcode > 15 && opcode != 20 )
{
panic("invalid opcode\n") ;
}
}
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort::convertToKernelDCL (UserExportDCLJump *pUserExportDCL, DCLJump *dcl )
{
dcl->pJumpDCLLabel = (DCLLabel*)( fProgramBuffer + (UInt32)pUserExportDCL->pJumpDCLLabel ) ;
if ( ( dcl->pJumpDCLLabel->opcode & ~kFWDCLOpFlagMask ) != kDCLLabelOp )
{
dcl->pJumpDCLLabel = NULL ;
DebugLog( "Jump %p pointing to non-label %p\n", dcl, dcl->pJumpDCLLabel ) ;
}
return kIOReturnSuccess ;
}
IOReturn
IOFWUserLocalIsochPort::convertToKernelDCL (UserExportDCLCallProc *pUserExportDCL, DCLCallProc * dcl)
{
io_user_reference_t * asyncRef = (io_user_reference_t *)(dcl + 1 ) ;
asyncRef[0] = 0 ;
asyncRef[ kIOAsyncCalloutFuncIndex ] = (mach_vm_address_t)pUserExportDCL->proc ;
asyncRef[ kIOAsyncCalloutRefconIndex ] = (io_user_reference_t)pUserExportDCL->procData ;
dcl->proc = (DCLCallCommandProc*) & s_dclCallProcHandler ;
dcl->procData = (DCLCallProcDataType) asyncRef ;
#if 0
DebugThing * debugThing = new DebugThing ;
dcl->procData = debugThing ;
debugThing->asyncRef = asyncRef ;
debugThing->port = this ;
#else
dcl->procData = (DCLCallProcDataType) asyncRef ;
#endif
return kIOReturnSuccess ;
}
void
IOFWUserLocalIsochPort::exporterCleanup( const OSObject * self )
{
IOFWUserLocalIsochPort * me = (IOFWUserLocalIsochPort*)self;
me->stop() ;
me->releasePort() ;
}
IOReturn
IOFWUserLocalIsochPort::userNotify (
UInt32 notificationType,
UInt32 numDCLs,
void * data,
IOByteCount dataSize )
{
InfoLog("+IOFWUserLocalIsochPort::userNotify, numDCLs=%ld\n", numDCLs ) ;
if ( __builtin_expect( numDCLs > 64, false ) )
{
return kIOReturnBadArgument ;
}
IOFWDCL * dcls[ numDCLs ] ;
const OSArray * program = fDCLPool->getProgramRef() ;
unsigned programLength = program->getCount() ;
IOReturn error = kIOReturnSuccess ;
switch( (IOFWDCLNotificationType)notificationType )
{
case kFWNuDCLModifyNotification :
{
IOMemoryMap * bufferMap = fProgram->getBufferMap() ;
for( unsigned index=0; index < numDCLs; ++index )
{
unsigned dclIndex = *(unsigned*)data - 1 ;
if ( dclIndex >= programLength )
{
DebugLog("out of range DCL dclIndex=%d, programLength=%d\n", dclIndex, programLength ) ;
error = kIOReturnBadArgument ;
}
else
{
dcls[ index ] = (IOFWDCL*)program->getObject( dclIndex ) ;
data = (UInt8*)data + sizeof( unsigned ) ;
IOByteCount dataSize ;
error = dcls[ index ]->importUserDCL( (UInt8*)data, dataSize, bufferMap, program ) ;
if ( dclIndex + 1 < programLength && !dcls[ index ]->getBranch() )
{
dcls[ index ]->setBranch( (IOFWDCL*)program->getObject( dclIndex + 1 ) ) ;
}
data = (UInt8*)data + dataSize ;
}
if ( error )
{
break ;
}
}
break ;
}
case kFWNuDCLModifyJumpNotification :
{
unsigned * dclIndexTable = (unsigned*)data ;
{
unsigned index = 0 ;
unsigned pairIndex = 0 ;
while( pairIndex < numDCLs )
{
--dclIndexTable[ index ] ;
if ( dclIndexTable[ index ] >= programLength )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndexTable[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ pairIndex ] = (IOFWDCL*)program->getObject( dclIndexTable[ index ] ) ;
++index ;
if (dclIndexTable[ index ])
{
--dclIndexTable[ index ] ;
if ( dclIndexTable[ index ] >= programLength )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndexTable[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ pairIndex ]->setBranch( (IOFWDCL*)program->getObject( dclIndexTable[ index ] ) ) ;
}
else
{
dcls[ pairIndex ]->setBranch( 0 ) ;
}
++index ;
++pairIndex ;
}
}
break ;
}
case kFWNuDCLUpdateNotification :
{
unsigned index = 0 ;
while ( index < numDCLs )
{
unsigned * dclIndices = (unsigned*)data ;
--dclIndices[ index ] ;
if ( __builtin_expect( dclIndices[ index ] >= programLength, false ) )
{
DebugLog("out of range DCL index=%d, dclIndices[ index ]=%d, programLength=%d\n", index, dclIndices[ index ], programLength ) ;
error = kIOReturnBadArgument ;
break ;
}
dcls[ index ] = (IOFWDCL*)program->getObject( dclIndices[ index ] ) ;
++index ;
}
break ;
}
default:
{
error = kIOReturnBadArgument ;
DebugLog("unsupported notification type 0x%08x\n", (uint32_t)notificationType) ;
break ;
}
}
program->release() ;
return error ? error : notify( (IOFWDCLNotificationType)notificationType, (DCLCommand**)dcls, numDCLs ) ;
}
IOWorkLoop *
IOFWUserLocalIsochPort::createRealtimeThread()
{
IOWorkLoop * workloop = IOWorkLoop::workLoop() ;
if ( workloop )
{
thread_time_constraint_policy_data_t constraints;
AbsoluteTime time;
nanoseconds_to_absolutetime(625000, &time);
constraints.period = AbsoluteTime_to_scalar(&time);
nanoseconds_to_absolutetime(60000, &time);
constraints.computation = AbsoluteTime_to_scalar(&time);
nanoseconds_to_absolutetime(1250000, &time);
constraints.constraint = AbsoluteTime_to_scalar(&time);
constraints.preemptible = TRUE;
{
IOThread thread;
thread = workloop->getThread();
thread_policy_set( thread, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) & constraints, THREAD_TIME_CONSTRAINT_POLICY_COUNT );
}
}
return workloop ;
}