Exemple #1
0
void WmipWaitForCollectionEnabled(
    PBGUIDENTRY GuidEntry
    )
{
    PAGED_CODE();
    
    WmipAssert((GuidEntry->Flags & GE_FLAG_COLLECTION_IN_PROGRESS) ==
                   GE_FLAG_COLLECTION_IN_PROGRESS);
    
    //
    // Collection Enable/Disable is in progress so
    // we cannot return just yet. Right now there could be a 
    // disable request being processed and if we didn't wait, we
    // might get back to this caller before that disable request
    // got around to realizing that it needs to send and enable 
    // request (needed by this thread's caller). So we'd have a 
    // situation where a thread though that collection was enabled
    // but in reality it wasn't yet enabled.
    if ((GuidEntry->Flags & GE_FLAG_WAIT_ENABLED) == 0)
    {
        KeInitializeEvent(GuidEntry->CollectInProgress, 
                          NotificationEvent,
                          FALSE);
        GuidEntry->Flags |= GE_FLAG_WAIT_ENABLED;
        WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p for %p %x created event\n",
                                 PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                                 GuidEntry,
                                 GuidEntry->Flags));
    }
            
    WmipLeaveSMCritSection();
    WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p waiting for %p %x on event\n",
                                 PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                                     GuidEntry,
                                     GuidEntry->Flags));
    KeWaitForSingleObject(GuidEntry->CollectInProgress, 
                          Executive,
                          KernelMode,
                          FALSE,
                          NULL);
    WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p done %p %x waiting on event\n",
                                 PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                                     GuidEntry,
                                     GuidEntry->Flags));
    WmipEnterSMCritSection();
    
}
Exemple #2
0
NTSTATUS
WmipConstructMCAErrorEvent(
    IN PMCA_EXCEPTION McaException,
    IN ULONG ErrorLogSize,
    IN OUT PWNODE_SINGLE_INSTANCE Wnode,
    IN OUT PMSMCAEvent_Header Header,
    IN OUT PUCHAR *RawPtr,
    IN OUT BOOLEAN *IsFatal
    )
