//==============================================================================
// IOHIDEvent::getLatency
//==============================================================================
uint64_t IOHIDEvent::getLatency(uint32_t scaleFactor)
{
    AbsoluteTime    delta = mach_absolute_time();
    uint64_t        ns;
    
    SUB_ABSOLUTETIME(&delta, &_timeStamp);
    
    absolutetime_to_nanoseconds(delta, &ns);

    return ns / scaleFactor;
}
void
AppleUSBUHCI::UIMRootHubStatusChange(void)
{
    UInt8								bitmap, bit;
    unsigned int						i, index, move;
    IOUSBHubPortStatus					portStatus;
    
    USBLog(7, "AppleUSBUHCI[%p]::UIMRootHubStatusChange (_controllerAvailable: %d)", this, _controllerAvailable);

	if (_controllerAvailable && !_wakingFromHibernation)
	{
		// For UHCI, we first need to see if we have a pending resume
		RHCheckStatus();
		
		// Assume a byte can hold all port bits.
		assert(kUHCI_NUM_PORTS < 8);

		/*
		 * Encode the status change bitmap.  The format of the bitmap:
		 * bit0 = hub status changed
		 * bit1 = port 1 status changed
		 * bit2 = port 2 status changed
		 * ...
		 * See USB 1.0 spec section 11.8.3 for more info.
		 */

		bitmap = 0;
		bit = 0x2;
		for (i=1; i <= kUHCI_NUM_PORTS; i++) 
		{
			GetRootHubPortStatus(&portStatus, i);
			if (portStatus.changeFlags != 0) 
			{
				UInt64			elapsedTime;
				uint64_t		currentTime;
				
				USBLog(5, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Port %d hub flags:", this, i);
				RHDumpHubPortStatus(&portStatus);

				bitmap |= bit;
				
				// If this port has seen a recovery attempt (see below) already, check to see what the current time is and if it's > than 2 seconds since the port recovery, then 'forget" about it
				currentTime = mach_absolute_time();
				SUB_ABSOLUTETIME(&currentTime, &_portRecoveryTime[i-1] );
				absolutetime_to_nanoseconds(*(AbsoluteTime *)&currentTime, &elapsedTime);
				elapsedTime /= 1000000000;									// Convert to seconds from nanoseconds
				
				if ( _previousPortRecoveryAttempted[i-1] && (elapsedTime >= kUHCITimeoutForPortRecovery) )
				{
					USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Forgetting about our portRecovery state since the last change occurred %qd seconds ago", this, elapsedTime);
					_previousPortRecoveryAttempted[i-1] = false;
				}
				
				//  If this port has a PED (port enable change) AND the current status is PortPower and Port Connection (which indicates that a condition
				//  on the bus caused the controller to disable the port) then we need to see if we should attempt to re-enable the port w/out calling the
				//  hub driver.  We will do this ONLY if the previous root hub status change for this port did NOT attempt this recovery -- we only try once
				
				if ( !_previousPortRecoveryAttempted[i-1] )
				{
					USBLog(7, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Port %d had a change: 0x%x", this, i, portStatus.changeFlags);
					if ( !(portStatus.statusFlags & kHubPortEnabled)				// if we are not presently enabled
						&& (portStatus.changeFlags & kHubPortEnabled)				// and we were previously enabled
						&& (portStatus.statusFlags & kHubPortConnection)			// and we are presently connected
						&& !(portStatus.changeFlags & kHubPortConnection)			// and the connection has not recently changed (i.e. quick disconnect-connect)
						&& (portStatus.statusFlags & kHubPortPower) )				// and the power is on
					{
						// Indicate that we are attempting a recovery
						_previousPortRecoveryAttempted[i-1] = true;
						currentTime = mach_absolute_time();
						_portRecoveryTime[i-1] = *(AbsoluteTime*)&currentTime;
						
						USBLog(1, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Port %d attempting to enable a disabled port to work around a fickle UHCI controller", this, i);
						USBTrace( kUSBTUHCI, kTPUHCIRootHubStatusChange, (uintptr_t)this, portStatus.statusFlags, portStatus.changeFlags, i );
						
						RHEnablePort(i, true);
						
						// Clear the bitmap
						bitmap &= ~bit;
					}
				}
				else
				{
					// If this is just the notification that the port has been enabled, then don't reset our previousPortRecoveryAttempt
					if ( (portStatus.changeFlags & kHubPortEnabled) and (portStatus.statusFlags & kHubPortConnection) and (portStatus.statusFlags & kHubPortPower) and (portStatus.statusFlags & kHubPortEnabled) )
					{
						USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Port %d had a change but it's just the port enabled notification", this, i);
					}
					else
					{
						USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  Port %d had a change but last time we attempted a recovery, so not attempting again", this, i);
						_previousPortRecoveryAttempted[i-1] = false;
					}
				}
			}
			
			bit <<= 1;

			// Don't clear status bits until explicitly told to.

		}
		if (bitmap)
		{
			USBLog(5, "AppleUSBUHCI[%p]::UIMRootHubStatusChange  RH status bitmap = %x",  this, bitmap);
		}
		_rootHubStatusChangedBitmap = bitmap;
	}
    
    // Bitmap is only one byte, so it doesn't need swapping.
}
Beispiel #3
0
IOReturn
IOPolledFileWrite(IOPolledFileIOVars * vars,
                  const uint8_t * bytes, IOByteCount size,
                  IOPolledFileCryptVars * cryptvars)
{
    IOReturn    err = kIOReturnSuccess;
    IOByteCount copy;
    bool	flush = false;

    do
    {
        if (!bytes && !size)
        {
            // seek to end of block & flush
            size = vars->position & (vars->blockSize - 1);
            if (size)
                size = vars->blockSize - size;
            flush = true;
            // use some garbage for the fill
            bytes = vars->buffer + vars->bufferOffset;
        }

        copy = vars->bufferLimit - vars->bufferOffset;
        if (copy > size)
            copy = size;
        else
            flush = true;

        if (bytes)
        {
            bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
            bytes += copy;
        }
        else
            bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);

        size -= copy;
        vars->bufferOffset += copy;
        vars->position += copy;

        if (flush && vars->bufferOffset)
        {
            uint64_t offset = (vars->position - vars->bufferOffset
                               - vars->extentPosition + vars->currentExtent->start);
            uint32_t length = (vars->bufferOffset);

#if CRYPTO
            if (cryptvars && vars->encryptStart
                    && (vars->position > vars->encryptStart)
                    && ((vars->position - length) < vars->encryptEnd))
            {
                AbsoluteTime startTime, endTime;

                uint64_t encryptLen, encryptStart;
                encryptLen = vars->position - vars->encryptStart;
                if (encryptLen > length)
                    encryptLen = length;
                encryptStart = length - encryptLen;
                if (vars->position > vars->encryptEnd)
                    encryptLen -= (vars->position - vars->encryptEnd);

                clock_get_uptime(&startTime);

                // encrypt the buffer
                aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
                                &cryptvars->aes_iv[0],
                                encryptLen / AES_BLOCK_SIZE,
                                vars->buffer + vars->bufferHalf + encryptStart,
                                &cryptvars->ctx.encrypt);

                clock_get_uptime(&endTime);
                ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
                SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
                vars->cryptBytes += encryptLen;

                // save initial vector for following encrypts
                bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
                      &cryptvars->aes_iv[0],
                      AES_BLOCK_SIZE);
            }
#endif /* CRYPTO */

            err = IOPolledFilePollersIODone(vars->pollers, true);
            if (kIOReturnSuccess != err)
                break;

            if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
//if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);

            err = IOStartPolledIO(vars->pollers, kIOPolledWrite, vars->bufferHalf, offset, length);
            if (kIOReturnSuccess != err)
                break;
            vars->pollers->io = true;

            vars->extentRemaining -= vars->bufferOffset;
            if (!vars->extentRemaining)
            {
                vars->currentExtent++;
                vars->extentRemaining = vars->currentExtent->length;
                vars->extentPosition  = vars->position;
            }

            vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
            vars->bufferOffset = 0;
            if (vars->bufferSize <= vars->extentRemaining)
                vars->bufferLimit = vars->bufferSize;
            else
                vars->bufferLimit = vars->extentRemaining;

            if (!vars->extentRemaining)
            {
                err = kIOReturnOverrun;
                break;
            }

            flush = false;
        }
    }
    while (size);

    return (err);
}
Beispiel #4
0
IOReturn
IOPolledFileRead(IOPolledFileIOVars * vars,
                 uint8_t * bytes, IOByteCount size,
                 IOPolledFileCryptVars * cryptvars)
{
    IOReturn    err = kIOReturnSuccess;
    IOByteCount copy;

//    bytesWritten += size;

    do
    {
        copy = vars->bufferLimit - vars->bufferOffset;
        if (copy > size)
            copy = size;

        if (bytes)
        {
            bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
            bytes += copy;
        }
        size -= copy;
        vars->bufferOffset += copy;
//	vars->position += copy;

        if ((vars->bufferOffset == vars->bufferLimit) && (vars->position < vars->readEnd))
        {
            if (!vars->pollers->io) cryptvars = 0;
            err = IOPolledFilePollersIODone(vars->pollers, true);
            if (kIOReturnSuccess != err)
                break;

            if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);

            vars->position        += vars->lastRead;
            vars->extentRemaining -= vars->lastRead;
            vars->bufferLimit      = vars->lastRead;

            if (!vars->extentRemaining)
            {
                vars->currentExtent++;
                vars->extentRemaining = vars->currentExtent->length;
                vars->extentPosition  = vars->position;
                if (!vars->extentRemaining)
                {
                    err = kIOReturnOverrun;
                    break;
                }
            }

            uint64_t length;
            uint64_t lastReadLength = vars->lastRead;
            uint64_t offset = (vars->position
                               - vars->extentPosition + vars->currentExtent->start);
            if (vars->extentRemaining <= vars->bufferSize)
                length = vars->extentRemaining;
            else
                length = vars->bufferSize;
            if ((length + vars->position) > vars->readEnd)
                length = vars->readEnd - vars->position;

            vars->lastRead = length;
            if (length)
            {
//if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
                err = IOStartPolledIO(vars->pollers, kIOPolledRead, vars->bufferHalf, offset, length);
                if (kIOReturnSuccess != err)
                    break;
                vars->pollers->io = true;
            }

            vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
            vars->bufferOffset = 0;

#if CRYPTO
            if (cryptvars)
            {
                uint8_t thisVector[AES_BLOCK_SIZE];
                AbsoluteTime startTime, endTime;

                // save initial vector for following decrypts
                bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE);
                bcopy(vars->buffer + vars->bufferHalf + lastReadLength - AES_BLOCK_SIZE,
                      &cryptvars->aes_iv[0], AES_BLOCK_SIZE);

                // decrypt the buffer
                clock_get_uptime(&startTime);

                aes_decrypt_cbc(vars->buffer + vars->bufferHalf,
                                &thisVector[0],
                                lastReadLength / AES_BLOCK_SIZE,
                                vars->buffer + vars->bufferHalf,
                                &cryptvars->ctx.decrypt);

                clock_get_uptime(&endTime);
                ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
                SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
                vars->cryptBytes += lastReadLength;
            }
#endif /* CRYPTO */
        }
    }
    while (size);

    return (err);
}
Beispiel #5
0
IOReturn
IOPolledFileOpen(const char * filename,
                 uint64_t setFileSize, uint64_t fsFreeSize,
                 void * write_file_addr, size_t write_file_len,
                 IOPolledFileIOVars ** fileVars,
                 OSData ** imagePath,
                 uint8_t * volumeCryptKey, size_t keySize)
{
    IOReturn             err = kIOReturnSuccess;
    IOPolledFileIOVars * vars;
    _OpenFileContext     ctx;
    OSData *             extentsData;
    OSNumber *           num;
    IOService *          part = 0;
    dev_t                block_dev;
    dev_t                image_dev;
    AbsoluteTime         startTime, endTime;
    uint64_t             nsec;

    vars = IONew(IOPolledFileIOVars, 1);
    if (!vars) return (kIOReturnNoMemory);
    bzero(vars, sizeof(*vars));
    vars->allocated = true;

    do
    {
        extentsData = OSData::withCapacity(32);
        ctx.extents = extentsData;
        ctx.size    = 0;
        clock_get_uptime(&startTime);

        vars->fileRef = kern_open_file_for_direct_io(filename,
                        (write_file_addr != NULL) || (0 != setFileSize),
                        &file_extent_callback, &ctx,
                        setFileSize,
                        fsFreeSize,
                        // write file:
                        0, write_file_addr, write_file_len,
                        // results
                        &block_dev,
                        &image_dev,
                        &vars->block0,
                        &vars->maxiobytes,
                        &vars->flags);
#if 0
        uint32_t msDelay = (131071 & random());
        HIBLOG("sleep %d\n", msDelay);
        IOSleep(msDelay);
#endif
        clock_get_uptime(&endTime);
        SUB_ABSOLUTETIME(&endTime, &startTime);
        absolutetime_to_nanoseconds(endTime, &nsec);

        if (!vars->fileRef) err = kIOReturnNoSpace;

        HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec / 1000000ULL);
        if (kIOReturnSuccess != err) break;

        HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename, ctx.size,
               (extentsData->getLength() / sizeof(IOPolledFileExtent)) - 1,
               vars->maxiobytes, kIOPolledFileSSD & vars->flags);
        assert(!vars->block0);
        if (extentsData->getLength() < sizeof(IOPolledFileExtent))
        {
            err = kIOReturnNoSpace;
            break;
        }

        vars->fileSize = ctx.size;
        vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();

        part = IOCopyMediaForDev(image_dev);
        if (!part)
        {
            err = kIOReturnNotFound;
            break;
        }

        if (!(vars->pollers = IOPolledFilePollers::copyPollers(part))) break;

        if ((num = OSDynamicCast(OSNumber, part->getProperty(kIOMediaPreferredBlockSizeKey))))
            vars->blockSize = num->unsigned32BitValue();
        if (vars->blockSize < 4096) vars->blockSize = 4096;

        HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
               major(image_dev), minor(image_dev), (long)vars->blockSize,
               vars->pollers->pollers->getCount());

        OSString * keyUUID = NULL;
        if (volumeCryptKey)
        {
            err = IOGetVolumeCryptKey(block_dev, &keyUUID, volumeCryptKey, keySize);
        }

        *fileVars    = vars;
        vars->fileExtents = extentsData;

        // make imagePath
        OSData * data;
        if (imagePath)
        {
#if defined(__i386__) || defined(__x86_64__)
            char str2[24 + sizeof(uuid_string_t) + 2];

            if (keyUUID)
                snprintf(str2, sizeof(str2), "%qx:%s",
                         vars->extentMap[0].start, keyUUID->getCStringNoCopy());
            else
                snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);

            err = IOService::getPlatform()->callPlatformFunction(
                      gIOCreateEFIDevicePathSymbol, false,
                      (void *) part, (void *) str2,
                      (void *) (uintptr_t) true, (void *) &data);
#else
            data = 0;
            err = kIOReturnSuccess;
#endif
            if (kIOReturnSuccess != err)
            {
                HIBLOG("error 0x%x getting path\n", err);
                break;
            }
            *imagePath = data;
        }
    }
    while (false);

    if (kIOReturnSuccess != err)
    {
        HIBLOG("error 0x%x opening polled file\n", err);
        IOPolledFileClose(&vars, 0, 0, 0, 0, 0);
    }

    if (part) part->release();

    return (err);
}