Example #1
0
/*++

Private so we can later expose to someone wanting to use a preallocated buffer

--*/
NTSTATUS
NTAPI
CdRompGetConfiguration(
    IN PDEVICE_OBJECT Fdo,
    IN PGET_CONFIGURATION_HEADER Buffer,
    IN ULONG BufferSize,
    OUT PULONG ValidBytes,
    IN FEATURE_NUMBER StartingFeature,
    IN ULONG RequestedType
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
    PCDROM_DATA cdData;
    SCSI_REQUEST_BLOCK srb;
    PCDB cdb;
    ULONG_PTR returned;
    NTSTATUS status;

    PAGED_CODE();
    ASSERT(Buffer);
    ASSERT(ValidBytes);

    *ValidBytes = 0;
    returned = 0;

    RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
    RtlZeroMemory(Buffer, BufferSize);

    fdoExtension = Fdo->DeviceExtension;
    cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);

    if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) {
        return STATUS_INVALID_DEVICE_REQUEST;
    }

    srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
    srb.CdbLength = 10;

    cdb = (PCDB)srb.Cdb;
    cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
    cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType;
    cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8);
    cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff);
    cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8);
    cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff);

    status = ClassSendSrbSynchronous(Fdo,  &srb,  Buffer,
                                     BufferSize, FALSE);
    returned = srb.DataTransferLength;

    KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
               "CdromGetConfiguration: Status was %x\n", status));

    if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {

        //
        // if returned more than can be stored in a ULONG, return false
        //

        if (returned > (ULONG)(-1)) {
            return STATUS_UNSUCCESSFUL;
        }
        ASSERT(returned <= BufferSize);
        *ValidBytes = (ULONG)returned;
        return STATUS_SUCCESS;

    } else {

        KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                   "CdromGetConfiguration: failed %x\n", status));
        return status;

    }
    ASSERT(FALSE);
    return STATUS_UNSUCCESSFUL;
}
Example #2
0
/*++

    NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
    if memory is non-paged
    
--*/
PVOID
NTAPI
CdRomFindFeaturePage(
    IN PGET_CONFIGURATION_HEADER FeatureBuffer,
    IN ULONG Length,
    IN FEATURE_NUMBER Feature
    )
{
    PUCHAR buffer;
    PUCHAR limit;
    
    if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) {
        return NULL;
    }

    //
    // set limit to point to first illegal address
    //

    limit  = (PUCHAR)FeatureBuffer;
    limit += Length;

    //
    // set buffer to point to first page
    //

    buffer = FeatureBuffer->Data;

    //
    // loop through each page until we find the requested one, or
    // until it's not safe to access the entire feature header
    // (if equal, have exactly enough for the feature header)
    //
    while (buffer + sizeof(FEATURE_HEADER) <= limit) {

        PFEATURE_HEADER header = (PFEATURE_HEADER)buffer;
        FEATURE_NUMBER thisFeature;

        thisFeature  =
            (header->FeatureCode[0] << 8) |
            (header->FeatureCode[1]);

        if (thisFeature == Feature) {

            PUCHAR temp;

            //
            // if don't have enough memory to safely access all the feature
            // information, return NULL
            //
            temp = buffer;
            temp += sizeof(FEATURE_HEADER);
            temp += header->AdditionalLength;
            
            if (temp > limit) {

                //
                // this means the transfer was cut-off, an insufficiently
                // small buffer was given, or other arbitrary error.  since
                // it's not safe to view the amount of data (even though
                // the header is safe) in this feature, pretend it wasn't
                // transferred at all...
                //

                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "Feature %x exists, but not safe to access all its "
                           "data.  returning NULL\n", Feature));
                return NULL;
            } else {
                return buffer;
            }
        }

        if (header->AdditionalLength % 4) {
            ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
            return NULL;
        }

        buffer += sizeof(FEATURE_HEADER);
        buffer += header->AdditionalLength;
    
    }
    return NULL;
}
Example #3
0
VOID
NTAPI
CdRompFlushDelayedList(
    IN PDEVICE_OBJECT Fdo,
    IN PCDROM_MMC_EXTENSION MmcData,
    IN NTSTATUS Status,
    IN BOOLEAN CalledFromWorkItem
    )
{
    PSINGLE_LIST_ENTRY list;
    PIRP irp;

    // NOTE - REF #0002
    //
    // need to set the new state first to prevent deadlocks.
    // this is only done from the workitem, to prevent any
    // edge cases where we'd "lose" the UpdateRequired
    //
    // then, must ignore the state, since it's not guaranteed to
    // be the same any longer.  the only thing left is to handle
    // all the delayed irps by flushing the queue and sending them
    // back onto the StartIo queue for the device.
    //

    if (CalledFromWorkItem) {
        
        LONG oldState;
        LONG newState;

        if (NT_SUCCESS(Status)) {
            newState = CdromMmcUpdateComplete;
        } else {
            newState = CdromMmcUpdateRequired;
        }

        oldState = InterlockedCompareExchange(&MmcData->UpdateState,
                                              newState,
                                              CdromMmcUpdateStarted);
        ASSERT(oldState == CdromMmcUpdateStarted);

    } else {

        //
        // just flushing the queue if not called from the workitem,
        // and we don't want to ever fail the queue in those cases.
        //

        ASSERT(NT_SUCCESS(Status));

    }

    list = ExInterlockedFlushSList(&MmcData->DelayedIrps);
    
    // if this assert fires, it means that we have started
    // a workitem when the previous workitem took the delayed
    // irp.  if this happens, then the logic in HACKHACK #0002
    // is either flawed or the rules set within are not being
    // followed.  this would require investigation.
    
    ASSERT(list != NULL);

    //
    // now either succeed or fail all the delayed irps, according
    // to the update status.
    //

    while (list != NULL) {

        irp = (PIRP)( ((PUCHAR)list) -
                      FIELD_OFFSET(IRP, Tail.Overlay.DriverContext[0])
                      );
        list = list->Next;
        irp->Tail.Overlay.DriverContext[0] = 0;
        irp->Tail.Overlay.DriverContext[1] = 0;
        irp->Tail.Overlay.DriverContext[2] = 0;
        irp->Tail.Overlay.DriverContext[3] = 0;

        if (NT_SUCCESS(Status)) {
            
            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Re-sending delayed irp %p\n",
                       irp));
            IoStartPacket(Fdo, irp, NULL, NULL);

        } else {
            
            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Failing delayed irp %p with "
                       " status %x\n", irp, Status));
            irp->IoStatus.Information = 0;
            irp->IoStatus.Status = Status;
            ClassReleaseRemoveLock(Fdo, irp);
            IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);

        }

    } // while (list)

    return;

}
Example #4
0
RPSTATUS
EventCheck(
	IN PUNICODE_STRING pusCriminal,
	IN PUNICODE_STRING pusVictim,
	IN PEPROCESS		pCriminalEproc,
	IN PEPROCESS		pVictimEproc,
	IN ULONG			ulCrimeType,
	IN ULONG_PTR		ulpExtraInfo
	)
