none
NDIS Miniport Interrupt Synchronization confusion ? RRS feed

  • Question

  • My miniport driver needs to access the NIC registers to enable/disable interrupts or to check if the interrupt was raised by the NIC or not.  While I was going through the NDIS docs, I came across this statement : Typically, MiniportEnableInterruptEx and MiniportDisableInterruptEx access miniport driver resources that are shared by the MiniportInterrupt function. Therefore, NDIS calls these handlers at DIRQL.

    So do I need to still synchronize my NdisRead/Write register functions by using the Miniport Synchronize Interrupt function handler provided by NDIS ? 


    With regards, Jenson Alex Pais

    Monday, September 26, 2016 1:58 PM

Answers

  • The docs should have mentioned that when it calls Miniport{Enable|DisableInterrupt}Ex at DIRQL, it also holds the interrupt object spinlock. You don't need to do any additional synchronization

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Monday, September 26, 2016 7:25 PM
    Moderator

All replies

  • The docs should have mentioned that when it calls Miniport{Enable|DisableInterrupt}Ex at DIRQL, it also holds the interrupt object spinlock. You don't need to do any additional synchronization

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Monday, September 26, 2016 7:25 PM
    Moderator
  • Thanks Brian for the prompt reply. So will the interrupt object spinlock protect the NIC read/write access done from these function calls ? Also let me know if I have used the synchronize interrupt calls in the wrong manner. 

    BOOLEAN HwInterruptRecognized(__in  PMP_ADAPTER Adapter)
    {
            return NdisMSynchronizeWithInterruptEx(
            Adapter->NdisInterruptHandle,
            0,
            HwInterruptRecognizedWithSync,
            (PVOID) Adapter);   
    }
    
    BOOLEAN HwInterruptRecognizedWithSync(__in PMP_ADAPTER Adapter)
    /**
     * Routine description: Recognize the interrupt to be serviced.
     * Arguments: Adapter - Adapter to the miniport 
     * Return values: TRUE - If interrupt relevant to this ISR.
     *                FALSE - If interrupt not generated by the NIC.
     **/ 
    {
    	ULONG isrVal, msrRead;
    
    	// Read the ISR value from the hardware to decide if the ISR needs to be notified or not.
    	//
    	
    	msrRead = HWReadMSR(Adapter);
            isrVal = msrRead & INTR_MSK;         // Mask the interrupt value read from main status register.
    
    	DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL,  "[%p]***IsrVal in HwIntrRecognized*** = 0x%lx\n ", Adapter, isrVal);
    	// HAL specific ISR processing
    	//
    
    	if(isrVal)
    	{
    		// Need a DPC to handle this interrupt
    		//
    		Adapter->InterruptReg = isrVal;
    		return TRUE;
    	}
    	else
    	{
    		return FALSE;
    	}
    }
    ps: MSR is read clear so whatever is read is stored into the Adapter->InterruptReg to be accessed in the Interrupt DPC. 


    With regards, Jenson Alex Pais





    • Edited by JENSON PAIS Wednesday, October 5, 2016 6:24 AM
    Tuesday, September 27, 2016 4:54 AM
  • It is not clear why you want to protect reading the "main status register". Does the DPC write to it? 

    Access to Adapter->InterruptReg can be made atomic, if you use InterlockedOr.

    IMHO all this activity in the ISR can be made lockless (besides of the interrupt object locking, the OS will do that anyway).

    -- pa

    Tuesday, September 27, 2016 12:33 PM
  • Pavel,

    The DPC only needs to read the value from the main status register. But since it's read clear and we are already reading from the ISR to decipher if the interrupt generated was by our NIC or not. 

    Will look into InterlockedOr.

    I was trying to keep it all lockless. But the ISR was preempting DPC if they were queued. I probably need to keep a count of disables and enables of the interrupt then ?

    Cheers once again Pavel. Also I had replied to your query in the this thread: Receive Side DMA. Need some clarifications there too. 


    With regards, Jenson Alex Pais



    • Edited by JENSON PAIS Tuesday, September 27, 2016 1:05 PM
    Tuesday, September 27, 2016 12:42 PM
  • One of the things I tell my students is to never, ever have device registers with read side-effects. This makes debugging extremely difficult.

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Tuesday, September 27, 2016 5:29 PM
    Moderator
  • Brian,

    I would agree with the debugging issue. Unfortunately, I'll have to live with it. As the NIC is in the testing facility along with the Linux driver, changes cannot be made on the H/W side. Instead of synchronizing the interrupts by simplifying the ISR and saving the interrupt status for the DPC. So there is no need to 

    Also, does the protocol driver provide the Ethernet/MAC header to the Ethernet frame it sends down in the net buffer or do I need to add the header myself in the miniport driver ? As far as I know the NDIS provides the net buffer with the ethernet header (14 bytes) + IP Header (20 bytes) + TCP Header. Please correct me if I'm wrong !!!

    Also, I did forget to ask on the other thread. I have followed your suggestions and implemented the receive side. Just one question, while indicating ethernet receives. Am I better off getting a NBL from a NBL pool allocated during initialization and indicating a list of NBLs. Or instead use your advice of using NdisAllocateNetBufferAndNetBufferList. and indicate the single NBL for each frame received. 

    With regards, Jenson Alex Pais


    • Edited by JENSON PAIS Wednesday, September 28, 2016 9:40 AM Added about RX indicate
    Wednesday, September 28, 2016 4:45 AM
  • Yes, the media-specific header will already be part of the outgoing NBLs that you receive. The job of the miniport driver is just to squirt the packets into the network. It is always better to indicate a list of packets rather than indicating each one individually, because that reduces the number of times you have to traverse the network stack.

    It is rare that explanations and examples of a concept are also the most efficient, but if I explained it exactly how I would write it, you wouldn't understand it without thousands of words of explanation and many days of study.

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Wednesday, September 28, 2016 6:25 PM
    Moderator
  • Hi Brian,

    Thanks once again for all the information and knowledge transfer that you have provided me with. Has been very helpful. Transmission side seems to be working along with pings. Discovery packets were sent when the miniport adapter installed. ARP generated by the pings were received by the destination IP and wireshark/network monitor did show them. ARP wasn't getting resolved but the issue seems to be with the size I'm allocating while creating the MDL and NetBuffer. Receive side the size of the ARP was varying, so trying to fix that part of code. 

    One thing that has baffled me is that the debugee machine's wireshark/net mon couldn't detect our adapter until I restarted the system. Also if I try to change the IPV4 to static address. It doesn't seem to change, sometimes the com surrogate fails and the UI freezes. Is there any link to the miniport driver here ?


    With regards, Jenson Alex Pais



    • Edited by JENSON PAIS Wednesday, October 5, 2016 6:38 AM
    Wednesday, October 5, 2016 6:35 AM
  • You're welcome :-)

    This sort of problem is very hard to debug remotely. You're probably not filling in one of the NDIS attributes structures properly. Enable NDIS tracing as described here. Enable the INFO level of tracing on all components, initially. You're going to see a ton of trace messages, but the reason should be in there.

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Wednesday, October 5, 2016 6:26 PM
    Moderator
  • Cheers once again for the info, Brian.

    I am not using a checked build of ndis.sys. But since it's NDIS tracing, I reckon it should still print the trace messages  ? 

    Also is there a reason why ndisParseReceivedNBL might cause a crash. Is it because there is cache tearing in the data or the mdl allocated is wrong ? Happened once in 10 times. But I am still in initial testing phase. 


    With regards, Jenson Alex Pais

    Thursday, October 6, 2016 5:35 AM
  • Yes, tracing is independent of whether it is a checked or free build - in fact, that is specifically the point.

    ndisParseReceivedNBL attempts to parse the datalink header to get the destination address. Without seeing the output of !analyze, I cannot offer more insight than to have you examine all your pointers and data structures. Cache line tearing won't cause a corruption, just a performance penalty

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Thursday, October 6, 2016 5:41 AM
    Moderator
  • This is what I could gather from !analyze 

    CURRENT_IRQL:  0
    
    FAULTING_IP: 
    ndis!ndisParseReceivedNBL+c8
    8c6d82ef 8a500d          mov     dl,byte ptr [eax+0Dh]
    
    DEFAULT_BUCKET_ID:  VISTA_DRIVER_FAULT
    
    BUGCHECK_STR:  0xD1
    
    TRAP_FRAME:  8e5f4870 -- (.trap 0xffffffff8e5f4870)
    ErrCode = 00000000
    eax=a0c02000 ebx=0000005a ecx=88ab01e8 edx=00000000 esi=00000000 edi=858835c0
    eip=8c6d82ef esp=8e5f48e4 ebp=8e5f48f4 iopl=0         nv up ei ng nz na pe nc
    cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010286
    ndis!ndisParseReceivedNBL+0xc8:
    8c6d82ef 8a500d          mov     dl,byte ptr [eax+0Dh]      ds:0023:a0c0200d=??
    Resetting default scope
    
    LAST_CONTROL_TRANSFER:  from 82d25ce7 to 82cc1308
    
    STACK_TEXT:  
    8e5f443c 82d25ce7 00000003 a8e2319f 00000065 nt!RtlpBreakWithStatusInstruction
    8e5f448c 82d267e5 00000003 a0c0200d 8c6d82ef nt!KiBugCheckDebugBreak+0x1c
    8e5f4850 82c86cbf 0000000a a0c0200d 00000002 nt!KeBugCheck2+0x68b
    8e5f4850 8c6d82ef 0000000a a0c0200d 00000002 nt!KiTrap0E+0x1b3
    8e5f48f4 8c6d8084 0000005a 858835c0 8e5f4938 ndis!ndisParseReceivedNBL+0xc8
    8e5f4940 8c6d8457 005f4958 858835c0 86051260 ndis!ndisSortNetBufferLists+0x7f
    8e5f4abc 8c683c1d 8858f0e0 00000000 00000000 ndis!ndisMDispatchReceiveNetBufferLists+0xce
    8e5f4ad8 8c6b456a 8858f0e0 858835c0 00000000 ndis!ndisMTopReceiveNetBufferLists+0x2d
    8e5f4af4 8c6b4504 8665dc70 858835c0 00000000 ndis!ndisFilterIndicateReceiveNetBufferLists+0x46
    8e5f4b10 91f0e553 8665dc70 858835c0 00000000 ndis!NdisFIndicateReceiveNetBufferLists+0x2f
    8e5f4b7c 8c6d8553 86051260 858835c0 00000000 nm3!NetmonReceiveNetBufferLists+0x1b3
    8e5f4ba4 8c683c78 8858f0e0 858835c0 00000000 ndis!ndisMIndicateReceiveNetBufferListsInternal+0x62
    8e5f4bcc 989cc5df 8858f0e0 858835c0 00000000 ndis!NdisMIndicateReceiveNetBufferLists+0x52
    8e5f4c14 8c6d889a 86163100 00000000 8e5f4c40 smigmptest620!MpInterruptDPC+0x34f [d:\prodigy-smig-windriver\mpisr.c @ 303]
    8e5f4c50 8c683a0f eb27a93c 0027a928 00000000 ndis!ndisMiniportDpc+0xe2
    8e5f4c78 82cbe015 eb27a93c eb27a928 00000000 ndis!ndisInterruptDpc+0xaf
    8e5f4cd4 82cbde78 8e5d8120 8e5dd800 00000000 nt!KiExecuteAllDpcs+0xf9
    8e5f4d20 82cbdc98 00000000 0000000e 00000000 nt!KiRetireDpcList+0xd5
    8e5f4d24 00000000 0000000e 00000000 00000000 nt!KiIdleLoop+0x38

    I'll look at the pointers and data structures. ReturnNetBufferList returns only the NBLs that have been already used by NDIS right ? Because I was freeing the NetBuffer and NBL allocated using the NdisAllocateNetBufferAndNetBufferList call in that routine.


    With regards, Jenson Alex Pais

    Thursday, October 6, 2016 5:46 AM
  • It is hard to say (always do '!analyze -v' and then a 'kv'), but you may be right about the MDL being messed up

     -Brian


    Azius Developer Training www.azius.com Windows device driver, internals, security, & forensics training and consulting. Blog at www.azius.com/blog

    Thursday, October 6, 2016 5:50 AM
    Moderator