#if FIRELOGCORE
#include "IOFireLogPriv.h"
void FireLog( const char *format, ... )
{
IOFireLog * firelog;
va_list ap;
va_start(ap, format);
firelog = IOFireLog::getFireLog();
if( firelog )
firelog->logString( format, ap );
va_end(ap);
}
#endif
#if FIRELOGCORE
extern "C" {
#include <kern/clock.h>
}
#define kFireLogVersionKey 0x19 // arbitrary
#define kFireLogSizeKey 0x1a // arbitrary
#define kFireLogAddressHiKey 0x1b // arbitrary
#define kFireLogAddressLoKey 0x1c // arbitrary
#define kFireLogRandomIDKey 0x1d // arbitrary
#define kFireLogMaxEntrySizeKey 0x1e // arbitrary
#define kFireLogTempBufferSize 255
OSObject * IOFireLog::sFireLog = NULL;
int IOFireLog::sTempBufferIndex = 0;
char IOFireLog::sTempBuffer[kFireLogTempBufferSize];
OSDefineMetaClassAndStructors(IOFireLog, OSObject)
IOReturn IOFireLog::create( void )
{
IOReturn status = kIOReturnSuccess;
IOFireLog * firelog;
if( status == kIOReturnSuccess )
{
firelog = new IOFireLog;
if( firelog == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = firelog->initialize();
}
if( status == kIOReturnSuccess )
{
Boolean result = false;
while( sFireLog == NULL && result == false )
{
result = OSCompareAndSwap( NULL, (UInt32)firelog, (UInt32*)&sFireLog );
}
if( result == false )
{
firelog->release();
}
else if( sFireLog != NULL ) {
IOLog( "Welcome to FireLog. (built %s %s)\n", __TIME__, __DATE__ );
FireLog( "Welcome to FireLog. (built %s %s)\n", __TIME__, __DATE__ );
}
}
return status;
}
IOReturn IOFireLog::initialize( void )
{
IOReturn status = kIOReturnSuccess;
AbsoluteTime time;
if( kFireLogSize & 0x00000003 ) panic( "FireLog : illegal log size 0x%08lx\n", kFireLogSize );
fLogSize = kFireLogSize + sizeof(FireLogHeader);
clock_get_uptime(&time);
fRandomID = time.lo;
fRandomID &= 0x00ffffff;
fController = NULL;
fLogDescriptor = IOBufferMemoryDescriptor::withCapacity( fLogSize, kIODirectionOutIn, true );
if( fLogDescriptor == NULL )
status = kIOReturnNoMemory;
if( status == kIOReturnSuccess )
{
fLogDescriptor->setLength( fLogSize );
IOPhysicalLength lengthOfSegment = 0;
IOPhysicalAddress phys = fLogDescriptor->getPhysicalSegment( 0, &lengthOfSegment );
if( lengthOfSegment != 0 )
{
fLogPhysicalAddress = phys;
IOLog( "FireLog : physical address = 0x%08lx, length = %ld\n", (UInt32)fLogPhysicalAddress, lengthOfSegment );
}
else
{
status = kIOReturnNoMemory;
}
}
if( status == kIOReturnSuccess )
{
fLogBuffer = (FireLogHeader*)fLogDescriptor->getBytesNoCopy();
fLogStart = ((char*)fLogBuffer) + sizeof(FireLogHeader);
fLogEnd = fLogStart + kFireLogSize;
bzero( fLogBuffer, fLogSize );
fNeedSpace = false;
fLogBuffer->start = 0;
fLogBuffer->end = 0;
}
if( status == kIOReturnSuccess )
{
fLock = IOLockAlloc();
if( fLock == NULL )
status = kIOReturnError;
}
return status;
}
void IOFireLog::free( void )
{
if( fLogDescriptor )
{
fLogDescriptor->release();
fLogDescriptor = NULL;
}
if( fLock != NULL )
{
IOLockFree( fLock );
fLock = NULL;
}
OSObject::free();
}
IOFireWireController * IOFireLog::getMainController( void )
{
return fController;
}
void IOFireLog::setMainController( IOFireWireController * controller )
{
IOLockLock( fLock );
if( fController == NULL )
fController = controller;
if( controller == NULL )
fController = NULL;
IOLockUnlock( fLock );
}
IOPhysicalAddress IOFireLog::getLogPhysicalAddress( void )
{
return fLogPhysicalAddress;
}
UInt32 IOFireLog::getLogSize( void )
{
return fLogSize;
}
UInt32 IOFireLog::getRandomID( void )
{
return fRandomID;
}
void IOFireLog::firelog_putc( char c )
{
sTempBuffer[sTempBufferIndex] = c;
sTempBufferIndex++;
}
IOFireLog * IOFireLog::getFireLog( void )
{
if( sFireLog == NULL )
IOFireLog::create();
return (IOFireLog*)sFireLog;
}
void IOFireLog::logString( const char *format, va_list ap )
{
UInt32 cycleTime;
AbsoluteTime absolute_time;
uint64_t time;
UInt32 new_encoded_end;
UInt32 new_encoded_start;
UInt32 length;
UInt32 str_length;
char * data_ptr;
char * length_ptr;
bool controllerExists = false;
if( fController )
{
controllerExists = true;
}
if( controllerExists )
{
fController->closeGate();
}
IOLockLock( fLock );
if( controllerExists )
fController->getCycleTime(cycleTime);
else
cycleTime = 0;
clock_get_uptime( &absolute_time );
absolutetime_to_nanoseconds( absolute_time, &time );
sTempBufferIndex = 0;
bzero( sTempBuffer, kFireLogTempBufferSize );
_doprnt(format, &ap, IOFireLog::firelog_putc, 16);
str_length = strlen(sTempBuffer) + 1;
length = ((( sizeof(uint64_t) +
sizeof(UInt32) +
str_length +
sizeof(UInt32)) +
3) & (~0x00000003));
{
char * min_new_start;
char * cur_new_start;
new_encoded_end = fLogBuffer->end;
length_ptr = encodedToLogical( new_encoded_end );
if( length_ptr + length < fLogEnd )
{
new_encoded_end += sizeToEncoded( sizeof(UInt32) );
data_ptr = length_ptr + sizeof(UInt32);
}
else
{
new_encoded_end += sizeToEncoded( fLogEnd - length_ptr );
data_ptr = fLogStart;
}
new_encoded_start = fLogBuffer->start;
cur_new_start = encodedToLogical( new_encoded_start );
if( data_ptr < length_ptr )
{
if( fNeedSpace )
{
if( cur_new_start > length_ptr )
{
while( true )
{
UInt32 entry_length = *((UInt32*)cur_new_start);
if( cur_new_start + entry_length < fLogEnd )
{
new_encoded_start += sizeToEncoded( entry_length );
cur_new_start += entry_length;
}
else
{
new_encoded_start += sizeToEncoded( fLogEnd - cur_new_start + entry_length - sizeof(UInt32) );
cur_new_start = fLogStart + entry_length - sizeof(UInt32);
break;
}
}
}
}
else
{
fNeedSpace = true;
}
}
if( fNeedSpace )
{
min_new_start = data_ptr + length;
if( !((cur_new_start < length_ptr) && (data_ptr > length_ptr)) )
{
while( cur_new_start < min_new_start )
{
UInt32 entry_length = *((UInt32*)cur_new_start);
if( cur_new_start + entry_length < fLogEnd )
{
new_encoded_start += sizeToEncoded( entry_length );
cur_new_start += entry_length;
}
else
{
new_encoded_start += sizeToEncoded( fLogEnd - cur_new_start + entry_length - sizeof(UInt32) );
cur_new_start = fLogStart + entry_length - sizeof(UInt32);
break;
}
}
}
fLogBuffer->start = new_encoded_start;
}
}
*((uint64_t*)data_ptr) = time;
data_ptr += sizeof(uint64_t);
*((UInt32*)data_ptr) = cycleTime;
data_ptr += sizeof(UInt32);
bcopy( sTempBuffer, data_ptr, str_length );
data_ptr += ((str_length+3) & ~0x00000003);
*((UInt32*)data_ptr) = 0;
*((UInt32*)length_ptr) = length;
new_encoded_end += sizeToEncoded( length - sizeof( UInt32 ) );
fLogBuffer->end = new_encoded_end;
IOLockUnlock( fLock );
if( controllerExists )
{
fController->openGate();
}
}
OSDefineMetaClassAndStructors(IOFireLogPublisher, OSObject)
IOFireLogPublisher * IOFireLogPublisher::create( IOFireWireController * controller )
{
IOReturn status = kIOReturnSuccess;
IOFireLogPublisher * firelogPublisher;
if( status == kIOReturnSuccess )
{
firelogPublisher = new IOFireLogPublisher;
if( firelogPublisher == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = firelogPublisher->initWithController( controller );
}
if( status != kIOReturnSuccess )
{
firelogPublisher = NULL;
}
else
{
FireLog( "IOFireWireController @ 0x%08lx created new IOFireLogPublisher @ 0x%08lx\n", (UInt32)controller, (UInt32)firelogPublisher );
}
return firelogPublisher;
}
IOReturn IOFireLogPublisher::initWithController( IOFireWireController* controller )
{
IOReturn status = kIOReturnSuccess;
IOPhysicalAddress log_physical_address;
UInt32 log_size = 0;
UInt32 log_random_id = 0;
if( status == kIOReturnSuccess )
{
fController = controller;
fController->retain();
fFireLog = IOFireLog::getFireLog();
if( fFireLog == NULL )
status = kIOReturnNoMemory;
else
fFireLog->retain();
}
IORegistryEntry* parent = controller->getParentEntry( gIOServicePlane ); parent = parent->getParentEntry( gIOServicePlane );
UInt32 vendor_id = 0;
{
OSData * vendor_id_data;
UInt32 * vendor_id_ptr = NULL;
vendor_id_data = (OSData*)parent->getProperty( "vendor-id" );
if( vendor_id_data != NULL )
vendor_id_ptr = (UInt32*)vendor_id_data->getBytesNoCopy();
if( vendor_id_ptr != NULL)
vendor_id = *vendor_id_ptr;
}
UInt32 subsystem_id = 0;
{
OSData * subsystem_id_data;
UInt32 * subsystem_id_ptr = NULL;
subsystem_id_data = (OSData*)parent->getProperty( "subsystem-id" );
if( subsystem_id_data != NULL )
subsystem_id_ptr = (UInt32*)subsystem_id_data->getBytesNoCopy();
if( subsystem_id_ptr != NULL)
subsystem_id = *subsystem_id_ptr;
}
UInt32 subsystem_vendor_id = 0;
{
OSData * subsystem_vendor_id_data;
UInt32 * subsystem_vendor_id_ptr = NULL;
subsystem_vendor_id_data = (OSData*)parent->getProperty( "subsystem-vendor-id" );
if( subsystem_vendor_id_data != NULL )
subsystem_vendor_id_ptr = (UInt32*)subsystem_vendor_id_data->getBytesNoCopy();
if( subsystem_vendor_id_ptr != NULL)
subsystem_vendor_id = *subsystem_vendor_id_ptr;
}
if( vendor_id == 0x106b )
{
fFireLog->setMainController( fController );
}
else if ( subsystem_vendor_id == 0x106b )
{
fFireLog->setMainController( fController );
}
else if( subsystem_vendor_id == 0x11c1 )
{
fFireLog->setMainController( fController );
}
else if ( vendor_id == 0x104c )
{
fFireLog->setMainController( fController );
}
else if ( subsystem_id == 0 && subsystem_vendor_id == 0 )
{
fFireLog->setMainController( fController );
}
if( status == kIOReturnSuccess )
{
log_physical_address = fFireLog->getLogPhysicalAddress();
log_size = fFireLog->getLogSize();
log_random_id = fFireLog->getRandomID();
}
if( status == kIOReturnSuccess )
{
fUnitDir = IOLocalConfigDirectory::create();
if( fUnitDir == NULL)
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fUnitDir->addEntry(kConfigUnitSpecIdKey, (UInt32)0x27);
fUnitDir->addEntry(kConfigUnitSwVersionKey, (UInt32)0x1);
fUnitDir->addEntry(kFireLogVersionKey, (UInt32)3 );
fUnitDir->addEntry(kFireLogSizeKey, log_size );
fUnitDir->addEntry(kFireLogAddressHiKey, (UInt32)(log_physical_address >> 16) );
fUnitDir->addEntry(kFireLogAddressLoKey, (UInt32)(log_physical_address & 0x0000FFFF) );
fUnitDir->addEntry(kFireLogRandomIDKey, (UInt32)(log_random_id & 0x00FFFFFF) );
fUnitDir->addEntry(kFireLogMaxEntrySizeKey, (UInt32)( sizeof(uint64_t) + sizeof(UInt32) + kFireLogTempBufferSize + sizeof(UInt32)) );
}
if( status == kIOReturnSuccess )
{
fController->AddUnitDirectory( fUnitDir );
}
if( status == kIOReturnSuccess )
{
fLogDescriptor = IOMemoryDescriptor::withPhysicalAddress( log_physical_address, log_size, kIODirectionOut );
if( fLogDescriptor == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
fLogPhysicalAddressSpace = fController->createPhysicalAddressSpace( fLogDescriptor );
if( fLogPhysicalAddressSpace == NULL )
status = kIOReturnNoMemory;
}
if( status == kIOReturnSuccess )
{
status = fLogPhysicalAddressSpace->activate();
}
return status;
}
void IOFireLogPublisher::free( void )
{
if( fLogPhysicalAddressSpace )
{
fLogPhysicalAddressSpace->deactivate();
fLogPhysicalAddressSpace->release();
fLogPhysicalAddressSpace = NULL;
}
if( fLogDescriptor )
{
fLogDescriptor->release();
fLogDescriptor = NULL;
}
if( fUnitDir )
{
fController->RemoveUnitDirectory( fUnitDir );
fUnitDir->release();
fUnitDir = NULL;
}
if( fFireLog->getMainController() == fController )
{
fFireLog->setMainController( NULL );
}
if( fController )
{
fController->release();
fController = NULL;
}
if( fFireLog )
{
fFireLog->release();
fFireLog = NULL;
}
OSObject::free();
}
#endif