/*++

Routine Description:

	处理检测到的违规操作


Arguments:

	pusCriminal - 违规者名字

	pusVictim - 受害者名字

	pCriminalEproc - 违规者进程

	pVictimEproc - 受害者进程

	ulCrimeType - 违规类型

	ulpExtraInfo - 额外信息,根据违规类型的不同而不同


Return Value:

	允许放行返回 RP_STATUS_OK,拒绝该操作返回 RP_STATUS_ERR


Author:

	Fypher

--*/
{
	PEVENTDATA pEvtData;
	ULONG ulJudgment;
	RPSTATUS RpStatus = RP_STATUS_NOT_CLEAR;

	PAGED_CODE();

	if (!g_pProtected)					// no ring3
		return RP_STATUS_OK;

	if (!IsMajorProtected(ulCrimeType))		// protect off
		return RP_STATUS_OK;

	if (IsInWhiteBlackHashTable(pusCriminal, CRIME_MAJOR_ALL, NODE_TYPE_WHITE))	// Super White List
		return RP_STATUS_OK;

	if (IsInWhiteBlackHashTable(pusCriminal, ulCrimeType, NODE_TYPE_WHITE))			// white list
		RpStatus = RP_STATUS_OK;
	else if (IsInWhiteBlackHashTable(pusCriminal, ulCrimeType, NODE_TYPE_BLACK))	// black list
		RpStatus = RP_STATUS_ERR;

	if (pCriminalEproc && pCriminalEproc == pVictimEproc)	// Self xx
		return RP_STATUS_OK;

	if (g_ulEventDataCount > MAX_EVENT_IN_LIST)	{ // too many
		KdPrintEx((DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, "EventCheck! g_ulEventDataCount: %d\r\n", g_ulEventDataCount));
		return RP_STATUS_ERR;
	}

	switch (ulCrimeType & CRIME_MAJOR_MASK) {
		//
		// CRIME_MAJOR_FILE
		//
		case CRIME_MAJOR_FILE:
			if (!IsInWhiteBlackHashTable(pusVictim, CRIME_MAJOR_FILE, NODE_TYPE_BLACK))
				return RP_STATUS_OK;

			break;
		//
		// CRIME_MAJOR_PROC
		//
		case CRIME_MAJOR_PROC:
			if (pVictimEproc == g_pProtected)	// self protect
				return RP_STATUS_ERR;

			// only for self protect
			if (ulCrimeType == CRIME_MINOR_NtOpenProcess	||
				ulCrimeType == CRIME_MINOR_NtOpenThread		||
				ulCrimeType == CRIME_MINOR_NtAssignProcessToJobObject)
			{
				return RP_STATUS_OK;
			}
			break;
		//
		// CRIME_MAJOR_REG
		//
		case CRIME_MAJOR_REG:
			break;
		//
		// CRIME_MAJOR_SYS
		//
		case CRIME_MAJOR_SYS:
			if (ulCrimeType == CRIME_MINOR_NtDuplicateObject)
			{
				if (g_pProtected == (PEPROCESS)ulpExtraInfo) {	// selfprotect
					return RP_STATUS_ERR;
				}
			}
			else if (ulCrimeType == CRIME_MINOR_NtOpenSection)
			{
				if (/*g_pPhysicalMemoryObj && */g_pPhysicalMemoryObj != (PVOID)ulpExtraInfo)
					return RP_STATUS_OK;
			}
			break;
		default:
			KdPrintEx((	DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL,
						"EventCheck! How did I get here! %x\r\n", ulCrimeType
					));
			break;
	}

	if (RpStatus != RP_STATUS_NOT_CLEAR)
		return RpStatus;

	pEvtData = BuildEventData(pusCriminal, pusVictim, pCriminalEproc, pVictimEproc, ulCrimeType, ulpExtraInfo);
	if (!pEvtData)
		return RP_STATUS_ERR;

	PushEvent(pEvtData);

	KeWaitForSingleObject(&pEvtData->evt, Executive, KernelMode, FALSE, NULL);

	ulJudgment = pEvtData->ulJudgment;

	DestroyEventData(pEvtData);

	if (ulJudgment & JUDGMENT_ACCEPT) {
		if (ulJudgment & JUDGMENT_ALWAYS) {
			AddToWhiteBlackHashTable(pusCriminal, ulCrimeType, NODE_TYPE_WHITE);
		}
		return RP_STATUS_OK;
	} else if (ulJudgment & JUDGMENT_REFUSE) {
		if (ulJudgment & JUDGMENT_ALWAYS) {
			AddToWhiteBlackHashTable(pusCriminal, ulCrimeType, NODE_TYPE_BLACK);
		}
		return RP_STATUS_ERR;
	}

	// never reaches here
	return RP_STATUS_ERR;

}
Example #5
0
VOID
NTAPI
CdRomUpdateMmcDriveCapabilities(
    IN PDEVICE_OBJECT Fdo,
    IN PVOID Context
    )
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
    PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
    PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
    PIO_STACK_LOCATION thisStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
    PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
    NTSTATUS status;


    ASSERT(Context == NULL);

    //
    // NOTE: a remove lock is unnecessary, since the delayed irp
    // will have said lock held for itself, preventing a remove.
    //
    CdRomPrepareUpdateCapabilitiesIrp(Fdo);
    
    ASSERT(thisStack->Parameters.Others.Argument1 == Fdo);
    ASSERT(thisStack->Parameters.Others.Argument2 == mmcData->CapabilitiesBuffer);
    ASSERT(thisStack->Parameters.Others.Argument3 == &(mmcData->CapabilitiesSrb));
    
    mmcData->WriteAllowed = FALSE; // default to read-only

    //
    // set max retries, and also allow volume verify override based on
    // original (delayed) irp
    //
    
    thisStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;

    //
    // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
    // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL 
    //

    IoCallDriver(commonExtension->LowerDeviceObject, mmcData->CapabilitiesIrp);

    KeWaitForSingleObject(&mmcData->CapabilitiesEvent,
                          Executive, KernelMode, FALSE, NULL);
    
    status = mmcData->CapabilitiesIrp->IoStatus.Status;
    
    if (!NT_SUCCESS(status)) {

        goto FinishDriveUpdate;
    
    }

    //
    // we've updated the feature set, so update whether or not reads and writes
    // are allowed or not.
    //

    KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
               "CdRomUpdateMmc => Succeeded "
               "--------------------"
               "--------------------\n"));

    /*++
    
    NOTE: It is important to only use srb->DataTransferLength worth
          of data at this point, since the bufferSize is what is
          *available* to use, not what was *actually* used.
    
    --*/

