none
Kernel Crash while accessing PCI express capability registers from PCI configuration space RRS feed

  • Question


  • I am new to driver development and presently working on a Windows Driver for a PCI express card.

    This card has a PCI express capability register. How do I access this ? I am using WDF  - KMDF driver design methodology.

    I followed MSDN reference given in this link and modified it for my requirement

    https://msdn.microsoft.com/en-us/windows/hardware/drivers/pci/accessing-pci-device-configuration-space?f=255&MSPPError=-2147217396

    So my code looks like below. I see a crash inside while loop. Am I doing this correctly ?

    NTSTATUS
     DevWaitTransPendBit(
    	IN	PDEVICE_CONTEXT    FdoData
    )
    {
    	PAGED_CODE();
    	NTSTATUS     status = STATUS_SUCCESS;
    	/* Wait for all transactions are finished before disabling/restting the device */
    
    	PCI_COMMON_HEADER Header;
    	PCI_COMMON_CONFIG *pPciConfig = (PCI_COMMON_CONFIG *)&Header;
    	
    	UCHAR CapabilityOffset;
    	DbgPrint("PCI_CAPABILITY_ID_PCI_EXPRESS\n");
    
    	FdoData->BusInterface.GetBusData(
    		FdoData->BusInterface.Context,
    		PCI_WHICHSPACE_CONFIG,
    		pPciConfig,
    		FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
    		0x90);
    
    	DbgPrint("==> PCI_CAP_REG 1\n");
    
    	if ((pPciConfig->Status &
    		PCI_STATUS_CAPABILITIES_LIST) == 0) {		
    		return(STATUS_NOT_IMPLEMENTED);
    	}
    
    	DbgPrint("==> PCI_CAP_REG 2\n");
    
    	if ((pPciConfig->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_BRIDGE_TYPE) {
    		CapabilityOffset = 	pPciConfig->u.type1.CapabilitiesPtr;
    	}
    	else if ((pPciConfig->HeaderType & (~PCI_MULTIFUNCTION)) == PCI_CARDBUS_BRIDGE_TYPE) {
    		CapabilityOffset = 	pPciConfig->u.type2.CapabilitiesPtr;
    	}
    	else {
    		DbgPrint("==> PCI_CAP_REG 3\n");
    		CapabilityOffset = 	pPciConfig->u.type0.CapabilitiesPtr;
    	}
    
    	DbgPrint("==> PCI_CAP_REG 4\n");
    	DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) UCHAR buffer[8];
    	PPCI_CAPABILITIES_HEADER pCapability = (PPCI_CAPABILITIES_HEADER)buffer;
    	DbgPrint("==> PCI_CAP_REG 5\n");
    
    	while (CapabilityOffset != 0) {    
    		DbgPrint("==> PCI_CAP_REG 6\n");      // Works fine till here
    
    		FdoData->BusInterface.GetBusData(     // this code leads to BSOD
    			FdoData->BusInterface.Context,
    			PCI_WHICHSPACE_CONFIG,
    			buffer,
    			CapabilityOffset,
    			sizeof(buffer));
    
    		DbgPrint("==> PCI_CAP_REG 7\n");
    
    		if (pCapability->CapabilityID ==
    			PCI_CAPABILITY_ID_PCI_EXPRESS) {
    			DbgPrint("found PCI_CAPABILITY_ID_PCI_EXPRESS \n");
    			break;
    		}
    		else {
    			DbgPrint("not found checking next Capability \n");
    			CapabilityOffset = pCapability->Next;
    		}
    	}
    
    	if (CapabilityOffset == 0) {
    		DbgPrint("PCI_CAPABILITY_ID_PCI_EXPRESS : Not Found \n");
    		return(STATUS_NOT_IMPLEMENTED);
    	}
    
    	DbgPrint("==> PCI_CAP_REG 8\n");
    	ULONG CSR; // Retrieve control status register to check for transaction pending bit. 
    
    	FdoData->BusInterface.GetBusData(
    		FdoData->BusInterface.Context,
    		PCI_WHICHSPACE_CONFIG,
    		&CSR,
    		(CapabilityOffset + 0x8),
    		sizeof(CSR));
    
    	DbgPrint("==> PCI_CAP_REG -9\n");
    	DbgPrint("CSR is: %u \n", CSR);
    
    	if (CSR & 0x00200000)
    		DbgPrint(" Transactions still pending \n"); /* if so wait in a while loop  using KeDelayExecutionThread() ? */
    
    	return status;
    }

    Also I  have confusion about how to access device status register from PCI configuration space .

    In Wdm.h  we have  PCI_CAPABILITIES_HEADER but there is not structure for PCI capabilities register.  However, there is structure for Power Management Capability.

    Also in ntddk.h  we can see a structure for  PCI_EXPRESS_DEVICE_STATUS_REGISTER --> How to access this in WDF driver code ?

    Thank you for the help.

    Steev




    Tuesday, April 4, 2017 12:29 PM

All replies

  • At what irql are you running? What is the output of !analyze -v ? How did you install the driver ? The most likely culprit is that FdoData->BusInterface.GetBusData is null

    d -- This posting is provided "AS IS" with no warranties, and confers no rights.

    Tuesday, April 4, 2017 2:31 PM
  • Your questions seem to be more about what the PCI Bus is doing than your device.   Most Windows drivers don't even worry about the PCI config space, and the registers you are asking about since the operating system takes care of the management for you.  

    What problem are you trying to solve by accessing these registers?   If you can tell the forum what your goal is in these accesses, we may be able to point out a better solution for this.   I have seen a number of Linux drivers and raw hardware test programs that use these, but when it comes time to make a functional Windows driver, I've never needed to access these.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Tuesday, April 4, 2017 2:48 PM
  • Thank you  for taking time to go through my question.

    Yes, I am from Linux background .

    Basically before resetting my device I want to make sure that there are no pending transactions .

    So our PCI device has device control and status register in PCI configuration space . This register has a transaction pending bit. I am trying to access this register value and then check that bit.

    Do you feel this step not required in Windows ? I will give a try without doing this.

    Thanks

    Steeva

    Wednesday, April 5, 2017 4:06 AM
  • What is triggering the reset?  Your driver in most cases has one or more active I/O Request's if anything is going on, if the reset is an also a request most drivers will design things to wait for the active requests to finish, and only then issue the reset.  Obviously, a lot depends on the design of the hardware, but most hardware I've encountered is either driven by I/O requests which then means the reset is normally controllable, or the rare piece of hardware which is highly asynchronous where a reset in general is not considered safe.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Wednesday, April 5, 2017 1:20 PM
  • I am resetting the device as part of the driver load process.

    As part of the driver load process I see following events:

    EvtDeviceD0Entry(),   then I call DevInit()  which calls DeviceHWReset()

    I feel can look into this later because this scenario does not come into picture during initial loading of the driver.

    Thanks, Steev

    Thursday, April 6, 2017 10:12 AM
  • As Doron pointed out the most common problem for your code would be that FdoData->BusInterface.GetBusData is null, or that your are running at an IRQL other than PASSIVE_LEVEL. 

    I'm still not sure you need this, EvtDeviceD0Entry occurs on startup, and coming out of hibernation or low power.  The later two cases typically don't occur while you are processing something, so why does the device need a reset when it starts processing again?  There are cases when this can happen, but they are not common.


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Thursday, April 6, 2017 2:14 PM