Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1624 lines
46 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. callouts.c
  5. Abstract:
  6. This is the source file that contains all the callout routines
  7. from the kernel itself. The only exception is TraceIo for DiskPerf.
  8. Author:
  9. Jee Fung Pang (jeepang) 03-Dec-1996
  10. Revision History:
  11. --*/
  12. #pragma warning(disable:4214)
  13. #pragma warning(disable:4115)
  14. #pragma warning(disable:4201)
  15. #pragma warning(disable:4127)
  16. #include <stdio.h>
  17. #include <ntos.h>
  18. #include <zwapi.h>
  19. #ifdef NTPERF
  20. #include <ntdddisk.h>
  21. #endif
  22. #include <evntrace.h>
  23. #include "wmikmp.h"
  24. #include "tracep.h"
  25. #pragma warning(default:4214)
  26. #pragma warning(default:4115)
  27. #pragma warning(default:4201)
  28. #pragma warning(default:4127)
  29. #ifndef _WMIKM_
  30. #define _WMIKM_
  31. #endif
  32. VOID
  33. FASTCALL
  34. WmipTracePageFault(
  35. IN NTSTATUS Status,
  36. IN PVOID VirtualAddress,
  37. IN PVOID TrapFrame
  38. );
  39. VOID
  40. WmipTraceNetwork(
  41. IN ULONG GroupType,
  42. IN PVOID EventInfo,
  43. IN ULONG EventInfoLen,
  44. IN PVOID Reserved
  45. );
  46. VOID
  47. WmipTraceIo(
  48. IN ULONG DiskNumber,
  49. IN PIRP Irp,
  50. IN PVOID Counters
  51. );
  52. VOID
  53. WmipTraceFile(
  54. IN PKAPC Apc,
  55. IN PKNORMAL_ROUTINE *NormalRoutine,
  56. IN PVOID *NormalContext,
  57. IN PVOID *SystemArgument1,
  58. IN PVOID *SystemArgument2
  59. );
  60. VOID
  61. WmipTraceLoadImage(
  62. IN PUNICODE_STRING ImageName,
  63. IN HANDLE ProcessId,
  64. IN PIMAGE_INFO ImageInfo
  65. );
  66. VOID
  67. WmipTraceRegistry(
  68. IN NTSTATUS Status,
  69. IN PVOID Kcb,
  70. IN LONGLONG ElapsedTime,
  71. IN ULONG Index,
  72. IN PUNICODE_STRING KeyName,
  73. IN UCHAR Type
  74. );
  75. #ifdef ALLOC_PRAGMA
  76. #pragma alloc_text(PAGEWMI, WmipIsLoggerOn)
  77. #pragma alloc_text(PAGE, WmipEnableKernelTrace)
  78. #pragma alloc_text(PAGE, WmipDisableKernelTrace)
  79. #pragma alloc_text(PAGE, WmipSetTraceNotify)
  80. #pragma alloc_text(PAGE, WmiTraceProcess)
  81. #pragma alloc_text(PAGE, WmiTraceThread)
  82. #pragma alloc_text(PAGE, WmipTraceFile)
  83. #pragma alloc_text(PAGE, WmipTraceLoadImage)
  84. #pragma alloc_text(PAGE, WmipTraceRegistry)
  85. #pragma alloc_text(PAGEWMI, WmipTracePageFault)
  86. #pragma alloc_text(PAGEWMI, WmipTraceNetwork)
  87. #pragma alloc_text(PAGEWMI, WmipTraceIo)
  88. #pragma alloc_text(PAGEWMI, WmiTraceContextSwap)
  89. #pragma alloc_text(PAGE, WmiStartContextSwapTrace)
  90. #pragma alloc_text(PAGE, WmiStopContextSwapTrace)
  91. #endif
  92. ULONG WmipTraceFileFlag = FALSE;
  93. ULONG WmipFileIndex = 0;
  94. PFILE_OBJECT *WmipFileTable = NULL;
  95. #ifdef ALLOC_DATA_PRAGMA
  96. #pragma data_seg("PAGEDATA")
  97. #endif
  98. ULONG WmipKernelLoggerStartedOnce = 0;
  99. LONG WmipTraceProcessRef = 0;
  100. PVOID WmipDiskIoNotify = NULL;
  101. PVOID WmipTdiIoNotify = NULL;
  102. #ifdef ALLOC_DATA_PRAGMA
  103. #pragma data_seg()
  104. #endif
  105. typedef struct _TRACE_DEVICE {
  106. PDEVICE_OBJECT DeviceObject;
  107. ULONG TraceClass;
  108. } TRACE_DEVICE, *PTRACE_DEVICE;
  109. VOID
  110. FASTCALL
  111. WmipEnableKernelTrace(
  112. IN ULONG EnableFlags
  113. )
  114. /*++
  115. Routine Description:
  116. This is called by WmipStartLogger in tracelog.c. Its purpose is to
  117. set up all the kernel notification routines that can produce event traces
  118. for capacity planning.
  119. Arguments:
  120. ExtendedOn a flag to indicate if extended mode tracing is requested
  121. Return Value:
  122. None
  123. --*/
  124. {
  125. PREGENTRY RegEntry;
  126. PLIST_ENTRY RegEntryList;
  127. ULONG DevicesFound;
  128. long Index, DiskFound;
  129. PTRACE_DEVICE *deviceList, device;
  130. CCHAR stackSize;
  131. PIRP irp;
  132. PVOID notifyRoutine;
  133. PIO_STACK_LOCATION irpStack;
  134. NTSTATUS status;
  135. ULONG enableDisk, enableNetwork;
  136. PAGED_CODE();
  137. //
  138. // Since we cannot do anything, we will have to count the number
  139. // of entries we need to create first, and add some buffer
  140. //
  141. DiskFound = 0;
  142. enableDisk = (EnableFlags & EVENT_TRACE_FLAG_DISK_IO);
  143. enableNetwork = (EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP);
  144. if ( enableDisk || enableNetwork ) {
  145. //
  146. // Setting the callouts will cause new PDO registration to be enabled
  147. // from here on.
  148. //
  149. if (enableDisk) {
  150. WmipDiskIoNotify = (PVOID) &WmipTraceIo;
  151. }
  152. if (enableNetwork) {
  153. WmipTdiIoNotify = (PVOID) &WmipTraceNetwork;
  154. }
  155. DevicesFound = WmipInUseRegEntryCount;
  156. deviceList = (PTRACE_DEVICE*)
  157. ExAllocatePoolWithTag(
  158. PagedPool,
  159. (DevicesFound) * sizeof(TRACE_DEVICE),
  160. TRACEPOOLTAG);
  161. if (deviceList == NULL)
  162. return;
  163. RtlZeroMemory(deviceList, sizeof(TRACE_DEVICE) * DevicesFound);
  164. //
  165. // Now, we will go through what's already in the list and enable trace
  166. // notification routine. Devices who registered while after we've set
  167. // the callout will get another Irp to enable, but that's alright
  168. //
  169. device = (PTRACE_DEVICE) deviceList; // start from first element
  170. Index = 0;
  171. WmipEnterSMCritSection();
  172. RegEntryList = WmipInUseRegEntryHead.Flink;
  173. while (RegEntryList != &WmipInUseRegEntryHead) {
  174. RegEntry = CONTAINING_RECORD(RegEntryList,REGENTRY,InUseEntryList);
  175. if (RegEntry->Flags & REGENTRY_FLAG_TRACED) {
  176. if ((ULONG) Index < DevicesFound) {
  177. device->TraceClass
  178. = RegEntry->Flags & WMIREG_FLAG_TRACE_NOTIFY_MASK;
  179. if (device->TraceClass == WMIREG_NOTIFY_DISK_IO)
  180. DiskFound++;
  181. device->DeviceObject = RegEntry->DeviceObject;
  182. device++;
  183. Index++;
  184. }
  185. }
  186. RegEntryList = RegEntryList->Flink;
  187. }
  188. WmipLeaveSMCritSection();
  189. //
  190. // actually send the notification to diskperf or tdi here
  191. //
  192. stackSize = WmipServiceDeviceObject->StackSize;
  193. irp = IoAllocateIrp(stackSize, FALSE);
  194. device = (PTRACE_DEVICE) deviceList;
  195. while (--Index >= 0 && irp != NULL) {
  196. if (device->DeviceObject != NULL) {
  197. if ( (device->TraceClass == WMIREG_NOTIFY_TDI_IO) &&
  198. enableNetwork ) {
  199. notifyRoutine = (PVOID) &WmipTraceNetwork;
  200. }
  201. else if ( (device->TraceClass == WMIREG_NOTIFY_DISK_IO) &&
  202. enableDisk ) {
  203. notifyRoutine = (PVOID) &WmipTraceIo;
  204. }
  205. else { // consider supporting generic callout for other devices
  206. notifyRoutine = NULL;
  207. device ++;
  208. continue;
  209. }
  210. do {
  211. IoInitializeIrp(irp, IoSizeOfIrp(stackSize), stackSize);
  212. IoSetNextIrpStackLocation(irp);
  213. irpStack = IoGetCurrentIrpStackLocation(irp);
  214. irpStack->DeviceObject = WmipServiceDeviceObject;
  215. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  216. status = WmipForwardWmiIrp(
  217. irp,
  218. IRP_MN_SET_TRACE_NOTIFY,
  219. IoWMIDeviceObjectToProviderId(device->DeviceObject),
  220. NULL,
  221. sizeof(notifyRoutine),
  222. &notifyRoutine
  223. );
  224. if (status == STATUS_WMI_TRY_AGAIN) {
  225. IoFreeIrp(irp);
  226. stackSize = WmipServiceDeviceObject->StackSize;
  227. irp = IoAllocateIrp(stackSize, FALSE);
  228. if (!irp) {
  229. break;
  230. }
  231. }
  232. } while (status == STATUS_WMI_TRY_AGAIN);
  233. }
  234. device++;
  235. }
  236. if (irp) {
  237. IoFreeIrp(irp);
  238. }
  239. ExFreePoolWithTag(deviceList, TRACEPOOLTAG);
  240. // free the array that we created above
  241. //
  242. }
  243. if (EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) {
  244. MmSetPageFaultNotifyRoutine(
  245. (PPAGE_FAULT_NOTIFY_ROUTINE) &WmipTracePageFault);
  246. }
  247. if (EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) {
  248. //
  249. // NOTE: We assume StartLogger will always reserve space for
  250. // FileTable already
  251. //
  252. WmipTraceFileFlag = TRUE;
  253. }
  254. if (EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  255. if (!(WmipKernelLoggerStartedOnce & EVENT_TRACE_FLAG_IMAGE_LOAD)) {
  256. PsSetLoadImageNotifyRoutine(
  257. (PLOAD_IMAGE_NOTIFY_ROUTINE) &WmipTraceLoadImage
  258. );
  259. WmipKernelLoggerStartedOnce |= EVENT_TRACE_FLAG_IMAGE_LOAD;
  260. }
  261. }
  262. if (EnableFlags & EVENT_TRACE_FLAG_REGISTRY) {
  263. CmSetTraceNotifyRoutine(
  264. (PCM_TRACE_NOTIFY_ROUTINE) &WmipTraceRegistry,
  265. FALSE
  266. );
  267. }
  268. }
  269. VOID
  270. FASTCALL
  271. WmipDisableKernelTrace(
  272. IN ULONG EnableFlags
  273. )
  274. /*++
  275. Routine Description:
  276. This is called by WmipStopLogger in tracelog.c. Its purpose of the
  277. disable all the kernel notification routines that was defined by
  278. WmipEnableKernelTrace
  279. Arguments:
  280. EnableFlags Flags indicated what was enabled and needs to be disabled
  281. Return Value:
  282. None
  283. --*/
  284. {
  285. PVOID NullPtr = NULL;
  286. PREGENTRY RegEntry;
  287. PLIST_ENTRY RegEntryList;
  288. ULONG DevicesFound;
  289. long Index;
  290. PTRACE_DEVICE* deviceList, device;
  291. CCHAR stackSize;
  292. PIRP irp;
  293. PIO_STACK_LOCATION irpStack;
  294. NTSTATUS status;
  295. ULONG enableDisk, enableNetwork;
  296. PAGED_CODE();
  297. //
  298. // first, disable partition change notification
  299. //
  300. if (EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO) {
  301. WmipTraceFileFlag = FALSE;
  302. if (WmipFileTable != NULL) {
  303. RtlZeroMemory(
  304. WmipFileTable,
  305. MAX_FILE_TABLE_SIZE * sizeof(PFILE_OBJECT));
  306. }
  307. }
  308. if (EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS) {
  309. MmSetPageFaultNotifyRoutine(NULL);
  310. }
  311. if (EnableFlags & EVENT_TRACE_FLAG_REGISTRY) {
  312. CmSetTraceNotifyRoutine(NULL,TRUE);
  313. }
  314. enableDisk = (EnableFlags & EVENT_TRACE_FLAG_DISK_IO);
  315. enableNetwork = (EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP);
  316. if (!enableDisk && !enableNetwork)
  317. return; // NOTE: assumes all flags are already checked
  318. //
  319. // Note. Since this is in the middle is StopLogger, it is not possible
  320. // StartLogger will prevent kernel tracing from being enabled, hence
  321. // we need not worry about WmipEnableKernelTrace() being called while
  322. // this is in progress.
  323. //
  324. WmipDiskIoNotify = NULL;
  325. WmipTdiIoNotify = NULL;
  326. DevicesFound = WmipInUseRegEntryCount;
  327. deviceList = (PTRACE_DEVICE*)
  328. ExAllocatePoolWithTag(
  329. PagedPool,
  330. (DevicesFound) * sizeof(TRACE_DEVICE),
  331. TRACEPOOLTAG);
  332. if (deviceList == NULL)
  333. return;
  334. RtlZeroMemory(deviceList, sizeof(TRACE_DEVICE) * DevicesFound);
  335. Index = 0;
  336. device = (PTRACE_DEVICE) deviceList; // start from first element
  337. //
  338. // To disable we do not need to worry about TraceClass, since we simply
  339. // set all callouts to NULL
  340. //
  341. WmipEnterSMCritSection();
  342. RegEntryList = WmipInUseRegEntryHead.Flink;
  343. while (RegEntryList != &WmipInUseRegEntryHead) {
  344. RegEntry = CONTAINING_RECORD(RegEntryList, REGENTRY, InUseEntryList);
  345. if (RegEntry->Flags & REGENTRY_FLAG_TRACED) {
  346. if ((ULONG)Index < DevicesFound)
  347. device->TraceClass
  348. = RegEntry->Flags & WMIREG_FLAG_TRACE_NOTIFY_MASK;
  349. device->DeviceObject = RegEntry->DeviceObject;
  350. device++; Index++;
  351. }
  352. RegEntryList = RegEntryList->Flink;
  353. }
  354. WmipLeaveSMCritSection();
  355. stackSize = WmipServiceDeviceObject->StackSize;
  356. irp = IoAllocateIrp(stackSize, FALSE);
  357. device = (PTRACE_DEVICE) deviceList; // start from first element
  358. while (--Index >= 0 && irp != NULL) {
  359. if (device->DeviceObject != NULL) {
  360. do {
  361. IoInitializeIrp(irp, IoSizeOfIrp(stackSize), stackSize);
  362. IoSetNextIrpStackLocation(irp);
  363. irpStack = IoGetCurrentIrpStackLocation(irp);
  364. irpStack->DeviceObject = WmipServiceDeviceObject;
  365. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  366. if ( !( (device->TraceClass == WMIREG_NOTIFY_TDI_IO) &&
  367. enableNetwork ) &&
  368. !( (device->TraceClass == WMIREG_NOTIFY_DISK_IO) &&
  369. enableDisk ) ) {
  370. continue;
  371. }
  372. status = WmipForwardWmiIrp(
  373. irp,
  374. IRP_MN_SET_TRACE_NOTIFY,
  375. IoWMIDeviceObjectToProviderId(device->DeviceObject),
  376. NULL,
  377. sizeof(NullPtr),
  378. &NullPtr
  379. );
  380. if (status == STATUS_WMI_TRY_AGAIN) {
  381. IoFreeIrp(irp);
  382. stackSize = WmipServiceDeviceObject->StackSize;
  383. irp = IoAllocateIrp(stackSize, FALSE);
  384. if (!irp) {
  385. break;
  386. }
  387. }
  388. } while (status == STATUS_WMI_TRY_AGAIN);
  389. }
  390. device++;
  391. }
  392. if (irp) {
  393. IoFreeIrp(irp);
  394. }
  395. ExFreePoolWithTag(deviceList, TRACEPOOLTAG);
  396. }
  397. VOID
  398. WmipSetTraceNotify(
  399. IN PDEVICE_OBJECT DeviceObject,
  400. IN ULONG TraceClass,
  401. IN ULONG Enable
  402. )
  403. {
  404. PIRP irp;
  405. PVOID NotifyRoutine = NULL;
  406. NTSTATUS status;
  407. CCHAR stackSize;
  408. PIO_STACK_LOCATION irpStack;
  409. if (Enable) {
  410. switch (TraceClass) {
  411. case WMIREG_NOTIFY_DISK_IO :
  412. NotifyRoutine = WmipDiskIoNotify;
  413. break;
  414. case WMIREG_NOTIFY_TDI_IO :
  415. NotifyRoutine = WmipTdiIoNotify;
  416. break;
  417. default :
  418. return;
  419. }
  420. if (NotifyRoutine == NULL) // trace not enabled, so do not
  421. return; // send any Irp to enable
  422. }
  423. do {
  424. stackSize = WmipServiceDeviceObject->StackSize;
  425. irp = IoAllocateIrp(stackSize, FALSE);
  426. if (!irp)
  427. return;
  428. IoSetNextIrpStackLocation(irp);
  429. irpStack = IoGetCurrentIrpStackLocation(irp);
  430. irpStack->DeviceObject = WmipServiceDeviceObject;
  431. status = WmipForwardWmiIrp(
  432. irp,
  433. IRP_MN_SET_TRACE_NOTIFY,
  434. IoWMIDeviceObjectToProviderId(DeviceObject),
  435. NULL,
  436. sizeof(NotifyRoutine),
  437. &NotifyRoutine
  438. );
  439. IoFreeIrp(irp);
  440. } while (status == STATUS_WMI_TRY_AGAIN);
  441. }
  442. //
  443. // All the following routines are callout or notification routines for
  444. // generating kernel event traces
  445. //
  446. NTKERNELAPI
  447. VOID
  448. FASTCALL
  449. WmiTraceProcess(
  450. IN PEPROCESS Process,
  451. IN BOOLEAN Create
  452. )
  453. /*++
  454. Routine Description:
  455. This callout routine is called from ps\create.c and ps\psdelete.c.
  456. Arguments:
  457. Process - PEPROCESS;
  458. Create - True if intended process is being created.
  459. Return Value:
  460. None
  461. --*/
  462. {
  463. ULONG Size, LoggerId;
  464. NTSTATUS Status;
  465. PCHAR AuxPtr;
  466. PSYSTEM_TRACE_HEADER Header;
  467. PVOID BufferResource;
  468. ULONG SidLength;
  469. PTOKEN_USER LocalUser = NULL;
  470. PWMI_PROCESS_INFORMATION ProcessInfo;
  471. PWMI_LOGGER_CONTEXT LoggerContext;
  472. PVOID Token;
  473. PAGED_CODE();
  474. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  475. (WmipIsLoggerOn(WmipEventLogger) == NULL))
  476. return;
  477. Token = PsReferencePrimaryToken(Process);
  478. if (Token != NULL) {
  479. Status = SeQueryInformationToken(
  480. Token,
  481. TokenUser,
  482. &LocalUser);
  483. PsDereferencePrimaryTokenEx (Process, Token);
  484. } else {
  485. Status = STATUS_SEVERITY_ERROR;
  486. }
  487. if (NT_SUCCESS(Status)) {
  488. WmipAssert(LocalUser != NULL); // temporary for SE folks
  489. if (LocalUser != NULL) {
  490. SidLength = SeLengthSid(LocalUser->User.Sid) + sizeof(TOKEN_USER);
  491. }
  492. } else {
  493. SidLength = sizeof(ULONG);
  494. LocalUser = NULL;
  495. }
  496. Size = SidLength + FIELD_OFFSET(WMI_PROCESS_INFORMATION, Sid) + sizeof(Process->ImageFileName);
  497. for (LoggerId = WmipKernelLogger;;LoggerId = WmipEventLogger) {
  498. LoggerContext = WmipIsLoggerOn(LoggerId);
  499. if (LoggerContext != NULL) {
  500. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_PROCESS) {
  501. Header = WmiReserveWithSystemHeader( LoggerId,
  502. Size,
  503. NULL,
  504. &BufferResource);
  505. if (Header) {
  506. if(Create) {
  507. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_CREATE;
  508. } else {
  509. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_DELETE;
  510. }
  511. ProcessInfo = (PWMI_PROCESS_INFORMATION) (Header + 1);
  512. ProcessInfo->PageDirectoryBase = MmGetDirectoryFrameFromProcess(Process);
  513. ProcessInfo->ProcessId = HandleToUlong(Process->UniqueProcessId);
  514. ProcessInfo->ParentId = HandleToUlong(Process->InheritedFromUniqueProcessId);
  515. ProcessInfo->SessionId = MmGetSessionId (Process);
  516. ProcessInfo->ExitStatus = (Create ? STATUS_SUCCESS : Process->ExitStatus);
  517. AuxPtr = (PCHAR) (&ProcessInfo->Sid);
  518. if (LocalUser != NULL) {
  519. RtlCopyMemory(AuxPtr, LocalUser, SidLength);
  520. } else {
  521. *((PULONG) AuxPtr) = 0;
  522. }
  523. AuxPtr += SidLength;
  524. RtlCopyMemory( AuxPtr,
  525. &Process->ImageFileName[0],
  526. sizeof(Process->ImageFileName));
  527. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  528. }
  529. }
  530. }
  531. if (LoggerId == WmipEventLogger)
  532. break;
  533. }
  534. if (LocalUser != NULL) {
  535. ExFreePool(LocalUser);
  536. }
  537. }
  538. NTKERNELAPI
  539. VOID
  540. WmiTraceThread(
  541. IN PETHREAD Thread,
  542. IN PINITIAL_TEB InitialTeb OPTIONAL,
  543. IN BOOLEAN Create
  544. )
  545. /*++
  546. Routine Description:
  547. This callout routine is called from ps\create.c and ps\psdelete.c.
  548. It is a PCREATE_THREAD_NOTIFY_ROUTINE.
  549. Arguments:
  550. Thread - PETHREAD structure
  551. InitialTeb - PINITIAL_TEB
  552. Create - True if intended thread is being created.
  553. Return Value:
  554. None
  555. --*/
  556. {
  557. ULONG LoggerId;
  558. PSYSTEM_TRACE_HEADER Header;
  559. PVOID BufferResource;
  560. PWMI_LOGGER_CONTEXT LoggerContext;
  561. PAGED_CODE();
  562. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  563. (WmipIsLoggerOn(WmipEventLogger) == NULL)) {
  564. return;
  565. }
  566. for (LoggerId = WmipKernelLogger;;LoggerId = WmipEventLogger) {
  567. LoggerContext = WmipIsLoggerOn(LoggerId);
  568. if (LoggerContext != NULL) {
  569. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_THREAD) {
  570. if (Create) {
  571. PWMI_EXTENDED_THREAD_INFORMATION ThreadInfo;
  572. Header = (PSYSTEM_TRACE_HEADER)
  573. WmiReserveWithSystemHeader( LoggerId,
  574. sizeof(WMI_EXTENDED_THREAD_INFORMATION),
  575. NULL,
  576. &BufferResource);
  577. if (Header) {
  578. Header->Packet.HookId = WMI_LOG_TYPE_THREAD_CREATE;
  579. ThreadInfo = (PWMI_EXTENDED_THREAD_INFORMATION) (Header + 1);
  580. ThreadInfo->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  581. ThreadInfo->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  582. ThreadInfo->StackBase = Thread->Tcb.StackBase;
  583. ThreadInfo->StackLimit = Thread->Tcb.StackLimit;
  584. if (InitialTeb != NULL) {
  585. if ((InitialTeb->OldInitialTeb.OldStackBase == NULL) &&
  586. (InitialTeb->OldInitialTeb.OldStackLimit == NULL)) {
  587. ThreadInfo->UserStackBase = InitialTeb->StackBase;
  588. ThreadInfo->UserStackLimit = InitialTeb->StackLimit;
  589. } else {
  590. ThreadInfo->UserStackBase = InitialTeb->OldInitialTeb.OldStackBase;
  591. ThreadInfo->UserStackLimit = InitialTeb->OldInitialTeb.OldStackLimit;
  592. }
  593. } else {
  594. ThreadInfo->UserStackBase = NULL;
  595. ThreadInfo->UserStackLimit = NULL;
  596. }
  597. ThreadInfo->StartAddr = (Thread)->StartAddress;
  598. ThreadInfo->Win32StartAddr = (Thread)->Win32StartAddress;
  599. ThreadInfo->WaitMode = -1;
  600. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  601. }
  602. } else {
  603. PWMI_THREAD_INFORMATION ThreadInfo;
  604. Header = (PSYSTEM_TRACE_HEADER)
  605. WmiReserveWithSystemHeader( LoggerId,
  606. sizeof(WMI_THREAD_INFORMATION),
  607. NULL,
  608. &BufferResource);
  609. if (Header) {
  610. Header->Packet.HookId = WMI_LOG_TYPE_THREAD_DELETE;
  611. ThreadInfo = (PWMI_THREAD_INFORMATION) (Header + 1);
  612. ThreadInfo->ProcessId = HandleToUlong((Thread)->Cid.UniqueProcess);
  613. ThreadInfo->ThreadId = HandleToUlong((Thread)->Cid.UniqueThread);
  614. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  615. }
  616. }
  617. }
  618. }
  619. if (LoggerId == WmipEventLogger) {
  620. break;
  621. }
  622. }
  623. }
  624. VOID
  625. FASTCALL
  626. WmipTracePageFault(
  627. IN NTSTATUS Status,
  628. IN PVOID VirtualAddress,
  629. IN PVOID TrapFrame
  630. )
  631. /*++
  632. Routine Description:
  633. This callout routine is called from mm\mmfault.c.
  634. It is a PPAGE_FAULT_NOTIFY_ROUTINE
  635. Arguments:
  636. Status Used to tell the type of fault
  637. VirtualAddress The virtual address responsible for the fault
  638. TrapFrame Trap Frame
  639. Return Value:
  640. None
  641. --*/
  642. {
  643. UCHAR Type;
  644. PVOID *AuxInfo;
  645. PSYSTEM_TRACE_HEADER Header;
  646. PVOID BufferResource;
  647. PWMI_LOGGER_CONTEXT LoggerContext;
  648. if (Status == STATUS_PAGE_FAULT_DEMAND_ZERO)
  649. Type = EVENT_TRACE_TYPE_MM_DZF;
  650. else if (Status == STATUS_PAGE_FAULT_TRANSITION)
  651. Type = EVENT_TRACE_TYPE_MM_TF;
  652. else if (Status == STATUS_PAGE_FAULT_COPY_ON_WRITE)
  653. Type = EVENT_TRACE_TYPE_MM_COW;
  654. else if (Status == STATUS_PAGE_FAULT_PAGING_FILE)
  655. Type = EVENT_TRACE_TYPE_MM_HPF;
  656. else if (Status == STATUS_PAGE_FAULT_GUARD_PAGE)
  657. Type = EVENT_TRACE_TYPE_MM_GPF;
  658. else {
  659. #if DBG
  660. DbgPrintEx(DPFLTR_WMILIB_ID,
  661. DPFLTR_INFO_LEVEL,
  662. "WmipTracePageFault: Skipping fault %X\n",
  663. Status);
  664. #endif
  665. return;
  666. }
  667. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  668. if (LoggerContext == NULL) {
  669. return;
  670. }
  671. Header = (PSYSTEM_TRACE_HEADER)
  672. WmiReserveWithSystemHeader(
  673. WmipKernelLogger,
  674. 2 * sizeof(PVOID),
  675. NULL,
  676. &BufferResource);
  677. if (Header == NULL)
  678. return;
  679. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_MEMORY >> 8);
  680. Header->Packet.Type = Type;
  681. AuxInfo = (PVOID*) ((PCHAR)Header + sizeof(SYSTEM_TRACE_HEADER));
  682. AuxInfo[0] = VirtualAddress;
  683. AuxInfo[1] = 0;
  684. if (TrapFrame != NULL) {
  685. #ifdef _X86_
  686. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->Eip;
  687. #endif
  688. #ifdef _IA64_
  689. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->StIIP;
  690. #endif
  691. #ifdef _AMD64_
  692. AuxInfo[1] = (PVOID) ((PKTRAP_FRAME)TrapFrame)->Rip;
  693. #endif
  694. }
  695. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  696. return;
  697. }
  698. VOID
  699. WmipTraceNetwork(
  700. IN ULONG GroupType, // Group/type for the event
  701. IN PVOID EventInfo, // Event data as defined in MOF
  702. IN ULONG EventInfoLen, // Length of the event data
  703. IN PVOID Reserved // not used
  704. )
  705. /*++
  706. Routine Description:
  707. This callout routine is called from tcpip.sys to log a network event.
  708. Arguments:
  709. GroupType a ULONG key to indicate the action
  710. EventInfo a pointer to contiguous memory containing information
  711. to be attached to event trace
  712. EventInfoLen length of EventInfo
  713. Reserved Not used.
  714. Return Value:
  715. None
  716. --*/
  717. {
  718. PPERFINFO_TRACE_HEADER Header;
  719. PWMI_BUFFER_HEADER BufferResource;
  720. PWMI_LOGGER_CONTEXT LoggerContext;
  721. LoggerContext = WmipLoggerContext[WmipKernelLogger];
  722. Header = WmiReserveWithPerfHeader(EventInfoLen, &BufferResource);
  723. if (Header == NULL) {
  724. return;
  725. }
  726. Header->Packet.HookId = (USHORT) GroupType;
  727. RtlCopyMemory((PUCHAR)Header + FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data),
  728. EventInfo,
  729. EventInfoLen);
  730. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  731. return;
  732. }
  733. VOID
  734. WmipTraceIo(
  735. IN ULONG DiskNumber,
  736. IN PIRP Irp,
  737. IN PVOID Counters // use PDISK_PERFORMANCE if we need it
  738. )
  739. /*++
  740. Routine Description:
  741. This callout routine is called from DiskPerf
  742. It is a PPHYSICAL_DISK_IO_NOTIFY_ROUTINE
  743. Arguments:
  744. DiskNumber The disk number assigned by DiskPerf
  745. CurrentIrpStack The Irp stack location that DiskPerf is at
  746. Irp The Irp that is being passed through DiskPerf
  747. Return Value:
  748. None
  749. --*/
  750. {
  751. PIO_STACK_LOCATION CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  752. WMI_DISKIO_READWRITE *IoTrace;
  753. ULONG Size;
  754. PLARGE_INTEGER IoResponse;
  755. PSYSTEM_TRACE_HEADER Header;
  756. PVOID BufferResource;
  757. PWMI_LOGGER_CONTEXT LoggerContext;
  758. UNREFERENCED_PARAMETER(Counters);
  759. Size = sizeof(struct _WMI_DISKIO_READWRITE);
  760. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  761. if (LoggerContext == NULL) {
  762. return;
  763. }
  764. Header = (PSYSTEM_TRACE_HEADER)
  765. WmiReserveWithSystemHeader(
  766. WmipKernelLogger,
  767. Size,
  768. Irp->Tail.Overlay.Thread,
  769. &BufferResource);
  770. if (Header == NULL)
  771. return;
  772. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_IO >> 8);
  773. if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
  774. Header->Packet.Type = EVENT_TRACE_TYPE_IO_READ;
  775. else
  776. Header->Packet.Type = EVENT_TRACE_TYPE_IO_WRITE;
  777. IoTrace = (struct _WMI_DISKIO_READWRITE *)
  778. ((PCHAR) Header + sizeof(SYSTEM_TRACE_HEADER));
  779. IoResponse = (PLARGE_INTEGER) &CurrentIrpStack->Parameters.Read;
  780. IoTrace->DiskNumber = DiskNumber;
  781. IoTrace->IrpFlags = Irp->Flags;
  782. IoTrace->Size = (ULONG) Irp->IoStatus.Information;
  783. IoTrace->ByteOffset = CurrentIrpStack->Parameters.Read.ByteOffset.QuadPart;
  784. if (IoResponse->HighPart == 0) {
  785. IoTrace->ResponseTime = IoResponse->LowPart;
  786. } else {
  787. IoTrace->ResponseTime = 0xFFFFFFFF;
  788. }
  789. IoTrace->HighResResponseTime = IoResponse->QuadPart;
  790. if (WmipTraceFileFlag) {
  791. if (Irp->Flags & IRP_ASSOCIATED_IRP) {
  792. IoTrace->FileObject = Irp->AssociatedIrp.MasterIrp->Tail.Overlay.OriginalFileObject;
  793. } else {
  794. IoTrace->FileObject = Irp->Tail.Overlay.OriginalFileObject;
  795. }
  796. }
  797. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  798. if (WmipTraceFileFlag) { // File tracing required
  799. PKAPC apc;
  800. PFILE_OBJECT fileObject = IoTrace->FileObject;
  801. PFILE_OBJECT *fileTable;
  802. ULONG i, fileIndex;
  803. PFILE_OBJECT lastFile = NULL;
  804. if (!fileObject) {
  805. return;
  806. }
  807. if (fileObject->FileName.Length == 0) {
  808. return;
  809. }
  810. if (!Irp->Tail.Overlay.Thread) {
  811. return;
  812. }
  813. fileTable = (PFILE_OBJECT *) WmipFileTable;
  814. if (fileTable == NULL)
  815. return;
  816. //
  817. // Cannot use list for regular LRU because the list needs to be
  818. // protected by spinlock. Use a simple array instead. We know we
  819. // can run into collision but can afford to have some entries
  820. // thrown away
  821. //
  822. // if (fileObject == fileTable[WmipFileIndex]) {
  823. // return; // just saw it, so return
  824. // }
  825. fileIndex = WmipFileIndex;
  826. for (i=0; i<MAX_FILE_TABLE_SIZE; i++) {
  827. if (fileTable[i] == NULL) {
  828. fileTable[i] = fileObject;
  829. goto TraceFileName;
  830. }
  831. else if (fileTable[i] == fileObject) {
  832. if (i <= MAX_FILE_TABLE_SIZE/2)
  833. return;
  834. lastFile = fileTable[fileIndex];
  835. fileTable[fileIndex] = fileObject;
  836. fileTable[i] = lastFile;
  837. if (++WmipFileIndex >= MAX_FILE_TABLE_SIZE/2) {
  838. WmipFileIndex = 0;
  839. }
  840. return;
  841. }
  842. }
  843. fileTable[fileIndex] = fileObject;
  844. if (++WmipFileIndex >= MAX_FILE_TABLE_SIZE/2) {
  845. WmipFileIndex = 0;
  846. }
  847. TraceFileName:
  848. // could not find it. Have to pay the price to get it
  849. //
  850. apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TRACEPOOLTAG);
  851. if (!apc)
  852. return;
  853. ObReferenceObjectByPointer (
  854. fileObject,
  855. 0L,
  856. NULL,
  857. KernelMode
  858. );
  859. KeInitializeApc (apc,
  860. &Irp->Tail.Overlay.Thread->Tcb, Irp->ApcEnvironment,
  861. (PKKERNEL_ROUTINE) WmipTraceFile,
  862. NULL, // rundown routine for thread termination
  863. NULL, // normal routine at IRQL0
  864. KernelMode,
  865. NULL);
  866. if (!KeInsertQueueApc (apc, fileObject, NULL, 0)) {
  867. ExFreePool (apc);
  868. ObDereferenceObject(fileObject);
  869. }
  870. }
  871. return;
  872. }
  873. VOID WmipTraceFile(
  874. IN PKAPC Apc,
  875. IN PKNORMAL_ROUTINE *NormalRoutine,
  876. IN PVOID *NormalContext,
  877. IN PVOID *SystemArgument1,
  878. IN PVOID *SystemArgument2
  879. )
  880. {
  881. ULONG len;
  882. PFILE_OBJECT fileObject = (PFILE_OBJECT) *SystemArgument1;
  883. PUNICODE_STRING fileName;
  884. PPERFINFO_TRACE_HEADER Header;
  885. PWMI_BUFFER_HEADER BufferResource;
  886. PUCHAR AuxPtr;
  887. PWMI_LOGGER_CONTEXT LoggerContext;
  888. UNREFERENCED_PARAMETER( NormalRoutine );
  889. UNREFERENCED_PARAMETER( NormalContext );
  890. UNREFERENCED_PARAMETER( SystemArgument2 );
  891. PAGED_CODE();
  892. if (!fileObject) { // should not happen
  893. ExFreePool(Apc);
  894. return;
  895. }
  896. if (!WmipTraceFileFlag)
  897. return;
  898. fileName = &fileObject->FileName;
  899. len = fileName->Length;
  900. if (len > (0XFFFF - sizeof(PFILE_OBJECT) - sizeof(WCHAR)))
  901. len = 0; // allow only 64K max
  902. if (len > 0 && fileName->Buffer != NULL) {
  903. LoggerContext = WmipLoggerContext[WmipKernelLogger];
  904. Header = WmiReserveWithPerfHeader(
  905. sizeof(PFILE_OBJECT) + len + sizeof(WCHAR),
  906. &BufferResource);
  907. if (Header == NULL)
  908. return;
  909. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_FILE >> 8);
  910. Header->Packet.Type = EVENT_TRACE_TYPE_INFO;
  911. AuxPtr = (PUCHAR)Header + FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data);
  912. *((PFILE_OBJECT*)AuxPtr) = fileObject;
  913. AuxPtr += sizeof(PFILE_OBJECT);
  914. RtlCopyMemory(AuxPtr, fileName->Buffer, len);
  915. AuxPtr += len;
  916. *((PWCHAR) AuxPtr) = UNICODE_NULL; // always put a NULL
  917. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  918. }
  919. ObDereferenceObject(fileObject);
  920. ExFreePool(Apc);
  921. }
  922. VOID
  923. WmipTraceLoadImage(
  924. IN PUNICODE_STRING ImageName,
  925. IN HANDLE ProcessId,
  926. IN PIMAGE_INFO ImageInfo
  927. )
  928. {
  929. PSYSTEM_TRACE_HEADER Header;
  930. PUCHAR AuxInfo;
  931. PVOID BufferResource;
  932. ULONG Length, LoggerId;
  933. PWMI_LOGGER_CONTEXT LoggerContext;
  934. PAGED_CODE();
  935. UNREFERENCED_PARAMETER(ProcessId);
  936. if ((WmipIsLoggerOn(WmipKernelLogger) == NULL) &&
  937. (WmipIsLoggerOn(WmipEventLogger) == NULL))
  938. return;
  939. if (ImageName == NULL)
  940. return;
  941. Length = ImageName->Length;
  942. if ((Length == 0) || (ImageName->Buffer == NULL)) {
  943. return;
  944. }
  945. if (Length > (0XFFFF - sizeof(PVOID) - sizeof(SIZE_T) - sizeof(WCHAR)))
  946. return;
  947. for (LoggerId = WmipKernelLogger;; LoggerId = WmipEventLogger) {
  948. LoggerContext = WmipIsLoggerOn(LoggerId);
  949. if (LoggerContext != NULL) {
  950. if (LoggerContext->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD) {
  951. PWMI_IMAGELOAD_INFORMATION ImageLoadInfo;
  952. Header = WmiReserveWithSystemHeader(
  953. LoggerId,
  954. FIELD_OFFSET (WMI_IMAGELOAD_INFORMATION, FileName) + Length + sizeof(WCHAR),
  955. NULL,
  956. &BufferResource);
  957. if (Header != NULL) {
  958. Header->Packet.HookId = WMI_LOG_TYPE_PROCESS_LOAD_IMAGE;
  959. ImageLoadInfo = (PWMI_IMAGELOAD_INFORMATION) (Header + 1);
  960. ImageLoadInfo->ImageBase = ImageInfo->ImageBase;
  961. ImageLoadInfo->ImageSize = ImageInfo->ImageSize;
  962. ImageLoadInfo->ProcessId = HandleToUlong(ProcessId);
  963. AuxInfo = (PUCHAR) &(ImageLoadInfo->FileName[0]);
  964. RtlCopyMemory(AuxInfo, ImageName->Buffer, Length);
  965. AuxInfo += Length;
  966. *((PWCHAR) AuxInfo) = UNICODE_NULL; // put a trailing NULL
  967. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  968. }
  969. }
  970. }
  971. if (LoggerId == WmipEventLogger)
  972. break;
  973. }
  974. PerfInfoFlushProfileCache();
  975. }
  976. VOID
  977. WmipTraceRegistry(
  978. IN NTSTATUS Status,
  979. IN PVOID Kcb,
  980. IN LONGLONG ElapsedTime,
  981. IN ULONG Index,
  982. IN PUNICODE_STRING KeyName,
  983. IN UCHAR Type
  984. )
  985. /*++
  986. Routine Description:
  987. This routine is called to trace out registry calls
  988. Arguments:
  989. Return Value:
  990. None
  991. --*/
  992. {
  993. PCHAR EventInfo;
  994. PSYSTEM_TRACE_HEADER Header;
  995. PVOID BufferResource;
  996. ULONG len = 0;
  997. PWMI_LOGGER_CONTEXT LoggerContext;
  998. PAGED_CODE();
  999. LoggerContext = WmipIsLoggerOn(WmipKernelLogger);
  1000. if (LoggerContext == NULL) {
  1001. return;
  1002. }
  1003. if( KeyName && KeyName->Buffer ) {
  1004. len += KeyName->Length;
  1005. if ((len ==0 ) || (KeyName->Buffer[len/sizeof(WCHAR) -1] != 0) ) {
  1006. //
  1007. // make room for NULL terminator
  1008. //
  1009. len += sizeof(WCHAR);
  1010. }
  1011. } else {
  1012. len += sizeof(WCHAR);
  1013. }
  1014. len += sizeof(PVOID) + sizeof(LONGLONG) + sizeof(ULONG);
  1015. #if defined(_WIN64)
  1016. len += sizeof(LONG64);
  1017. #else
  1018. len += sizeof(NTSTATUS);
  1019. #endif
  1020. if (len > 0xFFFF) // 64K bytes max
  1021. Header = NULL;
  1022. else {
  1023. Header = (PSYSTEM_TRACE_HEADER)
  1024. WmiReserveWithSystemHeader(
  1025. WmipKernelLogger,
  1026. len,
  1027. NULL,
  1028. &BufferResource);
  1029. }
  1030. if (Header == NULL)
  1031. return;
  1032. Header->Packet.Group = (UCHAR) (EVENT_TRACE_GROUP_REGISTRY >> 8);
  1033. Header->Packet.Type = Type;
  1034. EventInfo = (PCHAR) ((PCHAR) Header + sizeof(SYSTEM_TRACE_HEADER));
  1035. #if defined(_WIN64)
  1036. *((LONG64 *)EventInfo) = (LONG64)Status;
  1037. EventInfo += sizeof(LONG64);
  1038. #else
  1039. *((NTSTATUS *)EventInfo) = Status;
  1040. EventInfo += sizeof(NTSTATUS);
  1041. #endif
  1042. *((PVOID *)EventInfo) = Kcb;
  1043. EventInfo += sizeof(PVOID);
  1044. *((LONGLONG *)EventInfo) = ElapsedTime;
  1045. EventInfo += sizeof(LONGLONG);
  1046. *((ULONG *)EventInfo) = Index;
  1047. EventInfo += sizeof(ULONG);
  1048. len -= (sizeof(HANDLE) + sizeof(LONGLONG) + sizeof(ULONG) );
  1049. #if defined(_WIN64)
  1050. len -= sizeof(LONG64);
  1051. #else
  1052. len -= sizeof(NTSTATUS);
  1053. #endif
  1054. if( KeyName && KeyName->Buffer ) {
  1055. RtlCopyMemory(EventInfo, KeyName->Buffer, len - sizeof(WCHAR));
  1056. }
  1057. ((PWCHAR)EventInfo)[len/sizeof(WCHAR) -1] = UNICODE_NULL;
  1058. WmipReleaseTraceBuffer(BufferResource, LoggerContext);
  1059. }
  1060. VOID
  1061. FASTCALL
  1062. WmiTraceContextSwap (
  1063. IN PETHREAD OldEThread,
  1064. IN PETHREAD NewEThread )
  1065. /*++
  1066. Routine Description:
  1067. This routine is called to trace context swap
  1068. operations. It is called directly from the
  1069. context swap procedure while the context swap
  1070. lock is being held, so it is critical that this
  1071. routine not take any locks.
  1072. Assumptions:
  1073. - This routine will only be called from the ContextSwap routine
  1074. - This routine will always be called at IRQL >= DISPATCH_LEVEL
  1075. - This routine will only be called when the PPerfGlobalGroupMask
  1076. is not equal to null, and the context swap flag is set within
  1077. the structure to which PPerfGlobalGroupMask points to,
  1078. and the kernel's WMI_LOGGER_CONTEXT struct has been fully initialized.
  1079. - The Wmi kernel WMI_LOGGER_CONTEXT object, as well as all buffers
  1080. it allocates are allocated from nonpaged pool. All Wmi globals
  1081. that we access are also in nonpaged memory.
  1082. - This code has been locked into paged memory when the logger started
  1083. - The logger context reference count has been incremented via the
  1084. InterlockedIncrement() operation in WmipReferenceLogger(WmipKernelLogger)
  1085. by our start code.
  1086. Arguments:
  1087. OldThread - ptr to ETHREAD object of thread
  1088. being swapped out
  1089. NewThread - ptr to ETHREAD object of thread
  1090. being swapped in
  1091. Return Value:
  1092. None
  1093. --*/
  1094. {
  1095. UCHAR CurrentProcessor;
  1096. PWMI_BUFFER_HEADER Buffer;
  1097. PPERFINFO_TRACE_HEADER EventHeader;
  1098. SIZE_T EventSize;
  1099. PWMI_CONTEXTSWAP ContextSwapData;
  1100. //
  1101. // Figure out which processor we are running on
  1102. //
  1103. CurrentProcessor = (UCHAR)KeGetCurrentProcessorNumber();
  1104. //
  1105. // If we currently have no context swap buffer for this processor
  1106. // then we need to grab one from the ETW Free list.
  1107. //
  1108. Buffer = WmipContextSwapProcessorBuffers[CurrentProcessor];
  1109. if (Buffer == NULL) {
  1110. Buffer = WmipPopFreeContextSwapBuffer(
  1111. CurrentProcessor);
  1112. if( Buffer == NULL ) {
  1113. return;
  1114. }
  1115. //
  1116. // We have a legitimate buffer, so now we
  1117. // set it as this processor's current cxtswap buffer
  1118. //
  1119. WmipContextSwapProcessorBuffers[CurrentProcessor] = Buffer;
  1120. }
  1121. //
  1122. // Compute the pointers to our event structures within the buffer
  1123. // At this point, we will always have enough space in the buffer for
  1124. // this event. We check for a full buffer after we fill out the event
  1125. //
  1126. EventHeader = (PPERFINFO_TRACE_HEADER)( (SIZE_T)Buffer
  1127. + (SIZE_T)Buffer->CurrentOffset);
  1128. ContextSwapData = (PWMI_CONTEXTSWAP)( (SIZE_T)EventHeader
  1129. + (SIZE_T)FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data ));
  1130. EventSize = sizeof(WMI_CONTEXTSWAP)
  1131. + FIELD_OFFSET(PERFINFO_TRACE_HEADER, Data);
  1132. //
  1133. // Fill out the event header
  1134. //
  1135. EventHeader->Marker = PERFINFO_TRACE_MARKER;
  1136. EventHeader->Packet.Size = (USHORT) EventSize;
  1137. EventHeader->Packet.HookId = PERFINFO_LOG_TYPE_CONTEXTSWAP;
  1138. PerfTimeStamp(EventHeader->SystemTime);
  1139. //
  1140. // Assert that the event size is at alligned correctly
  1141. //
  1142. ASSERT( EventSize % WMI_CTXSWAP_EVENTSIZE_ALIGNMENT == 0);
  1143. //
  1144. // Fill out the event data struct for context swap
  1145. //
  1146. ContextSwapData->NewThreadId = HandleToUlong(NewEThread->Cid.UniqueThread);
  1147. ContextSwapData->OldThreadId = HandleToUlong(OldEThread->Cid.UniqueThread);
  1148. ContextSwapData->NewThreadPriority = NewEThread->Tcb.Priority;
  1149. ContextSwapData->OldThreadPriority = OldEThread->Tcb.Priority;
  1150. ContextSwapData->NewThreadQuantum = NewEThread->Tcb.Quantum;
  1151. ContextSwapData->OldThreadQuantum = OldEThread->Tcb.Quantum;
  1152. ContextSwapData->OldThreadWaitReason= OldEThread->Tcb.WaitReason;
  1153. ContextSwapData->OldThreadWaitMode = OldEThread->Tcb.WaitMode;
  1154. ContextSwapData->OldThreadState = OldEThread->Tcb.State;
  1155. ContextSwapData->OldThreadIdealProcessor =
  1156. OldEThread->Tcb.IdealProcessor;
  1157. //
  1158. // Increment the offset. Don't need synchronization here because
  1159. // IRQL >= DISPATCH_LEVEL.
  1160. //
  1161. Buffer->CurrentOffset += (ULONG)EventSize;
  1162. //
  1163. // Check if the buffer is full by taking the difference between
  1164. // the buffer's maximum offset and the current offset.
  1165. //
  1166. if ((Buffer->Offset - Buffer->CurrentOffset) <= EventSize) {
  1167. //
  1168. // Push the full buffer onto the FlushList.
  1169. //
  1170. WmipPushDirtyContextSwapBuffer(CurrentProcessor, Buffer);
  1171. //
  1172. // Zero out the processor buffer pointer so that when we next come
  1173. // into the trace code, we know to grab another one.
  1174. //
  1175. WmipContextSwapProcessorBuffers[CurrentProcessor] = NULL;
  1176. }
  1177. return;
  1178. }
  1179. VOID
  1180. FASTCALL
  1181. WmiStartContextSwapTrace
  1182. (
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Allocates the memory to track the per-processor buffers
  1187. used by context swap tracing. "locks" the logger by incrementing
  1188. the logger context reference count by one.
  1189. Assumptions:
  1190. - This function will not run at DISPATCH or higher
  1191. - The kernel logger context mutex has been acquired before entering
  1192. this function.
  1193. Calling Functions:
  1194. - PerfInfoStartLog
  1195. Arguments:
  1196. None
  1197. Return Value:
  1198. None
  1199. --*/
  1200. {
  1201. //
  1202. // Only used in checked builds - asserts if this code is called with
  1203. // Irql > APC_LEVEL.
  1204. //
  1205. PAGED_CODE();
  1206. //
  1207. // We must make sure we manage this ref count
  1208. // before making any references to the logger context struct to ensure
  1209. // that Wmi does not free the LoggerContext structure while we are using it
  1210. //
  1211. WmipReferenceLogger(WmipKernelLogger);
  1212. //
  1213. // Set the pointers to our buffers to NULL, indicating to the trace event
  1214. // code that a buffer needs to be acquired.
  1215. //
  1216. RtlZeroMemory(
  1217. WmipContextSwapProcessorBuffers,
  1218. sizeof(PWMI_BUFFER_HEADER)*MAXIMUM_PROCESSORS);
  1219. }
  1220. VOID
  1221. FASTCALL
  1222. WmiStopContextSwapTrace
  1223. (
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. Forces a context swap on a processor by jumping onto it.
  1228. Once a context swap has occured on a processor after the context
  1229. swap tracing flag has been disabled, we are guaranteed that the
  1230. buffer associated with that processor is not in use. It is then
  1231. safe to place that buffer on the flush list.
  1232. Assumptions:
  1233. - This function will not run at DISPATCH
  1234. - The kernel logger context mutex was acquired before this function
  1235. was called.
  1236. Calling Functions:
  1237. -PerfInfoStopLog
  1238. Arguments:
  1239. None
  1240. Return Value:
  1241. None; if we fail here there's nothing we can do anyway.
  1242. --*/
  1243. {
  1244. PKTHREAD ThisThread;
  1245. KAFFINITY OriginalAffinity;
  1246. UCHAR i;
  1247. PWMI_LOGGER_CONTEXT LoggerContext;
  1248. //
  1249. // Only used in checked builds - asserts if this code is called with
  1250. // Irql > APC_LEVEL.
  1251. //
  1252. PAGED_CODE();
  1253. //
  1254. // Remember the original thread affinity
  1255. //
  1256. ThisThread = KeGetCurrentThread();
  1257. OriginalAffinity = ThisThread->Affinity;
  1258. //
  1259. // Get the kernel logger context- this should never fail.
  1260. // If we can't get the logger context, then we have nowhere
  1261. // to flush buffers and we might as well stop here.
  1262. //
  1263. LoggerContext = WmipLoggerContext[WmipKernelLogger];
  1264. if( !WmipIsValidLogger( LoggerContext ) ) {
  1265. return;
  1266. }
  1267. //
  1268. // Loop through all processors and place their buffers on the flush list
  1269. // This would probably break if the number of processors were decreased in
  1270. // the middle of the trace.
  1271. //
  1272. for(i=0; i<KeNumberProcessors; i++) {
  1273. //
  1274. // Set the hard processor affinity to 1 << i
  1275. // This effectively jumps onto the processor
  1276. //
  1277. KeSetAffinityThread ( ThisThread, AFFINITY_MASK(i) );
  1278. //
  1279. // Check to make sure this processor even has a buffer,
  1280. // if it doesn't, then next loop
  1281. //
  1282. if(WmipContextSwapProcessorBuffers[i] == NULL) {
  1283. continue;
  1284. }
  1285. //
  1286. // Release the buffer to the flush list
  1287. //
  1288. WmipPushDirtyContextSwapBuffer(i, WmipContextSwapProcessorBuffers[i]);
  1289. WmipContextSwapProcessorBuffers[i] = NULL;
  1290. }
  1291. //
  1292. // We must make sure we manage this ref count
  1293. // before making any references to the logger context struct to ensure
  1294. // that Wmi does not free the LoggerContext structure while we are using it
  1295. //
  1296. WmipDereferenceLogger(WmipKernelLogger);
  1297. //
  1298. // Set our Affinity back to normal
  1299. //
  1300. KeSetAffinityThread( ThisThread, OriginalAffinity);
  1301. return;
  1302. }
  1303. PWMI_LOGGER_CONTEXT
  1304. FASTCALL
  1305. WmipIsLoggerOn(
  1306. IN ULONG LoggerId
  1307. )
  1308. {
  1309. PWMI_LOGGER_CONTEXT LoggerContext;
  1310. if (LoggerId > MAXLOGGERS)
  1311. return NULL;
  1312. LoggerContext = WmipLoggerContext[LoggerId];
  1313. if (!WmipIsValidLogger(LoggerContext))
  1314. return NULL;
  1315. if (LoggerContext->CollectionOn)
  1316. return LoggerContext;
  1317. return NULL;
  1318. }