/*++

Routine Description:

    This routine attempts to build an MCA error log event from the information
    in the supplied MCA_EXCEPTION.

Arguments:

    McaException - Pointer to a MCA_EXCEPTION that encapsulates the machine
                   check event.
    
    ErrorLogSize - The total size in bytes of the raw error information.

    Wnode        - Pointer to the error event WNODE.

    Header       - Pointer to the common header for all MCA events.

    RawPtr       - Address into which a pointer to the raw MCA data is to
                   be copied.

Return Value:

    STATUS_SUCCESS - If an event is successfully constructed.
    
    STATUS_NOT_SUPPORTED - If the routine does not create an event.

--*/
{
    PMSMCAEvent_MemoryHierarchyError memoryEvent;
    PMSMCAEvent_InvalidError invalidEvent;
    PMSMCAEvent_TLBError tlbEvent;
    PMSMCAEvent_BusError busEvent;
    NTSTATUS status;
    ULONG mcaCode;
    
    PAGED_CODE();

    if (*IsFatal) {
        if (McaException->ExceptionType == HAL_MCA_RECORD) {
            if (!McaException->u.Mca.Status.MciStats.UnCorrected) {
                *IsFatal = FALSE;
            }
        }
    }

    //
    // Sanity checks on the size of the event structures. None should be
    // larger than the size of a memory error event.
    //
    WmipAssert(sizeof(MSMCAEvent_MemoryError) >=
               sizeof(MSMCAEvent_InvalidError));
    WmipAssert(sizeof(MSMCAEvent_MemoryError) >=
               sizeof(MSMCAEvent_MemoryHierarchyError));
    WmipAssert(sizeof(MSMCAEvent_MemoryError) >=
               sizeof(MSMCAEvent_TLBError));
    WmipAssert(sizeof(MSMCAEvent_MemoryError) >=
               sizeof(MSMCAEvent_BusError));

    //
    // This routine is only to be called whe the MCA status bits are valid.
    //
    WmipAssert(McaException->u.Mca.Status.MciStats.Valid);
    mcaCode = McaException->u.Mca.Status.MciStats.McaCod;
    status = STATUS_SUCCESS;

    if (mcaCode == MCA_CODE_MICROCODE_ROM_PARITY_ERROR ||
        mcaCode == MCA_CODE_EXTERNAL_ERROR ||
        mcaCode == MCA_CODE_FRC_ERROR ||
        mcaCode == MCA_CODE_INTERNAL_TIMER_ERROR) {

        //
        // For Microcode ROM parity errors, external errors, FRC errors, and 
        // internal timer errors, we will use the InvalidError event since it
        // is useful for generating error events with no parameters.
        //
        invalidEvent = (PMSMCAEvent_InvalidError)Header;

        //
        // Indicate the error type.
        //
        if (mcaCode == MCA_CODE_MICROCODE_ROM_PARITY_ERROR) {
            invalidEvent->Type = (ULONG)MCA_MICROCODE_ROM_PARITY_ERROR;
        } else if (mcaCode == MCA_CODE_EXTERNAL_ERROR) {
            invalidEvent->Type = (ULONG)MCA_EXTERNAL_ERROR;
        } else if (mcaCode == MCA_CODE_FRC_ERROR) {
            invalidEvent->Type = (ULONG)MCA_FRC_ERROR;
        } else {
            invalidEvent->Type = (ULONG)MCA_INTERNALTIMER_ERROR;
        }

        //
        // Fill in the GUID and the size of the data block.
        //
        Wnode->WnodeHeader.Guid = WmipMSMCAEvent_InvalidErrGuid;
        Wnode->SizeDataBlock = 
            FIELD_OFFSET(MSMCAEvent_InvalidError, RawRecord) + ErrorLogSize;

        //
        // Copy the address of the raw record into the supplied address.
        //
        *RawPtr = invalidEvent->RawRecord;

        //
        // Indicate the size of the entire record.
        //
        invalidEvent->Size = ErrorLogSize;

    } else if (mcaCode & MCA_CODE_BUS_ERR_MASK) {

        //
        // Bus/Interconnect error. Extract the details of the error information
        // from the preserved MCI_STATS and save it in the bus error event.
        //

        busEvent = (PMSMCAEvent_BusError)Header;

        if (mcaCode & 0x0100) {
            busEvent->Type = (ULONG)MCA_BUS_TIMEOUT_ERROR;
        } else {
            busEvent->Type = (ULONG)MCA_BUS_ERROR;
        }

        busEvent->Participation = ((mcaCode & 0x00000600) >> 9);
        busEvent->MemoryHierarchyLevel = (mcaCode & 0x00000003);
        busEvent->RequestType = ((mcaCode & 0x000000F0) >> 4);
        busEvent->MemOrIo = ((mcaCode & 0x0000000C) >> 2);

        if (McaException->u.Mca.Status.MciStats.AddressValid) {
            busEvent->Address = McaException->u.Mca.Address.QuadPart;
        } else {
            busEvent->Address = (ULONG64)0; 
        }

        Wnode->WnodeHeader.Guid = WmipMSMCAEvent_BusErrorGuid;
        Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_BusError,
                                            RawRecord) + ErrorLogSize;

        busEvent->Size = ErrorLogSize;
        *RawPtr = busEvent->RawRecord;

    } else if (mcaCode & MCA_CODE_MEM_HIERARCHY_ERR_MASK) {
Exemple #3
0
ULONG WmipSendDisableRequest(
    PBGUIDENTRY GuidEntry,
    BOOLEAN IsEvent,
    BOOLEAN IsTraceLog,
    ULONG64 LoggerContext
    )
/*++
Routine Description:

    This routine will send an disable collection or notification request to
    all of the data providers that have registered the guid being disabled.
    This routine will manage any race conditions that might occur when
    multiple threads are enabling and disabling the notification
    simultaneously.

    This routine is called while the SM critical section is being held and
    will increment the appropriate reference count. if the ref count
    transitions from 1 to 0 then the disable request will need to be forwarded
    to the data providers otherwise the routine is all done and returns.
    Before sending the disable request the routine checks to see if any
    enable or disable requests are currently in progress and if not then sets
    the in progress flag, releases the critical section and sends the disable
    request. If there was a request in progress then the routine does not
    send a request, but just returns. When the other thread that was sending
    the request returns from processing the request it will recheck the
    refcount and notice that it is  0 and then send the disable
    request.


Arguments:

    GuidEntry is the Notification entry that describes the guid
        being enabled.

    GuidEntry is the guid entry that describes the guid being enabled. For
        a notification it may be NULL.

    NotificationContext is the notification context to use if enabling events

    IsEvent is TRUE if notifications are being enables else FALSE if
        collection is being enabled

    IsTraceLog is TRUE if enable is for a trace log guid

    LoggerContext is a context value to forward in the enable request

Return Value:

    ERROR_SUCCESS or an error code
--*/
{
    ULONG InProgressFlag;
    ULONG RefCount;
    ULONG Status;

    PAGED_CODE();
    
    if (IsEvent)
    {
        InProgressFlag = GE_FLAG_NOTIFICATION_IN_PROGRESS;
        RefCount = GuidEntry->EventRefCount;
        if (RefCount == 0)
        {
            //
            // A bad data consumer is disabling his event more
            // than once. Just ignore it
            return(STATUS_SUCCESS);
        }

        RefCount = --GuidEntry->EventRefCount;
    } else {
        WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p Disabling for %p %x\n",
                                 PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                                 GuidEntry,
                                 GuidEntry->Flags));
        InProgressFlag = GE_FLAG_COLLECTION_IN_PROGRESS;
        RefCount = --GuidEntry->CollectRefCount;
        WmipAssert(RefCount != 0xffffffff);
    }

    //
    // If we have transitioned to a refcount of zero and there is
    // not a request in progress then forward the disable request.
    if ((RefCount == 0) &&
        ! (GuidEntry->Flags & InProgressFlag))
    {

        //
        // Take an extra ref count so that even if this gets
        // disabled while the disable request is in progress the
        // GuidEntry will stay valid.
        GuidEntry->Flags |= InProgressFlag;
        WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p NE %p flags -> %x at %d\n",
                  PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                  GuidEntry,
                  GuidEntry->Flags,
                  __LINE__));

        Status = WmipDoDisableRequest(GuidEntry,
                                      IsEvent,
                                      IsTraceLog,
                                      LoggerContext,
                                      InProgressFlag);
                                  
    } else {
        Status = STATUS_SUCCESS;
    }

    if (! IsEvent)
    {
        WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p.%p Disable complete for %p %x\n",
                                 PsGetCurrentProcessId(), PsGetCurrentThreadId(),
                                 GuidEntry,
                                 GuidEntry->Flags));
    }
    return(Status);
}
Exemple #4
0
NTSTATUS WmipSendEnableDisableRequest(
    UCHAR ActionCode,
    PBGUIDENTRY GuidEntry,
    BOOLEAN IsEvent,
    BOOLEAN IsTraceLog,
    ULONG64 LoggerContext
    )