#if DBG
    CdRompPrintAllFeaturePages(mmcData->CapabilitiesBuffer,
                               srb->DataTransferLength);
#endif // DBG

    //
    // update whether or not writes are allowed.  this is currently defined
    // as requiring TargetDefectManagement and RandomWritable features
    //
    {
        PFEATURE_HEADER defectHeader;
        PFEATURE_HEADER writableHeader;

        defectHeader   = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
                                              srb->DataTransferLength,
                                              FeatureDefectManagement);
        writableHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
                                              srb->DataTransferLength,
                                              FeatureRandomWritable);

        if ((defectHeader != NULL)  && (writableHeader != NULL) &&
            (defectHeader->Current) && (writableHeader->Current)) {

            //
            // this should be the *ONLY* place writes are set to allowed 
            //

            KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                       "CdRomUpdateMmc => Writes *allowed*\n"));
            mmcData->WriteAllowed = TRUE;

        } else {

            if (defectHeader == NULL) {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "defect management", "DNE"));
            } else {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "defect management", "Not Current"));
            }
            if (writableHeader == NULL) {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "sector writable", "DNE"));
            } else {
                KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
                           "CdRomUpdateMmc => No writes - %s = %s\n",
                           "sector writable", "Not Current"));
            }
        } // end of feature checking
    } // end of check for writability

    //
    // update the cached partition table information
    //
    // NOTE: THIS WILL CURRENTLY CAUSE A DEADLOCK!
    //
    // ISSUE-2000/06/20-henrygab - partition support not implemented
    //                             IoReadPartitionTable must be done
    //                             at PASSIVE level, requiring a thread
    //                             or worker item or other such method.
    //
