RTDECL(RTCPUID) RTMpCpuId(void) { /* WDK upgrade warning: PCR->Number changed from BYTE to WORD. */ return KeGetCurrentProcessorNumber(); }
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) { NDIS_STATUS status = NDIS_STATUS_FAILURE; NDIS_MINIPORT_DRIVER_CHARACTERISTICS chars; #ifdef DEBUG_TIMING LARGE_INTEGER TickCount; LARGE_INTEGER SysTime; #endif DEBUG_TIMING ParaNdis_DebugInitialize(); DEBUG_ENTRY(0); DPrintf(0, (__DATE__ " " __TIME__ "built %d.%d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION)); #ifdef DEBUG_TIMING KeQueryTickCount(&TickCount); NdisGetCurrentSystemTime(&SysTime); DPrintf(0, ("\n%s>> CPU #%d, perf-counter %I64d, tick count %I64d, NDIS_sys_time %I64d\n", __FUNCTION__, KeGetCurrentProcessorNumber(), KeQueryPerformanceCounter(NULL).QuadPart,TickCount.QuadPart, SysTime.QuadPart)); #endif NdisZeroMemory(&chars, sizeof(chars)); chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS; chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1; chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1; chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION; chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION; /* stupid thing, they are at least short */ chars.MajorDriverVersion = (UCHAR)(PARANDIS_MAJOR_DRIVER_VERSION & 0xFF); chars.MinorDriverVersion = (UCHAR)(PARANDIS_MINOR_DRIVER_VERSION & 0xFF); // possible value for regular miniport NDIS_WDM_DRIVER - for USB or 1394 // chars.Flags = 0; chars.InitializeHandlerEx = ParaNdis6_Initialize; chars.HaltHandlerEx = ParaNdis6_Halt; chars.UnloadHandler = ParaNdis6_Unload; chars.PauseHandler = ParaNdis6_Pause; chars.RestartHandler = ParaNdis6_Restart; chars.OidRequestHandler = ParaNdis6_OidRequest; chars.CancelOidRequestHandler = ParaNdis6_OidCancelRequest; chars.SendNetBufferListsHandler = ParaNdis6_SendNetBufferLists; chars.CancelSendHandler = ParaNdis6_CancelSendNetBufferLists; chars.ReturnNetBufferListsHandler = ParaNdis6_ReturnNetBufferLists; chars.CheckForHangHandlerEx = ParaNdis6_CheckForHang; chars.ResetHandlerEx = ParaNdis6_Reset; chars.ShutdownHandlerEx = ParaNdis6_AdapterShutdown; chars.DevicePnPEventNotifyHandler = ParaNdis6_DevicePnPEvent; chars.SetOptionsHandler = ParaNdis6_SetOptions; #if NDIS_SUPPORT_NDIS61 chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; chars.DirectOidRequestHandler = ParaNdis6x_DirectOidRequest; chars.CancelDirectOidRequestHandler = ParaNdis6x_CancelDirectOidRequest; #endif status = NdisMRegisterMiniportDriver( pDriverObject, pRegistryPath, NULL, &chars, &DriverHandle); if (status == NDIS_STATUS_SUCCESS) { RetrieveDriverConfiguration(); } DEBUG_EXIT_STATUS(status ? 0 : 4, status); return status; }
/** * Internal worker for the RTMpOn* APIs. * * @returns IPRT status code. * @param pfnWorker The callback. * @param pvUser1 User argument 1. * @param pvUser2 User argument 2. * @param enmCpuid What to do / is idCpu valid. * @param idCpu Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored. */ static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu) { PRTMPARGS pArgs; KDPC *paExecCpuDpcs; #if 0 /* KeFlushQueuedDpcs must be run at IRQL PASSIVE_LEVEL according to MSDN, but the * driver verifier doesn't complain... */ AssertMsg(KeGetCurrentIrql() == PASSIVE_LEVEL, ("%d != %d (PASSIVE_LEVEL)\n", KeGetCurrentIrql(), PASSIVE_LEVEL)); #endif #ifdef IPRT_TARGET_NT4 KAFFINITY Mask; /* g_pfnrtNt* are not present on NT anyway. */ return VERR_NOT_SUPPORTED; #else KAFFINITY Mask = KeQueryActiveProcessors(); #endif /* KeFlushQueuedDpcs is not present in Windows 2000; import it dynamically so we can just fail this call. */ if (!g_pfnrtNtKeFlushQueuedDpcs) return VERR_NOT_SUPPORTED; pArgs = (PRTMPARGS)ExAllocatePoolWithTag(NonPagedPool, MAXIMUM_PROCESSORS*sizeof(KDPC) + sizeof(RTMPARGS), (ULONG)'RTMp'); if (!pArgs) return VERR_NO_MEMORY; pArgs->pfnWorker = pfnWorker; pArgs->pvUser1 = pvUser1; pArgs->pvUser2 = pvUser2; pArgs->idCpu = NIL_RTCPUID; pArgs->cHits = 0; pArgs->cRefs = 1; paExecCpuDpcs = (KDPC *)(pArgs + 1); if (enmCpuid == RT_NT_CPUID_SPECIFIC) { KeInitializeDpc(&paExecCpuDpcs[0], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[0], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[0], (int)idCpu); } else { for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++) { KeInitializeDpc(&paExecCpuDpcs[i], rtmpNtDPCWrapper, pArgs); KeSetImportanceDpc(&paExecCpuDpcs[i], HighImportance); KeSetTargetProcessorDpc(&paExecCpuDpcs[i], i); } } /* Raise the IRQL to DISPATCH_LEVEL so we can't be rescheduled to another cpu. * KeInsertQueueDpc must also be executed at IRQL >= DISPATCH_LEVEL. */ KIRQL oldIrql; KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); /* * We cannot do other than assume a 1:1 relationship between the * affinity mask and the process despite the warnings in the docs. * If someone knows a better way to get this done, please let bird know. */ ASMCompilerBarrier(); /* paranoia */ if (enmCpuid == RT_NT_CPUID_SPECIFIC) { ASMAtomicIncS32(&pArgs->cRefs); BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[0], 0, 0); Assert(ret); } else { unsigned iSelf = KeGetCurrentProcessorNumber(); for (unsigned i = 0; i < MAXIMUM_PROCESSORS; i++) { if ( (i != iSelf) && (Mask & RT_BIT_64(i))) { ASMAtomicIncS32(&pArgs->cRefs); BOOLEAN ret = KeInsertQueueDpc(&paExecCpuDpcs[i], 0, 0); Assert(ret); } } if (enmCpuid != RT_NT_CPUID_OTHERS) pfnWorker(iSelf, pvUser1, pvUser2); } KeLowerIrql(oldIrql); /* Flush all DPCs and wait for completion. (can take long!) */ /** @todo Consider changing this to an active wait using some atomic inc/dec * stuff (and check for the current cpu above in the specific case). */ /** @todo Seems KeFlushQueuedDpcs doesn't wait for the DPCs to be completely * executed. Seen pArgs being freed while some CPU was using it before * cRefs was added. */ g_pfnrtNtKeFlushQueuedDpcs(); /* Dereference the argument structure. */ int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs); Assert(cRefs >= 0); if (cRefs == 0) ExFreePool(pArgs); return VINF_SUCCESS; }