/*++

Routine Description:

    This routine will deliver an event or collection WNODE to all data
    providers of a guid. This routine assumes that it is called with the
    SM critical section held. The routine does not hold the critical
    section for the duration of the call.

Arguments:

    ActionCode is WMI_ENABLE_EVENTS, WMI_DISABLE_EVENTS,
        WMI_ENABLE_COLLECTION or WMI_DISABLE_COLLECTION

    GuidEntry is the guid entry for the guid that is being enabled/disable
        or collected/stop collected

    IsEvent is TRUE then ActionCode is to enable or disable events.
        If FALSE then ActionCode is to enable or disbale collecton

    IsTraceLog is TRUE then enable is only sent to those guids registered as
        being a tracelog guid

    LoggerContext is a logger context handle that should be placed in the
        HistoricalContext field of the WNODE_HEADER if IsTraceLog is TRUE.

Return Value:

    ERROR_SUCCESS or an error code

--*/
{
#if DBG
#define AVGISPERGUID 1
#else
#define AVGISPERGUID 64
#endif

    PLIST_ENTRY InstanceSetList;
    PBINSTANCESET InstanceSet;
    PBDATASOURCE DataSourceArray[AVGISPERGUID];
    PBDATASOURCE *DataSourceList;
    ULONG BufferSize;
    ULONG Status = 0;
    PWNODE_HEADER pWnode;
    ULONG i;
    PBDATASOURCE DataSource;
    ULONG DSCount;
    BOOLEAN IsEnable;
    ULONG IsFlags, IsUpdate;

    WMITRACE_NOTIFY_HEADER  TraceNotifyHeader;

    PAGED_CODE();

    if (GuidEntry->Flags & GE_FLAG_INTERNAL)
    {
        //
        // Guids that have been unregistered and Internally defined guids
        // have no data source to send requests to, so just leave happily
        return(STATUS_SUCCESS);
    }
            

    IsEnable = ((ActionCode == IRP_MN_ENABLE_EVENTS) ||
                (ActionCode == IRP_MN_ENABLE_COLLECTION));
    IsFlags = IsEvent ? IS_ENABLE_EVENT : IS_ENABLE_COLLECTION;

    //
    // Determine whether this is an update call and reset the bit
    //
    IsUpdate = (GuidEntry->Flags & GE_NOTIFICATION_TRACE_UPDATE);


    //
    // First we make a list of all of the DataSources that need to be called
    // while we have the critical section and take a reference on them so
    // they don't go away after we release them. Note that the DataSource
    // structure will stay, but the actual data provider may in fact go away.
    // In this case sending the request will fail.
    DSCount = 0;

    if (GuidEntry->ISCount > AVGISPERGUID)
    {
        DataSourceList = WmipAlloc(GuidEntry->ISCount * sizeof(PBDATASOURCE));
        if (DataSourceList == NULL)
        {
            WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: alloc failed for DataSource array in WmipSendEnableDisableRequest\n"));

            return(STATUS_INSUFFICIENT_RESOURCES);
        }
    } else {
        DataSourceList = &DataSourceArray[0];
    }
#if DBG
    memset(DataSourceList, 0, GuidEntry->ISCount * sizeof(PBDATASOURCE));
#endif

    InstanceSetList = GuidEntry->ISHead.Flink;
    while ((InstanceSetList != &GuidEntry->ISHead) &&
           (DSCount < GuidEntry->ISCount))
    {
        WmipAssert(DSCount < GuidEntry->ISCount);
        InstanceSet = CONTAINING_RECORD(InstanceSetList,
                                        INSTANCESET,
                                        GuidISList);


        //
        // We send requests to those data providers that are not inprocs when
        // it is an event being enabled or it is collection being enabled
        // and they are defined to be expensive (collection needs to be
        // enabled)
        if (
             ( (IsTraceLog && (InstanceSet->Flags & IS_TRACED)) ||
               ( ! IsTraceLog && (! (InstanceSet->Flags & IS_TRACED)) &&
                 (IsEvent || (InstanceSet->Flags & IS_EXPENSIVE))
               )
             )
           )
        {

            if ( (! IsEnable && (InstanceSet->Flags & IsFlags)) ||
                 ((IsEnable && ! (InstanceSet->Flags & IsFlags)) ||
                 (IsUpdate && IsTraceLog))
               )
            {
                DataSourceList[DSCount] = InstanceSet->DataSource;
                WmipReferenceDS(DataSourceList[DSCount]);
                DSCount++;
            }

            if (IsEnable)
            {
                InstanceSet->Flags |= IsFlags;
            } else {
                InstanceSet->Flags &= ~IsFlags;
            }
        }

        InstanceSetList = InstanceSetList->Flink;
    }


    if (IsUpdate) 
    { 
        GuidEntry->Flags &= ~GE_NOTIFICATION_TRACE_UPDATE;
    }


    WmipLeaveSMCritSection();

    //
    // Now without the critical section we send the request to all of the
    // data providers. Any new data providers who register after we made our
    // list will be enabled by the registration code.
    if (DSCount > 0)
    {
        pWnode = &TraceNotifyHeader.Wnode;
        RtlZeroMemory(pWnode, sizeof(TraceNotifyHeader));
        RtlCopyMemory(&pWnode->Guid, &GuidEntry->Guid, sizeof(GUID));
        BufferSize = sizeof(WNODE_HEADER);

        if (IsTraceLog)
        {
            BufferSize = sizeof(TraceNotifyHeader);
            TraceNotifyHeader.LoggerContext = LoggerContext;
            pWnode->Flags |= WNODE_FLAG_TRACED_GUID;
            //
            // If this GUID is already enabled then this must 
            // an update call. So mark it so. 
            // 
            if ( IsEnable &&  IsUpdate ) {
                pWnode->ClientContext = IsUpdate;
            }

        }
        pWnode->BufferSize = BufferSize;

        for (i = 0; i < DSCount; i++)
        {
            DataSource = DataSourceList[i];
            WmipAssert(DataSource != NULL);
            if (IsTraceLog) {
                if (DataSource->Flags & DS_KERNEL_MODE) {
                    pWnode->HistoricalContext = LoggerContext;
                }
                else if (DataSource->Flags & DS_USER_MODE) {
                    pWnode->HistoricalContext = 0;
                }
                else {
                    ASSERT(FALSE);
                }
            }
                                
            Status |= WmipDeliverWnodeToDS(ActionCode, 
                                          DataSource, 
                                          pWnode,
                                          BufferSize);
            

            WmipUnreferenceDS(DataSource);
        }
    }

    if( ! IsTraceLog )
    {

        Status = STATUS_SUCCESS;
    }

    if (DataSourceList != DataSourceArray)
    {
        WmipFree(DataSourceList);
    }

    WmipEnterSMCritSection();

    return(Status);
}