#if 0
    status = IoReadPartitionTable(Fdo, 1 << fdoExtension->SectorShift,
                                  TRUE, &mmcData->PartitionList);
    if (!NT_SUCCESS(status)) {

        goto FinishDriveUpdate;

    }
#endif

    status = STATUS_SUCCESS;

FinishDriveUpdate:

    CdRompFlushDelayedList(Fdo, mmcData, status, TRUE);

    return;
}
Example #6
0
//
// Io events callbacks.
//
VOID
MarsEvtIoDeviceControl(
                      IN WDFQUEUE Queue,
                      IN WDFREQUEST Request,
                      IN size_t OutputBufferLength,
                      IN size_t InputBufferLength,
                      IN ULONG IoControlCode
                      )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
    requests from the system.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - Handle to a framework request object.

    OutputBufferLength - length of the request's output buffer,
                        if an output buffer is available.
    InputBufferLength - length of the request's input buffer,
                        if an input buffer is available.

    IoControlCode - the driver-defined or system-defined I/O control code
                    (IOCTL) that is associated with the request.
Return Value:

    VOID

--*/
{
    PFDO_DATA               fdoData = NULL;
    WDFDEVICE               device;
    NTSTATUS                status = STATUS_SUCCESS;
    PVOID                   inBuffer = NULL, outBuffer = NULL;
    size_t                  bytesReturned = 0;
    size_t                  size = 0;

    PAGED_CODE();

    //DbgPrint(("Started MarsEvtIODeviceControl\n"));

    device = WdfIoQueueGetDevice(Queue);
    fdoData = MarsFdoGetData(device);            //Gets device context

    //
    // Get the ioctl input & output buffers
    //
    if (InputBufferLength != 0) {
        status = WdfRequestRetrieveInputBuffer(Request,
                                               InputBufferLength,
                                               &inBuffer,
                                               &size);

        if (!NT_SUCCESS(status)) {
            WdfRequestComplete(Request, status);
            return;
        }
    }

    if (OutputBufferLength != 0) {
        status = WdfRequestRetrieveOutputBuffer(Request,
                                                OutputBufferLength,
                                                &outBuffer,
                                                &size);
        if (!NT_SUCCESS(status)) {
            WdfRequestComplete(Request, status);
            return;
        }
    }

    switch (IoControlCode) {
    
    case IOCTL_MARS_GET_DRIVER_VERSION:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUSHORT)outBuffer = fdoData->DriverVersion;
        bytesReturned = sizeof(USHORT);
        break;


    case IOCTL_MARS_GET_FUNCTION_NUMBER:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUCHAR)outBuffer = fdoData->FunctionNumber;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_GET_FUNCTION_FOCUS:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUCHAR)outBuffer = fdoData->FunctionFocus;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_SET_FUNCTION_FOCUS:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        fdoData->FunctionFocus = *(PUCHAR)inBuffer;
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_WIDTH
        //
        //---------------------------------------------------

    case IOCTL_MARS_GET_BUS_WIDTH:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioGetProperty(device, SDP_BUS_WIDTH,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_BUS_WIDTH:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioSetProperty(device, SDP_BUS_WIDTH,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_CLOCK
        //
        //---------------------------------------------------

    case IOCTL_MARS_GET_BUS_CLOCK:

        if (OutputBufferLength < sizeof(ULONG)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioGetProperty(device, SDP_BUS_CLOCK,
                                 outBuffer, sizeof(ULONG));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(ULONG);
        }
        break;


    case IOCTL_MARS_SET_BUS_CLOCK:

        if (InputBufferLength < sizeof(ULONG)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioSetProperty(device, SDP_BUS_CLOCK,
                                 inBuffer, sizeof(ULONG));
        break;


        //---------------------------------------------------
        //
        // SDP_FUNCTION_BLOCK_LENGTH
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_BLOCKLEN:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FUNCTION_BLOCK_LENGTH,
                                 outBuffer, sizeof(SHORT));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(USHORT);
        }
        break;


    case IOCTL_MARS_SET_BLOCKLEN:

        if (InputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FUNCTION_BLOCK_LENGTH,
                                 inBuffer, sizeof(SHORT));
        break;


        //---------------------------------------------------
        //
        // SDP_FN0_BLOCK_LENGTH
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_FN0_BLOCKLEN:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FN0_BLOCK_LENGTH,
                                 outBuffer, sizeof(SHORT));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(USHORT);
        }
        break;


    case IOCTL_MARS_SET_FN0_BLOCKLEN:

        if (InputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FN0_BLOCK_LENGTH,
                                 inBuffer, sizeof(SHORT));
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_INTERFACE_CONTROL
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_BUS_INTERFACE_CONTROL:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_BUS_INTERFACE_CONTROL,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_BUS_INTERFACE_CONTROL:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_BUS_INTERFACE_CONTROL,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // SDP_FUNCTION_INT_ENABLE
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_INT_ENABLE:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FUNCTION_INT_ENABLE,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_INT_ENABLE:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FUNCTION_INT_ENABLE,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // READ/WRITE BYTE
        //
        //---------------------------------------------------


    case IOCTL_MARS_READ_BYTE:

        if ((InputBufferLength < sizeof(ULONG)) || (OutputBufferLength < sizeof(UCHAR))) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioReadWriteByte(device,
                                   fdoData->FunctionFocus,
                                   (PUCHAR)outBuffer,
                                   *(PULONG)inBuffer,
                                   FALSE);

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }

        break;


    case IOCTL_MARS_WRITE_BYTE:

        if ((InputBufferLength < sizeof(ULONG)*2)) {//||(OutputBufferLength < sizeof(UCHAR))) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        // BUGBUG: check for output buffer length

        status = SdioReadWriteByte(device,
                                   fdoData->FunctionFocus,
                                   (PUCHAR)(&((PULONG)inBuffer)[1]),
                                   *(PULONG)inBuffer,
                                   TRUE);

        // BUGBUG: Return the right size

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }


        break;


        //---------------------------------------------------
        //
        // Mode settings
        //
        //---------------------------------------------------

    case IOCTL_MARS_SET_TRANSFER_MODE:

        bytesReturned  = 0;

        break;

    case IOCTL_MARS_TOGGLE_MODE:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (fdoData->DriverVersion < SDBUS_DRIVER_VERSION_2) {
            status = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }

        fdoData->BlockMode = fdoData->BlockMode ? 0 : 1;
        *(PUCHAR)outBuffer = fdoData->BlockMode;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_TOGGLE_NOISY:

        if (OutputBufferLength < sizeof(BOOLEAN)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        NoisyMode = NoisyMode ? 0 : 1;
        *(PBOOLEAN)outBuffer = NoisyMode;
        bytesReturned  = sizeof(BOOLEAN);

        if (NoisyMode) {
            KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Noisy mode\n"));
        } else {
            KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Quiet mode\n"));
        }
        break;


    default:
        NT_ASSERTMSG("Invalid IOCTL request\n", FALSE);

        status = STATUS_INVALID_DEVICE_REQUEST;
    }

    WdfRequestCompleteWithInformation(Request, status, bytesReturned);
    return;
}
VOID  TpmEvtIoDeviceControl (
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  OutputBufferLength,
    IN size_t  InputBufferLength,
    IN ULONG  IoControlCode
    )
{
    NTSTATUS        status;
    PTPM_CONTEXT    TpmContext;
    WDFDEVICE       Device;

	PAGED_CODE();

    Device = WdfIoQueueGetDevice(Queue);
    TpmContext = GetTpmContext(Device);

    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_WARNING_LEVEL,
            "TpmEvtIoDeviceControl called - IoControlCode: 0x%x \n",
            IoControlCode));

    switch(IoControlCode)
    {
    case TPM_CANCEL_COMMAND:
		
        status = TpmAbort(TpmContext,StAvailable,StAborting,IdAbort);
        break;

    case TPM_TRANSMIT_COMMAND:
		
        status = TpmHandleTransmit(Device,
                                   Request,
                                   OutputBufferLength,
                                   InputBufferLength);
        break;

    case TPM_SUMBIT_ACPI_COMMAND:

        if(TpmContext->TpmState != StAvailable)
        {
            status = STATUS_CANCELLED;
            WdfRequestComplete( Request, status);
			return;
        }

        status = TpmHandleSubmitAcpiCommand(Device,
                                   Request,
                                   OutputBufferLength,
                                   InputBufferLength);

        break;

    default:
        KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
            "TpmEvtIoDeviceControl: Invalid request 0x%x\n",IoControlCode));
        status = STATUS_INVALID_DEVICE_REQUEST;

        break;
    }

    WdfRequestComplete( Request, status);
}
NTSTATUS
TpmEvtDevicePrepareHardware (
							 WDFDEVICE      Device,
							 WDFCMRESLIST   Resources,
							 WDFCMRESLIST   ResourcesTranslated
    )
{
    NTSTATUS                    status;
    ULONG                       ListCount = 0;
    ULONG                       MemLen = 0;
//    ULONG                       NumberOfBytes;
    PTPM_CONTEXT                TpmContext;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDesc;
    ULONG                       ListIndex;
    PHYSICAL_ADDRESS            MemoryAddr;
    BOOLEAN                     bMemAddr = FALSE;

	PAGED_CODE();

    TpmContext = GetTpmContext(Device);

    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                "TpmEvtDevicePrepareHardware (raw count = %u, trans count = %u)\n",
                WdfCmResourceListGetCount(Resources),
                WdfCmResourceListGetCount(ResourcesTranslated)));

    ListIndex = 0;

    ListCount = WdfCmResourceListGetCount(ResourcesTranslated);

    if(ListCount)
    {
        while(ListIndex < ListCount)
        {
            ResourceDesc = WdfCmResourceListGetDescriptor(ResourcesTranslated,ListIndex);

            if(!ResourceDesc) break;

            if(ResourceDesc->Type == CmResourceTypePort)
            {
                if(TpmContext->UsePortBasedIO)
                {
                    TpmContext->PortAddr = (PUCHAR)ResourceDesc->u.Port.Start.u.LowPart;
                }
            }
            else if(ResourceDesc->Type == CmResourceTypeMemory && TpmContext->UsePortBasedIO == 0)
            {
                MemoryAddr.u.LowPart = ResourceDesc->u.Memory.Start.u.LowPart;
                MemoryAddr.u.HighPart = ResourceDesc->u.Memory.Start.u.HighPart;
                MemLen = ResourceDesc->u.Memory.Length;
                bMemAddr = TRUE;
            }
            ListIndex++;
        }

        do
        {
            if(ListIndex < WdfCmResourceListGetCount( ResourcesTranslated))
            {
                KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                    "WdfCmResourceListGetDescriptor failed.\n"));
                status = STATUS_DEVICE_CONFIGURATION_ERROR; // 0xC0000182;
                break;
            }

            if(TpmContext->UsePortBasedIO)
            {
                if(!TpmContext->PortAddr)
                {
                    if(TpmContext->UsePortBasedIO != TRUE)
                    {
                        KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_WARNING_LEVEL,
                                  "Port I/O resources required but not allocated for Vendor index %u",
                                  TpmContext->UsePortBasedIO));
                        status = STATUS_DEVICE_CONFIGURATION_ERROR; // 0xC0000182;
                        goto Exit;
                    }

                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_WARNING_LEVEL,
                            "No resources allocated for Port-based I/O."));

					status = STATUS_DEVICE_CONFIGURATION_ERROR;
					break;
                }
            }
            else
            {
                if(!bMemAddr)
                {
                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                            "Physical address resource not provided via ACPI; using default address and size.\n"));
                    MemLen = 1024;
                    MemoryAddr.u.LowPart    = TPM_DEFAULT_ADDRESS;
                    MemoryAddr.u.HighPart   = 0;
                }

                if(MemLen < 1024)
                {
                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                            "Physical address length provided is too small (%d)\n",MemLen));
                    status = STATUS_DEVICE_CONFIGURATION_ERROR; //0xC0000182;
                    break;
                }

                if(MemoryAddr.u.LowPart != TPM_DEFAULT_ADDRESS || MemoryAddr.u.HighPart)
                {
                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                                "Physical address provided is incorrect: 0x%08x`%08x\n",MemoryAddr.u.HighPart,MemoryAddr.u.LowPart));
                    status = STATUS_DEVICE_CONFIGURATION_ERROR; //0xC0000182;
                    break;
                }

                TpmContext->MemAddr = MmMapIoSpace(MemoryAddr,MemLen,MmNonCached);
                if(!TpmContext->MemAddr)
                {
                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                            "MmMapIoSpace couldn't map the TPM device: 0x%x.\n", MemoryAddr.u.LowPart));
                    status = STATUS_INSUFFICIENT_RESOURCES; //0xC000009A;
                    break;
                }

                TpmContext->MemLen = MemLen;

            }

            status = TpmSetDefaultTimingValues(TpmContext);
            if(!NT_SUCCESS(status))
            {
                KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                    "TpmSetDefaultTimingValues failed with status 0x%x",status));
                break;
            }

            if(TpmContext->SkipInitCommands)
            {
                KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                    "Skipping initialization commands\n"));
            }
            else
            {
                TpmGetTimeoutInfo(TpmContext);
                TpmGetDurations(TpmContext);
				// 获取硬件厂商信息
				TpmGetManufacturer(TpmContext);
            }

            status = TpmVerifyAccessRegister(TpmContext,TpmINB(TpmContext,0),0);
            if(!NT_SUCCESS(status))
            {
                break;
            }

#if _NT_TARGET_VERSION >= 0x601
            status = TpmEntropyInit(TpmContext);
#endif

        } while(FALSE);
    }
    else
    {
         KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
            "Physical address resource not provided via ACPI; using default address and size.\n"));
    }

Exit:
    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
        "TpmEvtDevicePrepareHardware exited with Status code 0x%x\n",status));

    return status;
}
NTSTATUS
TpmEvtDeviceAdd(
				IN WDFDRIVER        Driver,
				IN PWDFDEVICE_INIT  DeviceInit
    )
{
    NTSTATUS                    status = STATUS_SUCCESS;
    WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks;
    WDF_OBJECT_ATTRIBUTES       DeviceAttributes;
    WDFDEVICE                   device;
    PTPM_CONTEXT                TpmContext;
    WDF_IO_QUEUE_CONFIG         IoQueueConfig;
    WDFQUEUE                    hQueue;
    WDF_QUERY_INTERFACE_CONFIG  InterfaceConfig;
    TPM_INTERFACE_STANDARD      TpmInterface;
    WDF_DEVICE_POWER_CAPABILITIES   PowerCaps;

	PAGED_CODE();

    UNREFERENCED_PARAMETER( Driver );

    
    RtlZeroMemory(&PnpPowerEventCallbacks,sizeof(PnpPowerEventCallbacks));
    RtlZeroMemory(&PowerCaps,sizeof(PowerCaps));

    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
		"TpmEvtDeviceAdd routine PDO: %p (%p)\n",
				WdfDriverWdmGetDriverObject(Driver)));
    //
    // Zero out the PnpPowerCallbacks structure.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerEventCallbacks);

    //
    // These two callbacks set up and tear down hardware state that must be
    // done every time the device moves in and out of the D0-working state.
    //
    PnpPowerEventCallbacks.EvtDeviceD0Entry         = TpmEvtDeviceD0Entry;

    PnpPowerEventCallbacks.EvtDeviceD0Exit          = TpmEvtDeviceD0Exit;
    //
    // Set Callbacks for any of the functions we are interested in.
    // If no callback is set, Framework will take the default action
    // by itself.
    //
    PnpPowerEventCallbacks.EvtDevicePrepareHardware = TpmEvtDevicePrepareHardware;
    PnpPowerEventCallbacks.EvtDeviceReleaseHardware = TpmEvtDeviceReleaseHardware;


    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit,&PnpPowerEventCallbacks);

    //
    // Specify the context type and size for the device we are about to create.
    //
	RtlZeroMemory(&DeviceAttributes,sizeof(DeviceAttributes));
    WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&DeviceAttributes, TPM_CONTEXT);
	DeviceAttributes.Size = sizeof(WDF_OBJECT_ATTRIBUTES);
	DeviceAttributes.SynchronizationScope	= WdfSynchronizationScopeInheritFromParent;
	DeviceAttributes.ExecutionLevel			= WdfExecutionLevelPassive;

    status = WdfDeviceCreate(&DeviceInit,&DeviceAttributes,&device);

    if(NT_SUCCESS(status))
    {
        TpmContext = GetTpmContext(device);
        RtlZeroMemory(TpmContext,sizeof(TPM_CONTEXT));
        TpmContext->Device = device;
        TpmContext->AccessRegister = FALSE;
        KeInitializeSpinLock(&TpmContext->SpinLock);
        TpmContext->TpmState = StSuspend;
        TpmInitStateTable();
        KeInitializeEvent(&TpmContext->Event,NotificationEvent,TRUE);

        status = WdfDeviceCreateDeviceInterface(device,&GUID_DEVINTERFACE_TPM,NULL);

        if(NT_SUCCESS(status))
        {
            WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
                                           &IoQueueConfig,
                                           WdfIoQueueDispatchParallel
                                           );
            IoQueueConfig.EvtIoDeviceControl = TpmEvtIoDeviceControl;

            status = WdfIoQueueCreate(
                              device,
                              &IoQueueConfig,
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &hQueue
                              );

            if(NT_SUCCESS(status))
            {

                WDF_DEVICE_POWER_CAPABILITIES_INIT(&PowerCaps);

                WdfDeviceSetPowerCapabilities(device,&PowerCaps);

                //
                TpmGetRegistryFlags(device,TpmContext);

                //
                RtlZeroMemory(&TpmInterface,sizeof(TpmInterface));
                TpmInterface.InterfaceHeader.Size = sizeof(TpmInterface);
                TpmInterface.InterfaceHeader.Version = 1;
                TpmInterface.InterfaceHeader.Context = (PVOID)TpmContext;

                TpmInterface.InterfaceHeader.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
                TpmInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
                TpmInterface.pfn_TpmSetMorBitState = TpmSetMorBitState;

                //
                // Initialize the InterfaceConfig structure.
                //
                WDF_QUERY_INTERFACE_CONFIG_INIT(
                                &InterfaceConfig,
                                (PINTERFACE)&TpmInterface,
                                &GUID_TPM_INTERFACE_STANDARD,
                                NULL
                                );

                //
                // Create the interface.
                //
                status = WdfDeviceAddQueryInterface(
                                                    device,
                                                    &InterfaceConfig
                                                    );
                if(!NT_SUCCESS(status))
                {
                    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                        "WdfDeviceAddQueryInterface failed with NTSTATUS 0x%x\n",status));
                }
            }
            else
            {
                KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                    "WdfIoQueueCreate failed with Status code 0x%x\n",status));
            }
        }
        else
        {
            KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                "WdfDeviceCreateDeviceInterface failed with Status code 0x%x\n",status));
        }
    }
    else
    {
        KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
                "WdfDeviceCreate failed with Status code 0x%x\n",status));
    }

    KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL,
            "TpmEvtDeviceAdd exited with Status code 0x%x\n",status));

    return status;
}
VOID EvtDriverUnload(_In_ WDFDRIVER DriverObject) {
	DriverObject;
	KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Driver Unloaded\n"));
}