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.

2537 lines
79 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. tracesup.c
  5. Abstract:
  6. This is the source file that implements the private routines of
  7. the performance event tracing and logging facility. These routines
  8. work on manipulating the LoggerContext table and synchronization
  9. across event tracing sessions.
  10. Author:
  11. Jee Fung Pang (jeepang) 03-Jan-2000
  12. Revision History:
  13. --*/
  14. #include <ntos.h>
  15. #include <evntrace.h>
  16. #include "wmikmp.h"
  17. #include <wmi.h>
  18. #include "tracep.h"
  19. #define max(a,b) (((a) > (b)) ? (a) : (b))
  20. #define KERNEL_LOGGER_CAPTION L"NT Kernel Logger"
  21. #define DEFAULT_BUFFERS 2
  22. #define DEFAULT_AGE_LIMIT 15 // 15 minutes
  23. #define SEMAPHORE_LIMIT 1024
  24. #define CONTEXT_SIZE PAGE_SIZE
  25. #define DEFAULT_MAX_IRQL DISPATCH_LEVEL
  26. ULONG WmipKernelLogger = KERNEL_LOGGER;
  27. ULONG WmipEventLogger = 0XFFFFFFFF;
  28. FAST_MUTEX WmipTraceFastMutex;
  29. #ifdef ALLOC_DATA_PRAGMA
  30. #pragma data_seg("PAGEDATA")
  31. #endif
  32. ULONG WmipLoggerCount = 0;
  33. HANDLE WmipPageLockHandle = NULL;
  34. #ifdef ALLOC_DATA_PRAGMA
  35. #pragma data_seg()
  36. #endif
  37. extern SIZE_T MmMaximumNonPagedPoolInBytes;
  38. #pragma warning( default: 4035 )
  39. #pragma warning( default: 4127 )
  40. WMI_GET_CPUCLOCK_ROUTINE WmiGetCpuClock = &WmipGetSystemTime;
  41. //
  42. // Function prototypes for routines used locally
  43. //
  44. NTSTATUS
  45. WmipLookupLoggerIdByName(
  46. IN PUNICODE_STRING Name,
  47. OUT PULONG LoggerId
  48. );
  49. PWMI_LOGGER_CONTEXT
  50. WmipInitContext(
  51. );
  52. NTSTATUS
  53. WmipAllocateTraceBufferPool(
  54. IN PWMI_LOGGER_CONTEXT LoggerContext
  55. );
  56. NTSTATUS
  57. WmipFreeTraceBufferPool(
  58. IN PWMI_LOGGER_CONTEXT LoggerContext
  59. );
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text(PAGE, WmipStartLogger)
  62. #pragma alloc_text(PAGE, WmipQueryLogger)
  63. #pragma alloc_text(PAGE, WmipStopLoggerInstance)
  64. #pragma alloc_text(PAGE, WmipVerifyLoggerInfo)
  65. #pragma alloc_text(PAGE, WmipExtendBase)
  66. #pragma alloc_text(PAGE, WmipFreeLoggerContext)
  67. #pragma alloc_text(PAGE, WmipInitContext)
  68. #pragma alloc_text(PAGE, WmipAllocateTraceBufferPool)
  69. #pragma alloc_text(PAGE, WmipFreeTraceBufferPool)
  70. #pragma alloc_text(PAGE, WmipLookupLoggerIdByName)
  71. #pragma alloc_text(PAGE, WmipShutdown)
  72. #pragma alloc_text(PAGE, WmipFlushLogger)
  73. #pragma alloc_text(PAGE, WmipNtDllLoggerInfo)
  74. #pragma alloc_text(PAGE, WmipValidateClockType)
  75. #pragma alloc_text(PAGE, WmipDumpGuidMaps)
  76. #pragma alloc_text(PAGE, WmipGetTraceBuffer)
  77. #pragma alloc_text(PAGEWMI, WmipNotifyLogger)
  78. #endif
  79. NTSTATUS
  80. WmipStartLogger(
  81. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  82. )
  83. /*++
  84. Routine Description:
  85. It is called by WmipIoControl in wmi.c, with IOCTL_WMI_START_LOGGER
  86. to start up an instance of the logger. It basically creates and
  87. initializes the logger instance context, and starts up a system
  88. thread for the logger (WmipLogger()). If the user has requested to
  89. turn on kernel tracing, it will also lock in the necessary routines
  90. after the logger has started.
  91. NOTE: A special instance (KERNEL_LOGGER) is reserved exclusively for
  92. logging kernel tracing.
  93. To turn on KERNEL_LOGGER, LoggerInfo->Wnode.Guid should be set to
  94. SystemTraceControlGuid, and sufficient space must be provided in
  95. LoggerInfo->LoggerName.
  96. To turn on other loggers, simply provide a name in LoggerName. The
  97. logger id will be returned.
  98. Arguments:
  99. LoggerInfo a pointer to the structure for the logger's control
  100. and status information
  101. Return Value:
  102. The status of performing the action requested.
  103. --*/
  104. {
  105. NTSTATUS Status;
  106. ULONG LoggerId, EnableKernel, EnableFlags;
  107. HANDLE ThreadHandle;
  108. PWMI_LOGGER_CONTEXT LoggerContext;
  109. LARGE_INTEGER TimeOut = {(ULONG)(-20 * 1000 * 1000 * 10), -1};
  110. LARGE_INTEGER OneSecond = {(ULONG)(-1 * 1000 * 1000 * 10), -1};
  111. ACCESS_MASK DesiredAccess = TRACELOG_GUID_ENABLE;
  112. PWMI_LOGGER_CONTEXT *ContextTable;
  113. PFILE_OBJECT FileObject;
  114. GUID InstanceGuid;
  115. KPROCESSOR_MODE RequestorMode;
  116. SECURITY_QUALITY_OF_SERVICE ServiceQos;
  117. PTRACE_ENABLE_FLAG_EXTENSION FlagExt;
  118. PERFINFO_GROUPMASK *PerfGroupMasks=NULL;
  119. BOOLEAN IsGlobalForKernel = FALSE;
  120. ULONG GroupMaskSize;
  121. UNICODE_STRING FileName, LoggerName;
  122. ULONG LogFileMode;
  123. #if DBG
  124. LONG RefCount;
  125. #endif
  126. PAGED_CODE();
  127. if (LoggerInfo == NULL)
  128. return STATUS_SEVERITY_ERROR;
  129. //
  130. // try and check for bogus parameter
  131. // if the size is at least what we want, we have to assume it's valid
  132. //
  133. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  134. return STATUS_INVALID_BUFFER_SIZE;
  135. if (! (LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  136. return STATUS_INVALID_PARAMETER;
  137. LogFileMode = LoggerInfo->LogFileMode;
  138. if ( (LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) &&
  139. (LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ) {
  140. return STATUS_INVALID_PARAMETER;
  141. }
  142. if ( (LogFileMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE) &&
  143. (LogFileMode & EVENT_TRACE_USE_LOCAL_SEQUENCE) ) {
  144. return STATUS_INVALID_PARAMETER;
  145. }
  146. /* if (LogFileMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE) {
  147. if ((LoggerInfo->LogFileName.Length == 0) ||
  148. (LoggerInfo->LogFileName.Buffer == NULL) )
  149. return STATUS_INVALID_PARAMETER;
  150. }*/
  151. if ( !(LogFileMode & EVENT_TRACE_REAL_TIME_MODE) ) {
  152. if ( !(LogFileMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE) )
  153. if (LoggerInfo->LogFileHandle == NULL)
  154. return STATUS_INVALID_PARAMETER;
  155. }
  156. // Cannot support append to circular
  157. if ( (LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) &&
  158. (LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) ) {
  159. return STATUS_INVALID_PARAMETER;
  160. }
  161. if (LogFileMode & EVENT_TRACE_REAL_TIME_MODE)
  162. DesiredAccess |= TRACELOG_CREATE_REALTIME;
  163. if ((LoggerInfo->LogFileHandle != NULL) ||
  164. (LogFileMode & EVENT_TRACE_DELAY_OPEN_FILE_MODE))
  165. DesiredAccess |= TRACELOG_CREATE_ONDISK;
  166. EnableFlags = LoggerInfo->EnableFlags;
  167. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  168. FlagExt = (PTRACE_ENABLE_FLAG_EXTENSION) &EnableFlags;
  169. if ((FlagExt->Length == 0) || (FlagExt->Offset == 0))
  170. return STATUS_INVALID_PARAMETER;
  171. if ((FlagExt->Length * sizeof(ULONG)) >
  172. (LoggerInfo->Wnode.BufferSize - FlagExt->Offset))
  173. return STATUS_INVALID_PARAMETER;
  174. }
  175. if (LogFileMode & EVENT_TRACE_FILE_MODE_NEWFILE) {
  176. if ((LoggerInfo->LogFileName.Buffer == NULL) ||
  177. (LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) ||
  178. (LoggerInfo->MaximumFileSize == 0))
  179. return STATUS_INVALID_PARAMETER;
  180. }
  181. RequestorMode = KeGetPreviousMode();
  182. if (LoggerInfo->LoggerName.Length > 0) {
  183. LoggerName.Buffer = NULL;
  184. try {
  185. if (RequestorMode != KernelMode) {
  186. ProbeForRead(
  187. LoggerInfo->LoggerName.Buffer,
  188. LoggerInfo->LoggerName.Length,
  189. sizeof (UCHAR) );
  190. }
  191. if (! RtlCreateUnicodeString(
  192. &LoggerName,
  193. LoggerInfo->LoggerName.Buffer) ) {
  194. Status = STATUS_NO_MEMORY;
  195. }
  196. }
  197. except (EXCEPTION_EXECUTE_HANDLER) {
  198. if (LoggerName.Buffer) {
  199. RtlFreeUnicodeString(&LoggerName);
  200. }
  201. return GetExceptionCode();
  202. }
  203. Status = WmipLookupLoggerIdByName(&LoggerName, &LoggerId);
  204. if (NT_SUCCESS(Status)) {
  205. RtlFreeUnicodeString(&LoggerName);
  206. return STATUS_OBJECT_NAME_COLLISION;
  207. }
  208. }
  209. //
  210. // TODO: Perhaps make the last entry of table point to another table?
  211. //
  212. RtlZeroMemory(&InstanceGuid, sizeof(GUID));
  213. if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &InstanceGuid)) {
  214. InstanceGuid = EventTraceGuid;
  215. }
  216. else {
  217. InstanceGuid = LoggerInfo->Wnode.Guid;
  218. }
  219. ContextTable = (PWMI_LOGGER_CONTEXT *) &WmipLoggerContext[0];
  220. EnableKernel = IsEqualGUID(&InstanceGuid, &SystemTraceControlGuid);
  221. if (EnableKernel) {
  222. //
  223. // This prevents multiple threads from continuing beyond this
  224. // point in the code. Only the first thread will progress.
  225. //
  226. if (InterlockedCompareExchangePointer( // if already running
  227. &ContextTable[WmipKernelLogger], ContextTable, NULL) != NULL)
  228. return STATUS_OBJECT_NAME_COLLISION;
  229. LoggerId = WmipKernelLogger;
  230. DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
  231. }
  232. else if (IsEqualGUID(&InstanceGuid, &GlobalLoggerGuid)) {
  233. LoggerId = WMI_GLOBAL_LOGGER_ID;
  234. if (InterlockedCompareExchangePointer( // if already running
  235. &ContextTable[LoggerId], ContextTable, NULL) != NULL)
  236. return STATUS_OBJECT_NAME_COLLISION;
  237. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  238. PULONG pFlag;
  239. pFlag = (PULONG) ((PCHAR)LoggerInfo + FlagExt->Offset);
  240. if (*pFlag != 0) {
  241. EnableKernel = TRUE;
  242. IsGlobalForKernel = TRUE;
  243. WmipKernelLogger = LoggerId;
  244. }
  245. }
  246. // everyone has access to send to this
  247. }
  248. else { // other loggers requested
  249. for (LoggerId = 2; LoggerId < MAXLOGGERS; LoggerId++) {
  250. if ( InterlockedCompareExchangePointer(
  251. &ContextTable[LoggerId],
  252. ContextTable,
  253. NULL ) == NULL )
  254. break; // mark the slot as busy by putting in ServiceInfo
  255. }
  256. if (LoggerId >= MAXLOGGERS) { // could not find any more slots
  257. return STATUS_UNSUCCESSFUL;
  258. }
  259. }
  260. #if DBG
  261. RefCount =
  262. #endif
  263. WmipReferenceLogger(LoggerId);
  264. TraceDebug((1, "WmipStartLogger: %d %d->%d\n", LoggerId,
  265. RefCount-1, RefCount));
  266. //
  267. // first, check to see if caller has access to EventTraceGuid
  268. //
  269. Status = WmipCheckGuidAccess(
  270. (LPGUID) &EventTraceGuid,
  271. DesiredAccess
  272. );
  273. if (NT_SUCCESS(Status) && (!IsEqualGUID(&InstanceGuid, &EventTraceGuid))) {
  274. //
  275. // next, check to see if more access required
  276. //
  277. Status = WmipCheckGuidAccess(
  278. (LPGUID) &InstanceGuid,
  279. DesiredAccess
  280. );
  281. }
  282. if (!NT_SUCCESS(Status)) {
  283. #if DBG
  284. RefCount =
  285. #endif
  286. WmipDereferenceLogger(LoggerId);
  287. TraceDebug((1, "WmipStartLogger: Status1=%X %d %d->%d\n",
  288. Status, LoggerId, RefCount+1, RefCount));
  289. ContextTable[LoggerId] = NULL;
  290. return Status;
  291. }
  292. // Next, try and see if we need to get the logfile object first
  293. //
  294. FileObject = NULL;
  295. if (LoggerInfo->LogFileHandle != NULL) {
  296. OBJECT_HANDLE_INFORMATION handleInformation;
  297. ACCESS_MASK grantedAccess;
  298. Status = ObReferenceObjectByHandle(
  299. LoggerInfo->LogFileHandle,
  300. 0L,
  301. IoFileObjectType,
  302. RequestorMode,
  303. (PVOID *) &FileObject,
  304. &handleInformation);
  305. if (NT_SUCCESS(Status)) {
  306. TraceDebug((1, "WmipStartLogger: Referenced FDO %X %X %d\n",
  307. FileObject, LoggerInfo->LogFileHandle,
  308. ((POBJECT_HEADER)FileObject)->PointerCount));
  309. if (RequestorMode != KernelMode) {
  310. grantedAccess = handleInformation.GrantedAccess;
  311. if (!SeComputeGrantedAccesses(grantedAccess, FILE_WRITE_DATA)) {
  312. ObDereferenceObject( FileObject );
  313. TraceDebug((1, "WmipStartLogger: Deref FDO %x %d\n",
  314. FileObject,
  315. ((POBJECT_HEADER)FileObject)->PointerCount));
  316. Status = STATUS_ACCESS_DENIED;
  317. }
  318. }
  319. ObDereferenceObject(FileObject);
  320. }
  321. if (!NT_SUCCESS(Status)) {
  322. #if DBG
  323. RefCount =
  324. #endif
  325. WmipDereferenceLogger(LoggerId);
  326. TraceDebug((1, "WmipStartLogger: Status2=%X %d %d->%d\n",
  327. Status, LoggerId, RefCount+1, RefCount));
  328. ContextTable[LoggerId] = NULL;
  329. return Status;
  330. }
  331. }
  332. LoggerContext = WmipInitContext();
  333. if (LoggerContext == NULL) {
  334. #if DBG
  335. RefCount =
  336. #endif
  337. WmipDereferenceLogger(LoggerId);
  338. Status = STATUS_NO_MEMORY;
  339. TraceDebug((1, "WmipStartLogger: Status5=%X %d %d->%d\n",
  340. Status, LoggerId, RefCount+1, RefCount));
  341. ContextTable[LoggerId] = NULL;
  342. return Status;
  343. }
  344. #ifndef WMI_MUTEX_FREE
  345. WmipInitializeMutex(&LoggerContext->LoggerMutex);
  346. #endif
  347. if (LogFileMode & EVENT_TRACE_USE_PAGED_MEMORY) {
  348. LoggerContext->PoolType = PagedPool;
  349. LoggerContext->LoggerMode |= EVENT_TRACE_USE_PAGED_MEMORY;
  350. }
  351. else {
  352. LoggerContext->PoolType = NonPagedPool;
  353. }
  354. if (LogFileMode & EVENT_TRACE_KD_FILTER_MODE) {
  355. LoggerContext->LoggerMode |= EVENT_TRACE_KD_FILTER_MODE;
  356. LoggerContext->BufferCallback = &KdReportTraceData;
  357. }
  358. LoggerContext->InstanceGuid = InstanceGuid;
  359. // By now, the slot will be allocated properly
  360. LoggerContext->MaximumFileSize = LoggerInfo->MaximumFileSize;
  361. LoggerContext->BuffersWritten = LoggerInfo->BuffersWritten;
  362. LoggerContext->LoggerMode |= LoggerInfo->LogFileMode & 0x0000FFFF;
  363. if (LoggerContext->LoggerMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
  364. LoggerContext->RequestFlag |= REQUEST_FLAG_CIRCULAR_PERSIST;
  365. }
  366. WmipValidateClockType(LoggerInfo);
  367. LoggerContext->UsePerfClock = LoggerInfo->Wnode.ClientContext;
  368. #ifdef WMI_NON_BLOCKING
  369. if (LoggerInfo->FlushTimer > 0)
  370. LoggerContext->FlushTimer = LoggerInfo->FlushTimer;
  371. #else
  372. if (LoggerInfo->FlushTimer > 0)
  373. LoggerContext->FlushTimer.QuadPart = LoggerInfo->FlushTimer
  374. * OneSecond.QuadPart;
  375. #endif //WMI_NON_BLOCKING
  376. if (LoggerInfo->AgeLimit >= 0) { // minimum is 15 minutes
  377. LoggerContext->BufferAgeLimit.QuadPart
  378. = max (DEFAULT_AGE_LIMIT, LoggerInfo->AgeLimit)
  379. * OneSecond.QuadPart * 60;
  380. }
  381. else if (LoggerInfo->AgeLimit < 0) {
  382. LoggerContext->BufferAgeLimit.QuadPart = 0;
  383. }
  384. LoggerContext->LoggerId = LoggerId;
  385. LoggerContext->EnableFlags = EnableFlags;
  386. LoggerContext->KernelTraceOn = EnableKernel;
  387. LoggerContext->MaximumIrql = DEFAULT_MAX_IRQL;
  388. if (EnableKernel) {
  389. //
  390. // Always reserve space for FileTable to allow file trace
  391. // to be turn on/off dynamically
  392. //
  393. WmipFileTable
  394. = (PFILE_OBJECT*) WmipExtendBase(
  395. LoggerContext, MAX_FILE_TABLE_SIZE * sizeof(PVOID));
  396. Status = (WmipFileTable == NULL) ? STATUS_NO_MEMORY : STATUS_SUCCESS;
  397. if (NT_SUCCESS(Status)) {
  398. if (! RtlCreateUnicodeString(
  399. &LoggerContext->LoggerName, KERNEL_LOGGER_CAPTION)) {
  400. Status = STATUS_NO_MEMORY;
  401. }
  402. }
  403. if (!NT_SUCCESS(Status)) {
  404. ExFreePool(LoggerContext); // free the partial context
  405. #if DBG
  406. RefCount =
  407. #endif
  408. WmipDereferenceLogger(LoggerId);
  409. TraceDebug((1, "WmipStartLogger: Status6=%X %d %d->%d\n",
  410. Status, LoggerId, RefCount+1, RefCount));
  411. ContextTable[LoggerId] = NULL;
  412. return Status;
  413. }
  414. }
  415. //
  416. // Next, if user provided acceptable default buffer parameters, use them.
  417. // Otherwise, set them to predetermined default values.
  418. //
  419. if (LoggerInfo->BufferSize > 0) {
  420. if (LoggerInfo->BufferSize > MAX_WMI_BUFFER_SIZE) {
  421. LoggerInfo->BufferSize = MAX_WMI_BUFFER_SIZE;
  422. }
  423. LoggerContext->BufferSize = LoggerInfo->BufferSize * 1024;
  424. }
  425. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  426. if (LoggerInfo->MaximumBuffers >= 2) {
  427. LoggerContext->MaximumBuffers = LoggerInfo->MaximumBuffers;
  428. }
  429. if (LoggerInfo->MinimumBuffers >= 2 &&
  430. LoggerInfo->MinimumBuffers <= LoggerContext->MaximumBuffers) {
  431. LoggerContext->MinimumBuffers = LoggerInfo->MinimumBuffers;
  432. }
  433. RtlInitUnicodeString(&FileName, NULL);
  434. if (LoggerName.Buffer != NULL) {
  435. if (LoggerContext->KernelTraceOn) {
  436. RtlFreeUnicodeString(&LoggerName);
  437. LoggerName.Buffer = NULL;
  438. }
  439. else {
  440. RtlInitUnicodeString(&LoggerContext->LoggerName, LoggerName.Buffer);
  441. }
  442. }
  443. try {
  444. if (LoggerInfo->Checksum != NULL) {
  445. ULONG SizeNeeded = sizeof(WNODE_HEADER)
  446. + sizeof(TRACE_LOGFILE_HEADER);
  447. if (RequestorMode != KernelMode) {
  448. ProbeForRead(LoggerInfo->Checksum, SizeNeeded, sizeof(UCHAR));
  449. }
  450. LoggerContext->LoggerHeader =
  451. ExAllocatePoolWithTag(PagedPool, SizeNeeded, TRACEPOOLTAG);
  452. if (LoggerContext->LoggerHeader != NULL) {
  453. RtlCopyMemory(LoggerContext->LoggerHeader,
  454. LoggerInfo->Checksum,
  455. SizeNeeded);
  456. }
  457. }
  458. if (LoggerContext->KernelTraceOn) {
  459. if (RequestorMode != KernelMode) {
  460. ProbeForWrite(
  461. LoggerInfo->LoggerName.Buffer,
  462. LoggerContext->LoggerName.Length + sizeof(WCHAR),
  463. sizeof (UCHAR) );
  464. }
  465. RtlCopyUnicodeString(
  466. &LoggerInfo->LoggerName, &LoggerContext->LoggerName);
  467. }
  468. if (LoggerInfo->LogFileName.Length > 0) {
  469. if (RequestorMode != KernelMode) {
  470. ProbeForRead(
  471. LoggerInfo->LogFileName.Buffer,
  472. LoggerInfo->LogFileName.Length,
  473. sizeof (UCHAR) );
  474. }
  475. if (! RtlCreateUnicodeString(
  476. &FileName,
  477. LoggerInfo->LogFileName.Buffer) ) {
  478. Status = STATUS_NO_MEMORY;
  479. }
  480. }
  481. //
  482. // Set up the Global mask for Perf traces
  483. //
  484. if (IsGlobalForKernel) {
  485. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  486. GroupMaskSize = FlagExt->Length * sizeof(ULONG);
  487. if (GroupMaskSize < sizeof(PERFINFO_GROUPMASK)) {
  488. GroupMaskSize = sizeof(PERFINFO_GROUPMASK);
  489. }
  490. } else {
  491. GroupMaskSize = sizeof(PERFINFO_GROUPMASK);
  492. }
  493. LoggerContext->EnableFlagArray = (PULONG) WmipExtendBase(LoggerContext, GroupMaskSize);
  494. if (LoggerContext->EnableFlagArray) {
  495. PCHAR FlagArray;
  496. RtlZeroMemory(LoggerContext->EnableFlagArray, GroupMaskSize);
  497. if (EnableFlags & EVENT_TRACE_FLAG_EXTENSION) {
  498. FlagArray = (PCHAR) (FlagExt->Offset + (PCHAR) LoggerInfo);
  499. //
  500. // Copy only the bytes actually supplied
  501. //
  502. RtlCopyMemory(LoggerContext->EnableFlagArray, FlagArray, FlagExt->Length * sizeof(ULONG));
  503. LoggerContext->EnableFlags = LoggerContext->EnableFlagArray[0];
  504. } else {
  505. LoggerContext->EnableFlagArray[0] = EnableFlags;
  506. }
  507. PerfGroupMasks = (PERFINFO_GROUPMASK *) &LoggerContext->EnableFlagArray[0];
  508. } else {
  509. Status = STATUS_NO_MEMORY;
  510. }
  511. } else {
  512. ASSERT((EnableFlags & EVENT_TRACE_FLAG_EXTENSION) ==0);
  513. }
  514. }
  515. except (EXCEPTION_EXECUTE_HANDLER) {
  516. //
  517. // The context is partially set up by now, so have to clean up
  518. //
  519. if (LoggerContext->LoggerName.Buffer != NULL) {
  520. RtlFreeUnicodeString(&LoggerContext->LoggerName);
  521. }
  522. if (FileName.Buffer != NULL) {
  523. RtlFreeUnicodeString(&FileName);
  524. }
  525. if (LoggerContext->LoggerHeader != NULL) {
  526. ExFreePool(LoggerContext->LoggerHeader);
  527. }
  528. #if DBG
  529. RefCount =
  530. #endif
  531. WmipDereferenceLogger(LoggerId);
  532. TraceDebug((1, "WmipStartLogger: Status7=EXCEPTION %d %d->%d\n",
  533. LoggerId, RefCount+1, RefCount));
  534. ContextTable[LoggerId] = NULL;
  535. ExFreePool(LoggerContext); // free the partial context
  536. return GetExceptionCode();
  537. }
  538. if (LoggerContext->LoggerMode & EVENT_TRACE_FILE_MODE_NEWFILE) {
  539. LoggerContext->LogFilePattern = FileName;
  540. Status = WmipGenerateFileName(
  541. &LoggerContext->LogFilePattern,
  542. &LoggerContext->FileCounter,
  543. &LoggerContext->LogFileName);
  544. }
  545. else {
  546. LoggerContext->LogFileName = FileName;
  547. }
  548. if (NT_SUCCESS(Status)) {
  549. // Obtain the security context here so we can use it
  550. // later to impersonate the user, which we will do
  551. // if we cannot access the file as SYSTEM. This
  552. // usually occurs if the file is on a remote machine.
  553. //
  554. ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  555. ServiceQos.ImpersonationLevel = SecurityImpersonation;
  556. ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  557. ServiceQos.EffectiveOnly = TRUE;
  558. Status = SeCreateClientSecurity(
  559. CONTAINING_RECORD(KeGetCurrentThread(), ETHREAD, Tcb),
  560. &ServiceQos,
  561. FALSE,
  562. &LoggerContext->ClientSecurityContext);
  563. }
  564. if (!NT_SUCCESS(Status)) {
  565. #if DBG
  566. RefCount =
  567. #endif
  568. WmipDereferenceLogger(LoggerId);
  569. TraceDebug((1, "WmipStartLogger: Status8=%X %d %d->%d\n",
  570. Status, LoggerId, RefCount+1, RefCount));
  571. ContextTable[LoggerId] = NULL;
  572. if (LoggerContext != NULL) {
  573. if (LoggerContext->LoggerHeader != NULL) {
  574. ExFreePool(LoggerContext->LoggerHeader);
  575. }
  576. ExFreePool(LoggerContext);
  577. }
  578. return(Status);
  579. }
  580. //
  581. // Now, allocate the buffer pool and associated buffers.
  582. // Note that buffer allocation routine will also set NumberOfBuffers and
  583. // MaximumBuffers.
  584. //
  585. #ifdef WMI_NON_BLOCKING
  586. KeInitializeSpinLock (&WmiSlistLock);
  587. InitializeSListHead (&LoggerContext->FreeList);
  588. InitializeSListHead (&LoggerContext->FlushList);
  589. InitializeSListHead (&LoggerContext->GlobalList);
  590. #else
  591. InitializeListHead(&LoggerContext->FreeList);
  592. InitializeListHead(&LoggerContext->FlushList);
  593. #endif //WMI_NON_BLOCKING
  594. #ifdef NTPERF
  595. //
  596. // Check if we are logging into perfmem.
  597. //
  598. if (PERFINFO_IS_PERFMEM_ALLOCATED()) {
  599. if (NT_SUCCESS(PerfInfoStartPerfMemLog())) {
  600. LoggerContext->MaximumBuffers = PerfQueryBufferSizeBytes()/LoggerContext->BufferSize;
  601. }
  602. }
  603. #endif //NTPERF
  604. Status = WmipAllocateTraceBufferPool(LoggerContext);
  605. if (!NT_SUCCESS(Status)) {
  606. if (LoggerContext != NULL) {
  607. if (LoggerContext->LoggerHeader != NULL) {
  608. ExFreePool(LoggerContext->LoggerHeader);
  609. }
  610. ExFreePool(LoggerContext);
  611. }
  612. #if DBG
  613. RefCount =
  614. #endif
  615. WmipDereferenceLogger(LoggerId);
  616. TraceDebug((1, "WmipStartLogger: Status9=%X %d %d->%d\n",
  617. Status, LoggerId, RefCount+1, RefCount));
  618. ContextTable[LoggerId] = NULL;
  619. return Status;
  620. }
  621. //
  622. // From this point on, LoggerContext is a valid structure
  623. //
  624. LoggerInfo->NumberOfBuffers = (ULONG) LoggerContext->NumberOfBuffers;
  625. LoggerInfo->MaximumBuffers = LoggerContext->MaximumBuffers;
  626. LoggerInfo->MinimumBuffers = LoggerContext->MinimumBuffers;
  627. LoggerInfo->FreeBuffers = (ULONG) LoggerContext->BuffersAvailable;
  628. LoggerInfo->EnableFlags = LoggerContext->EnableFlags;
  629. LoggerInfo->AgeLimit = (ULONG) (LoggerContext->BufferAgeLimit.QuadPart
  630. / OneSecond.QuadPart / 60);
  631. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  632. WmiSetLoggerId(LoggerId,
  633. (PTRACE_ENABLE_CONTEXT)&LoggerInfo->Wnode.HistoricalContext);
  634. if (LoggerContext->LoggerMode & EVENT_TRACE_USE_LOCAL_SEQUENCE)
  635. LoggerContext->SequencePtr = (PLONG) &LoggerContext->LocalSequence;
  636. else if (LoggerContext->LoggerMode & EVENT_TRACE_USE_GLOBAL_SEQUENCE)
  637. LoggerContext->SequencePtr = (PLONG) &WmipGlobalSequence;
  638. // Initialize synchronization event with logger
  639. KeInitializeEvent(
  640. &LoggerContext->LoggerEvent,
  641. NotificationEvent,
  642. FALSE
  643. );
  644. KeInitializeEvent(
  645. &LoggerContext->FlushEvent,
  646. NotificationEvent,
  647. FALSE
  648. );
  649. //
  650. // Close file handle here so that it can be opened by system thread
  651. //
  652. if (LoggerInfo->LogFileHandle != NULL) {
  653. ZwClose(LoggerInfo->LogFileHandle);
  654. LoggerInfo->LogFileHandle = NULL;
  655. }
  656. //
  657. // User Mode call always gets APPEND mode
  658. //
  659. LogFileMode = LoggerContext->LoggerMode;
  660. if (RequestorMode != KernelMode) {
  661. LoggerContext->LoggerMode |= EVENT_TRACE_FILE_MODE_APPEND;
  662. }
  663. //
  664. // Start up the logger as a system thread
  665. //
  666. if (NT_SUCCESS(Status)) {
  667. Status = PsCreateSystemThread(
  668. &ThreadHandle,
  669. THREAD_ALL_ACCESS,
  670. NULL,
  671. NULL,
  672. NULL,
  673. WmipLogger,
  674. LoggerContext );
  675. }
  676. if (NT_SUCCESS(Status)) { // if SystemThread is started
  677. ZwClose (ThreadHandle);
  678. // Wait for Logger to start up properly before proceeding
  679. //
  680. KeWaitForSingleObject(
  681. &LoggerContext->LoggerEvent,
  682. Executive,
  683. KernelMode,
  684. FALSE,
  685. &TimeOut
  686. );
  687. KeResetEvent(&LoggerContext->LoggerEvent);
  688. //
  689. // If the logger is up and running properly, we can now turn on
  690. // event tracing if kernel tracing is requested
  691. //
  692. if (NT_SUCCESS(LoggerContext->LoggerStatus)) {
  693. ULONG i;
  694. ULONG NumberProcessors = (ULONG) KeNumberProcessors;
  695. PLIST_ENTRY pHead, pNext;
  696. PWMI_BUFFER_HEADER pBuffer;
  697. LoggerContext->LoggerMode = LogFileMode;
  698. LoggerContext->WriteFailureLimit = 100;
  699. #ifdef NTPERF
  700. if (EnableKernel) {
  701. WmiGetCpuClock = &PerfGetCycleCount;
  702. }
  703. LoggerContext->GetCpuClock = &PerfGetCycleCount;
  704. #else
  705. switch (LoggerContext->UsePerfClock) {
  706. case EVENT_TRACE_CLOCK_SYSTEMTIME:
  707. if (EnableKernel) {
  708. WmiGetCpuClock = &WmipGetSystemTime;
  709. }
  710. LoggerContext->GetCpuClock = &WmipGetSystemTime;
  711. break;
  712. case EVENT_TRACE_CLOCK_PERFCOUNTER:
  713. default :
  714. if (EnableKernel) {
  715. WmiGetCpuClock = &WmipGetPerfCounter;
  716. }
  717. LoggerContext->GetCpuClock = &WmipGetPerfCounter;
  718. break;
  719. }
  720. #endif //NTPERF
  721. #ifndef WMI_NON_BLOCKING
  722. pHead = &LoggerContext->FreeList;
  723. pNext = pHead->Flink;
  724. while (pNext != pHead) {
  725. pBuffer = (PWMI_BUFFER_HEADER)
  726. CONTAINING_RECORD(pNext, WMI_BUFFER_HEADER, Entry);
  727. pBuffer->UsePerfClock = LoggerContext->UsePerfClock;
  728. pNext = pNext->Flink;
  729. }
  730. #endif //WMI_NON_BLOCKING
  731. //
  732. // At this point, the clock type should be set and we take a
  733. // reference timesamp, which should be the earliest timestamp
  734. // for the logger. The order is this way sine SystemTime
  735. // is typically cheaper to obtain.
  736. //
  737. PerfTimeStamp(LoggerContext->ReferenceTimeStamp);
  738. KeQuerySystemTime(&LoggerContext->ReferenceSystemTime);
  739. //
  740. // Lock down the routines that need to be non-pageable
  741. //
  742. ExAcquireFastMutex(&WmipTraceFastMutex);
  743. if (++WmipLoggerCount == 1) {
  744. ASSERT(WmipPageLockHandle);
  745. MmLockPagableSectionByHandle(WmipPageLockHandle);
  746. WmipGlobalSequence = 0;
  747. }
  748. ExReleaseFastMutex(&WmipTraceFastMutex);
  749. //
  750. // After we release this mutex, any other thread can acquire
  751. // the valid logger context and call the shutdown path for
  752. // this logger. Until this, no other thread can call the enable
  753. // or disable code for this logger.
  754. //
  755. WmipAcquireMutex( &LoggerContext->LoggerMutex );
  756. InterlockedIncrement(&LoggerContext->MutexCount);
  757. LoggerInfo->BuffersWritten = LoggerContext->BuffersWritten;
  758. WmipLoggerContext[LoggerId] = LoggerContext;
  759. TraceDebug((1, "WmipStartLogger: Started %X %d\n",
  760. LoggerContext, LoggerContext->LoggerId));
  761. if (LoggerContext->KernelTraceOn) {
  762. EnableFlags = LoggerContext->EnableFlags;
  763. if (EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO)
  764. EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
  765. WmipEnableKernelTrace(EnableFlags);
  766. }
  767. if (IsEqualGUID(&InstanceGuid, &WmiEventLoggerGuid)) {
  768. WmipEventLogger = LoggerId;
  769. EnableFlags = EVENT_TRACE_FLAG_PROCESS |
  770. EVENT_TRACE_FLAG_THREAD |
  771. EVENT_TRACE_FLAG_IMAGE_LOAD;
  772. WmipEnableKernelTrace(EnableFlags);
  773. LoggerContext->EnableFlags = EnableFlags;
  774. }
  775. if (LoggerContext->LoggerThread) {
  776. LoggerInfo->LoggerThreadId
  777. = LoggerContext->LoggerThread->Cid.UniqueThread;
  778. }
  779. //
  780. // Logger is started properly, now turn on perf trace
  781. //
  782. if (IsGlobalForKernel) {
  783. Status = PerfInfoStartLog(PerfGroupMasks,
  784. PERFINFO_START_LOG_FROM_GLOBAL_LOGGER);
  785. }
  786. InterlockedDecrement(&LoggerContext->MutexCount);
  787. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  788. // LoggerContext refcount is now >= 1 until it is stopped
  789. return Status;
  790. }
  791. Status = LoggerContext->LoggerStatus;
  792. }
  793. TraceDebug((2, "WmipStartLogger: %d %X failed with status=%X ref %d\n",
  794. LoggerId, LoggerContext, Status, WmipRefCount[LoggerId]));
  795. //
  796. // will get here if Status has failed earlier.
  797. if (LoggerContext != NULL) { // should not be NULL
  798. // WmipReferenceLogger(LoggerId); // Below will deref twice
  799. WmipFreeLoggerContext(LoggerContext);
  800. }
  801. else {
  802. WmipDereferenceLogger(LoggerId);
  803. ContextTable[LoggerId] = NULL;
  804. }
  805. return STATUS_UNSUCCESSFUL;
  806. }
  807. NTSTATUS
  808. WmipQueryLogger(
  809. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo,
  810. IN PWMI_LOGGER_CONTEXT LoggerContext
  811. )
  812. /*++
  813. Routine Description:
  814. This routine is called to control the data collection and logger.
  815. It is called by WmipIoControl in wmi.c, with IOCTL_WMI_QUERY_LOGGER.
  816. Caller must pass in either the Logger Name or a valid Logger Id/Handle.
  817. Arguments:
  818. LoggerInfo a pointer to the structure for the logger's control
  819. and status information
  820. LoggerContext if this is provided, it assumes it is a valid one
  821. Return Value:
  822. The status of performing the action requested.
  823. --*/
  824. {
  825. NTSTATUS Status;
  826. ULONG LoggerId, NoContext;
  827. LARGE_INTEGER OneSecond = {(ULONG)(-1 * 1000 * 1000 * 10), -1};
  828. ACCESS_MASK DesiredAccess = WMIGUID_QUERY;
  829. KPROCESSOR_MODE RequestorMode;
  830. #if DBG
  831. LONG RefCount;
  832. #endif
  833. PAGED_CODE();
  834. NoContext = (LoggerContext == NULL);
  835. if (NoContext) {
  836. if ((LoggerInfo->Wnode.HistoricalContext == 0XFFFF) || (LoggerInfo->Wnode.HistoricalContext < 1))
  837. TraceDebug((2, "WmipQueryLogger: %d\n",
  838. LoggerInfo->Wnode.HistoricalContext));
  839. #if DBG
  840. Status = WmipVerifyLoggerInfo(
  841. LoggerInfo, &LoggerContext, "WmipQueryLogger");
  842. #else
  843. Status = WmipVerifyLoggerInfo( LoggerInfo, &LoggerContext );
  844. #endif
  845. if (!NT_SUCCESS(Status) || (LoggerContext == NULL))
  846. return Status; // cannot find by name nor logger id
  847. LoggerInfo->Wnode.Flags = 0;
  848. LoggerInfo->EnableFlags = 0;
  849. LoggerId = (ULONG) LoggerContext->LoggerId;
  850. if (LoggerContext->KernelTraceOn) {
  851. DesiredAccess |= TRACELOG_ACCESS_KERNEL_LOGGER;
  852. }
  853. Status = WmipCheckGuidAccess(
  854. (LPGUID) &EventTraceGuid,
  855. DesiredAccess
  856. );
  857. if (!NT_SUCCESS(Status)) {
  858. #ifndef WMI_MUTEX_FREE
  859. InterlockedDecrement(&LoggerContext->MutexCount);
  860. TraceDebug((1, "WmipQueryLogger: Release mutex1 %d %d\n",
  861. LoggerId, LoggerContext->MutexCount));
  862. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  863. #endif
  864. #if DBG
  865. RefCount =
  866. #endif
  867. WmipDereferenceLogger(LoggerId);
  868. TraceDebug((1, "WmipQueryLogger: Status1=%X %d %d->%d\n",
  869. Status, LoggerId, RefCount+1, RefCount));
  870. return Status;
  871. }
  872. if (!IsEqualGUID(&LoggerContext->InstanceGuid, &EventTraceGuid)) {
  873. Status = WmipCheckGuidAccess(
  874. (LPGUID) &LoggerContext->InstanceGuid,
  875. DesiredAccess
  876. );
  877. if (!NT_SUCCESS(Status)) {
  878. #ifndef WMI_MUTEX_FREE
  879. InterlockedDecrement(&LoggerContext->MutexCount);
  880. TraceDebug((1, "WmipQueryLogger: Release mutex2 %d %d\n",
  881. LoggerId, LoggerContext->MutexCount));
  882. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  883. #endif
  884. #if DBG
  885. RefCount =
  886. #endif
  887. WmipDereferenceLogger(LoggerId);
  888. TraceDebug((1, "WmipQueryLogger: Status2=%X %d %d->%d\n",
  889. Status, LoggerId, RefCount+1, RefCount));
  890. return Status;
  891. }
  892. }
  893. }
  894. else {
  895. LoggerId = LoggerContext->LoggerId;
  896. }
  897. if (LoggerContext->KernelTraceOn) {
  898. LoggerInfo->Wnode.Guid = SystemTraceControlGuid;
  899. LoggerInfo->EnableFlags = LoggerContext->EnableFlags;
  900. }
  901. else
  902. LoggerInfo->Wnode.Guid = LoggerContext->InstanceGuid;
  903. LoggerInfo->LogFileMode = LoggerContext->LoggerMode;
  904. LoggerInfo->MaximumFileSize = LoggerContext->MaximumFileSize;
  905. #ifdef WMI_NON_BLOCKING
  906. LoggerInfo->FlushTimer = LoggerContext->FlushTimer;
  907. #else
  908. LoggerInfo->FlushTimer = (ULONG) (LoggerContext->FlushTimer.QuadPart
  909. / OneSecond.QuadPart);
  910. #endif //WMI_NON_BLOCKING
  911. LoggerInfo->BufferSize = LoggerContext->BufferSize / 1024;
  912. LoggerInfo->NumberOfBuffers = (ULONG) LoggerContext->NumberOfBuffers;
  913. LoggerInfo->MinimumBuffers = LoggerContext->MinimumBuffers;
  914. LoggerInfo->MaximumBuffers = LoggerContext->MaximumBuffers;
  915. LoggerInfo->EventsLost = LoggerContext->EventsLost;
  916. LoggerInfo->FreeBuffers = (ULONG) LoggerContext->BuffersAvailable;
  917. LoggerInfo->BuffersWritten = LoggerContext->BuffersWritten;
  918. LoggerInfo->LogBuffersLost = LoggerContext->LogBuffersLost;
  919. LoggerInfo->RealTimeBuffersLost = LoggerContext->RealTimeBuffersLost;
  920. LoggerInfo->AgeLimit = (ULONG)
  921. (LoggerContext->BufferAgeLimit.QuadPart
  922. / OneSecond.QuadPart / 60);
  923. WmiSetLoggerId(LoggerId,
  924. (PTRACE_ENABLE_CONTEXT)&LoggerInfo->Wnode.HistoricalContext);
  925. if (LoggerContext->LoggerThread) {
  926. LoggerInfo->LoggerThreadId
  927. = LoggerContext->LoggerThread->Cid.UniqueThread;
  928. }
  929. LoggerInfo->Wnode.ClientContext = LoggerContext->UsePerfClock;
  930. //
  931. // Return LogFileName and Logger Caption here
  932. //
  933. RequestorMode = KeGetPreviousMode();
  934. try {
  935. if (LoggerContext->LogFileName.Length > 0 &&
  936. LoggerInfo->LogFileName.MaximumLength > 0) {
  937. if (RequestorMode != KernelMode) {
  938. ProbeForWrite(
  939. LoggerInfo->LogFileName.Buffer,
  940. LoggerContext->LogFileName.Length + sizeof(WCHAR),
  941. sizeof (UCHAR) );
  942. }
  943. RtlCopyUnicodeString(
  944. &LoggerInfo->LogFileName,
  945. &LoggerContext->LogFileName);
  946. }
  947. if (LoggerContext->LoggerName.Length > 0 &&
  948. LoggerInfo->LoggerName.MaximumLength > 0) {
  949. if (RequestorMode != KernelMode) {
  950. ProbeForWrite(
  951. LoggerInfo->LoggerName.Buffer,
  952. LoggerContext->LoggerName.Length + sizeof(WCHAR),
  953. sizeof(UCHAR));
  954. }
  955. RtlCopyUnicodeString(
  956. &LoggerInfo->LoggerName,
  957. &LoggerContext->LoggerName);
  958. }
  959. }
  960. except (EXCEPTION_EXECUTE_HANDLER) {
  961. if (NoContext) {
  962. #ifndef WMI_MUTEX_FREE
  963. InterlockedDecrement(&LoggerContext->MutexCount);
  964. TraceDebug((1, "WmipQueryLogger: Release mutex3 %d %d\n",
  965. LoggerId, LoggerContext->MutexCount));
  966. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  967. #endif
  968. #if DBG
  969. RefCount =
  970. #endif
  971. WmipDereferenceLogger(LoggerId);
  972. TraceDebug((1, "WmipQueryLogger: Status3=EXCEPTION %d %d->%d\n",
  973. LoggerId, RefCount+1, RefCount));
  974. }
  975. return GetExceptionCode();
  976. }
  977. if (NoContext) {
  978. #if DBG
  979. RefCount =
  980. #endif
  981. WmipDereferenceLogger(LoggerId);
  982. TraceDebug((1, "WmipQueryLogger: %d %d->%d\n",
  983. LoggerId, RefCount+1, RefCount));
  984. #ifndef WMI_MUTEX_FREE
  985. InterlockedDecrement(&LoggerContext->MutexCount);
  986. TraceDebug((1, "WmipQueryLogger: Release mutex %d %d\n",
  987. LoggerId, LoggerContext->MutexCount));
  988. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  989. #endif
  990. }
  991. return STATUS_SUCCESS;
  992. }
  993. NTSTATUS
  994. WmipStopLoggerInstance(
  995. IN PWMI_LOGGER_CONTEXT LoggerContext
  996. )
  997. {
  998. LONG LoggerOn;
  999. PAGED_CODE();
  1000. if (LoggerContext == NULL) { // just in case
  1001. return STATUS_INVALID_HANDLE;
  1002. }
  1003. if (LoggerContext->KernelTraceOn) {
  1004. // PerfInfoStopLog should not be executed when perf logging is starting
  1005. // or stopping by other thread. PerfLogInTransition flag in the logger
  1006. // context should only be used here and UpdateTrace and NO WHERE ELSE.
  1007. LONG PerfLogInTransition =
  1008. InterlockedCompareExchange(&LoggerContext->PerfLogInTransition,
  1009. PERF_LOG_STOP_TRANSITION,
  1010. PERF_LOG_NO_TRANSITION);
  1011. if (PerfLogInTransition == PERF_LOG_START_TRANSITION) {
  1012. // This is the logger thread, and it is terminating.
  1013. // UpdateTrace call is enabling perf logging at the moment.
  1014. // Come back later.
  1015. return STATUS_UNSUCCESSFUL;
  1016. }
  1017. else if (PerfLogInTransition == PERF_LOG_STOP_TRANSITION) {
  1018. return STATUS_ALREADY_DISCONNECTED;
  1019. }
  1020. //
  1021. // Time to turn off trace in perf tools
  1022. //
  1023. PerfInfoStopLog();
  1024. }
  1025. //
  1026. // turn off data tracing first
  1027. //
  1028. LoggerOn = InterlockedExchange(&LoggerContext->CollectionOn, FALSE);
  1029. if (LoggerOn == FALSE) {
  1030. // This happens if another stoplogger already in progress
  1031. return STATUS_ALREADY_DISCONNECTED;
  1032. }
  1033. if (LoggerContext->KernelTraceOn) {
  1034. //
  1035. // Turn off everything, just to be on the safe side
  1036. // NOTE: If we start sharing callouts, the argument should be
  1037. // LoggerContext->EnableFlags
  1038. //
  1039. WmipDisableKernelTrace(LoggerContext->EnableFlags);
  1040. }
  1041. if (LoggerContext->LoggerId == WmipEventLogger) {
  1042. WmipDisableKernelTrace(EVENT_TRACE_FLAG_PROCESS |
  1043. EVENT_TRACE_FLAG_THREAD |
  1044. EVENT_TRACE_FLAG_IMAGE_LOAD);
  1045. WmipEventLogger = 0xFFFFFFFF;
  1046. }
  1047. //
  1048. // Mark the table entry as in-transition
  1049. // From here on, the stop operation will not fail
  1050. //
  1051. WmipLoggerContext[LoggerContext->LoggerId] = (PWMI_LOGGER_CONTEXT)
  1052. &WmipLoggerContext[0];
  1053. WmipNotifyLogger(LoggerContext);
  1054. WmipSendNotification(LoggerContext, STATUS_THREAD_IS_TERMINATING, 0);
  1055. return STATUS_SUCCESS;
  1056. }
  1057. NTSTATUS
  1058. WmipVerifyLoggerInfo(
  1059. IN PWMI_LOGGER_INFORMATION LoggerInfo,
  1060. #if DBG
  1061. OUT PWMI_LOGGER_CONTEXT *pLoggerContext,
  1062. IN LPSTR Caller
  1063. #else
  1064. OUT PWMI_LOGGER_CONTEXT *pLoggerContext
  1065. #endif
  1066. )
  1067. {
  1068. NTSTATUS Status = STATUS_SEVERITY_ERROR;
  1069. ULONG LoggerId;
  1070. UNICODE_STRING LoggerName;
  1071. KPROCESSOR_MODE RequestorMode;
  1072. PWMI_LOGGER_CONTEXT LoggerContext, CurrentContext;
  1073. LONG MutexCount = 0;
  1074. #if DBG
  1075. LONG RefCount;
  1076. #endif
  1077. PAGED_CODE();
  1078. *pLoggerContext = NULL;
  1079. if (LoggerInfo == NULL)
  1080. return STATUS_SEVERITY_ERROR;
  1081. //
  1082. // try and check for bogus parameter
  1083. // if the size is at least what we want, we have to assume it's valid
  1084. //
  1085. if (LoggerInfo->Wnode.BufferSize < sizeof(WMI_LOGGER_INFORMATION))
  1086. return STATUS_INVALID_BUFFER_SIZE;
  1087. if (! (LoggerInfo->Wnode.Flags & WNODE_FLAG_TRACED_GUID) )
  1088. return STATUS_INVALID_PARAMETER;
  1089. RtlInitUnicodeString(&LoggerName, NULL);
  1090. RequestorMode = KeGetPreviousMode();
  1091. try {
  1092. if (LoggerInfo->LoggerName.Length > 0) {
  1093. if (RequestorMode != KernelMode) {
  1094. ProbeForRead(
  1095. LoggerInfo->LoggerName.Buffer,
  1096. LoggerInfo->LoggerName.Length,
  1097. sizeof (UCHAR) );
  1098. }
  1099. RtlCreateUnicodeString(
  1100. &LoggerName,
  1101. LoggerInfo->LoggerName.Buffer);
  1102. }
  1103. }
  1104. except (EXCEPTION_EXECUTE_HANDLER) {
  1105. if (LoggerName.Buffer != NULL) {
  1106. RtlFreeUnicodeString(&LoggerName);
  1107. }
  1108. return GetExceptionCode();
  1109. }
  1110. Status = STATUS_SUCCESS;
  1111. if (IsEqualGUID(&LoggerInfo->Wnode.Guid, &SystemTraceControlGuid)) {
  1112. LoggerId = WmipKernelLogger;
  1113. }
  1114. else if (LoggerName.Length > 0) { // Logger Name is passed
  1115. Status = WmipLookupLoggerIdByName(&LoggerName, &LoggerId);
  1116. }
  1117. else {
  1118. LoggerId = WmiGetLoggerId(LoggerInfo->Wnode.HistoricalContext);
  1119. if (LoggerId == KERNEL_LOGGER_ID) {
  1120. LoggerId = WmipKernelLogger;
  1121. }
  1122. else if (LoggerId < 1 || LoggerId >= MAXLOGGERS) {
  1123. Status = STATUS_INVALID_HANDLE;
  1124. }
  1125. }
  1126. if (LoggerName.Buffer != NULL) {
  1127. RtlFreeUnicodeString(&LoggerName);
  1128. }
  1129. if (!NT_SUCCESS(Status)) // cannot find by name nor logger id
  1130. return Status;
  1131. #if DBG
  1132. RefCount =
  1133. #endif
  1134. WmipReferenceLogger(LoggerId);
  1135. if (LoggerId < 1)
  1136. TraceDebug((2, "WmipVerifyLoggerInfo(%s): %d %d->%d\n",
  1137. Caller, LoggerId, RefCount-1, RefCount));
  1138. LoggerContext = WmipGetLoggerContext( LoggerId );
  1139. if (!WmipIsValidLogger(LoggerContext)) {
  1140. #if DBG
  1141. RefCount =
  1142. #endif
  1143. WmipDereferenceLogger(LoggerId);
  1144. if (LoggerId < 1)
  1145. TraceDebug((2, "WmipVerifyLoggerInfo(%s): Status=%X %d %d->%d\n",
  1146. Caller, STATUS_WMI_INSTANCE_NOT_FOUND,
  1147. LoggerId, RefCount+1, RefCount));
  1148. return STATUS_WMI_INSTANCE_NOT_FOUND;
  1149. }
  1150. #ifndef WMI_MUTEX_FREE
  1151. InterlockedIncrement(&LoggerContext->MutexCount);
  1152. TraceDebug((1, "WmipVerifyLoggerInfo: Acquiring mutex... %d %d\n",
  1153. LoggerId, LoggerContext->MutexCount));
  1154. WmipAcquireMutex (&LoggerContext->LoggerMutex);
  1155. TraceDebug((1, "WmipVerifyLoggerInfo: Acquired mutex %d %d %X\n",
  1156. LoggerId, LoggerContext->MutexCount, LoggerContext));
  1157. #endif
  1158. // Need to check for validity of LoggerContext in mutex
  1159. CurrentContext = WmipGetLoggerContext( LoggerId );
  1160. if (!WmipIsValidLogger(CurrentContext) ||
  1161. !LoggerContext->CollectionOn ) {
  1162. #ifndef WMI_MUTEX_FREE
  1163. TraceDebug((1, "WmipVerifyLoggerInfo: Released mutex %d %d\n",
  1164. LoggerId, LoggerContext->MutexCount-1));
  1165. WmipReleaseMutex(&LoggerContext->LoggerMutex);
  1166. MutexCount = InterlockedDecrement(&LoggerContext->MutexCount);
  1167. #endif
  1168. #if DBG
  1169. RefCount =
  1170. #endif
  1171. WmipDereferenceLogger(LoggerId);
  1172. TraceDebug((2, "WmipVerifyLoggerInfo(%s): Status2=%X %d %d->%d\n",
  1173. Caller, STATUS_WMI_INSTANCE_NOT_FOUND,
  1174. LoggerId, RefCount+1, RefCount));
  1175. return STATUS_WMI_INSTANCE_NOT_FOUND;
  1176. }
  1177. *pLoggerContext = LoggerContext;
  1178. return STATUS_SUCCESS;
  1179. }
  1180. PVOID
  1181. WmipExtendBase(
  1182. IN PWMI_LOGGER_CONTEXT Base,
  1183. IN ULONG Size
  1184. )
  1185. {
  1186. //
  1187. // This private routine only return space from the Base by extending its
  1188. // offset. It does not actually try and allocate memory from the system
  1189. //
  1190. // It rounds the size to a ULONGLONG alignment and expects EndPageMarker
  1191. // to already be aligned.
  1192. //
  1193. PVOID Space = NULL;
  1194. ULONG SpaceLeft;
  1195. PAGED_CODE();
  1196. ASSERT(((ULONGLONG) Base->EndPageMarker % sizeof(ULONGLONG)) == 0);
  1197. //
  1198. // Round up to pointer boundary
  1199. //
  1200. Size = ALIGN_TO_POWER2(Size, DEFAULT_TRACE_ALIGNMENT);
  1201. SpaceLeft = CONTEXT_SIZE - (ULONG) (Base->EndPageMarker - (PUCHAR)Base);
  1202. if ( SpaceLeft > Size ) {
  1203. Space = Base->EndPageMarker;
  1204. Base->EndPageMarker += Size;
  1205. }
  1206. return Space;
  1207. }
  1208. VOID
  1209. WmipFreeLoggerContext(
  1210. IN PWMI_LOGGER_CONTEXT LoggerContext
  1211. )
  1212. {
  1213. ULONG LoggerId;
  1214. ULONG i;
  1215. LONG RefCount;
  1216. LARGE_INTEGER Timeout = {(ULONG)(-50 * 1000 * 10), -1}; // 50 ms
  1217. NTSTATUS Status = STATUS_TIMEOUT;
  1218. LONG count = 0;
  1219. PAGED_CODE();
  1220. if (LoggerContext == NULL)
  1221. return; // should not happen
  1222. if (LoggerContext->LoggerHeader != NULL) {
  1223. ExFreePool(LoggerContext->LoggerHeader);
  1224. }
  1225. LoggerId = LoggerContext->LoggerId;
  1226. //
  1227. // The RefCount must be at least 2 at this point.
  1228. // One was set by WmipStartLogger() in the beginning, and the
  1229. // second must be done normally by WmiStopTrace() or anybody who
  1230. // needs to call this routine to free the logger context
  1231. //
  1232. // RefCount = WmipDereferenceLogger(LoggerId);
  1233. KeResetEvent(&LoggerContext->LoggerEvent);
  1234. RefCount = WmipRefCount[LoggerId];
  1235. WmipAssert(RefCount >= 1);
  1236. TraceDebug((1, "WmipFreeLoggerContext: %d %d->%d\n",
  1237. LoggerId, RefCount+1, RefCount));
  1238. while (Status == STATUS_TIMEOUT) {
  1239. count ++;
  1240. Status = KeWaitForSingleObject(
  1241. &LoggerContext->LoggerEvent,
  1242. Executive,
  1243. KernelMode,
  1244. FALSE,
  1245. &Timeout);
  1246. KeResetEvent(&LoggerContext->LoggerEvent);
  1247. KeSetEvent(&LoggerContext->FlushEvent, 0, FALSE); // Just to be sure
  1248. #ifndef WMI_MUTEX_FREE
  1249. if (LoggerContext->MutexCount >= 1) {
  1250. KeResetEvent(&LoggerContext->LoggerEvent);
  1251. Status = STATUS_TIMEOUT;
  1252. continue;
  1253. }
  1254. #endif
  1255. if (WmipRefCount[LoggerId] <= 1)
  1256. break;
  1257. /*
  1258. // For temporary Debugging only
  1259. if (WmipRefCount[LoggerId] == RefCount) {
  1260. if (count > 495) {
  1261. TraceDebug((0,
  1262. "WmipFreeLoggerContext: %d Waiting for %d ref %d\n",
  1263. count, LoggerId, RefCount));
  1264. }
  1265. if (count >= 500) { // temporarily only to catch synch problems
  1266. TraceDebug((0, "WmipFreeLoggerContext: Resetting %d...\n",
  1267. LoggerId));
  1268. break;
  1269. }
  1270. Status = STATUS_TIMEOUT; // try again
  1271. }
  1272. #if DBG
  1273. else if (count > 495) {
  1274. TraceDebug((0, "WmipFreeLoggerContext: %d Logger %d ref %d\n",
  1275. count, LoggerId, WmipRefCount[LoggerId]));
  1276. }
  1277. #endif
  1278. */
  1279. RefCount = WmipRefCount[LoggerId];
  1280. }
  1281. ExAcquireFastMutex(&WmipTraceFastMutex);
  1282. if (--WmipLoggerCount == 0) {
  1283. if (WmipPageLockHandle) {
  1284. MmUnlockPagableImageSection(WmipPageLockHandle);
  1285. }
  1286. #if DBG
  1287. else {
  1288. ASSERT(WmipPageLockHandle);
  1289. }
  1290. #endif
  1291. }
  1292. ExReleaseFastMutex(&WmipTraceFastMutex);
  1293. WmipFreeTraceBufferPool(LoggerContext);
  1294. if (LoggerContext->LoggerName.Buffer != NULL) {
  1295. RtlFreeUnicodeString(&LoggerContext->LoggerName);
  1296. }
  1297. if (LoggerContext->LogFileName.Buffer != NULL) {
  1298. RtlFreeUnicodeString(&LoggerContext->LogFileName);
  1299. }
  1300. if (LoggerContext->NewLogFileName.Buffer != NULL) {
  1301. RtlFreeUnicodeString(&LoggerContext->NewLogFileName);
  1302. }
  1303. #if DBG
  1304. RefCount =
  1305. #endif
  1306. //
  1307. // Finally, decrement the refcount incremented by WmipStartLogger()
  1308. //
  1309. WmipDereferenceLogger(LoggerId);
  1310. #if DBG
  1311. TraceDebug((2, "WmipFreeLoggerContext: Freeing pool %X %d %d->%d\n",
  1312. LoggerContext, LoggerId, RefCount+1, RefCount));
  1313. if (LoggerContext->CollectionOn) {
  1314. TraceDebug((1,
  1315. "WmipFreeLoggerContext: %X %d still active\n", LoggerContext,
  1316. LoggerId));
  1317. // DbgBreakPoint();
  1318. }
  1319. #ifndef WMI_MUTEX_FREE
  1320. if (LoggerContext->MutexCount >= 1) {
  1321. TraceDebug((0, "****ERROR**** Mutex count is %d for %d\n", LoggerId,
  1322. LoggerContext->MutexCount));
  1323. // DbgBreakPoint();
  1324. }
  1325. #endif
  1326. // if (WmipRefCount[LoggerId] >= 1) {
  1327. // TraceDebug((1, "****ERROR**** Ref count for %d is %d\n", LoggerId,
  1328. // WmipRefCount[LoggerId]));
  1329. // DbgBreakPoint();
  1330. // }
  1331. #endif
  1332. ExFreePool(LoggerContext);
  1333. WmipLoggerContext[LoggerId] = NULL;
  1334. }
  1335. PWMI_LOGGER_CONTEXT
  1336. WmipInitContext(
  1337. )
  1338. /*++
  1339. Routine Description:
  1340. This routine is called to initialize the context of LoggerContext
  1341. Arguments:
  1342. None
  1343. Returned Value:
  1344. Status of STATUS_SUCCESS if the allocation was successful
  1345. --*/
  1346. {
  1347. PWMI_LOGGER_CONTEXT LoggerContext;
  1348. ULONG Min_Buffers;
  1349. PAGED_CODE();
  1350. LoggerContext = (PWMI_LOGGER_CONTEXT)
  1351. ExAllocatePoolWithTag(NonPagedPool,
  1352. CONTEXT_SIZE, TRACEPOOLTAG);
  1353. // One page is reserved to store the buffer pool pointers plus anything
  1354. // else that we need. Should experiment a little more to reduce it further
  1355. if (LoggerContext == NULL) {
  1356. return NULL;
  1357. }
  1358. RtlZeroMemory(LoggerContext, CONTEXT_SIZE);
  1359. LoggerContext->EndPageMarker =
  1360. (PUCHAR) LoggerContext +
  1361. ALIGN_TO_POWER2(sizeof(WMI_LOGGER_CONTEXT), DEFAULT_TRACE_ALIGNMENT);
  1362. LoggerContext->BufferSize = PAGE_SIZE;
  1363. LoggerContext->MinimumBuffers = (ULONG)KeNumberProcessors + DEFAULT_BUFFERS;
  1364. // 20 additional buffers for MaximumBuffers
  1365. LoggerContext->MaximumBuffers
  1366. = LoggerContext->MinimumBuffers + DEFAULT_BUFFERS + 20;
  1367. KeQuerySystemTime(&LoggerContext->StartTime);
  1368. KeInitializeSemaphore( &LoggerContext->LoggerSemaphore,
  1369. 0,
  1370. SEMAPHORE_LIMIT );
  1371. KeInitializeSpinLock(&LoggerContext->BufferSpinLock);
  1372. return LoggerContext;
  1373. }
  1374. NTSTATUS
  1375. WmipAllocateTraceBufferPool(
  1376. IN PWMI_LOGGER_CONTEXT LoggerContext
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This routine is used to set up the circular trace buffers
  1381. Arguments:
  1382. LoggerContext Context of the logger to own the buffers.
  1383. Returned Value:
  1384. STATUS_SUCCESS if the initialization is successful
  1385. --*/
  1386. {
  1387. ULONG BufferSize, NumberProcessors, Max_Buffers;
  1388. LONG i;
  1389. PWMI_BUFFER_HEADER Buffer;
  1390. #ifdef WMI_NON_BLOCKING
  1391. ULONG AllocatedBuffers, NumberOfBuffers;
  1392. #endif //WMI_NON_BLOCKING
  1393. PAGED_CODE();
  1394. //
  1395. // Allocate the pointers the each buffer here by sharing the same page
  1396. // with LoggerContext context pointer
  1397. //
  1398. NumberProcessors = (ULONG) KeNumberProcessors;
  1399. Max_Buffers = (ULONG) (MmMaximumNonPagedPoolInBytes
  1400. / TRACE_MAXIMUM_NP_POOL_USAGE
  1401. / LoggerContext->BufferSize);
  1402. if (LoggerContext->MaximumBuffers > Max_Buffers) {
  1403. LoggerContext->MaximumBuffers = Max_Buffers;
  1404. } else if (LoggerContext->MaximumBuffers < Max_Buffers) {
  1405. Max_Buffers = max(LoggerContext->MaximumBuffers,
  1406. NumberProcessors + DEFAULT_BUFFERS + 20);
  1407. }
  1408. LoggerContext->MinimumBuffers = max(LoggerContext->MinimumBuffers,
  1409. NumberProcessors + DEFAULT_BUFFERS);
  1410. LoggerContext->NumberOfBuffers = (LONG) LoggerContext->MinimumBuffers;
  1411. if (LoggerContext->NumberOfBuffers > (LONG) Max_Buffers) {
  1412. LoggerContext->NumberOfBuffers = (LONG) Max_Buffers;
  1413. LoggerContext->MinimumBuffers = Max_Buffers;
  1414. }
  1415. LoggerContext->MaximumBuffers = Max_Buffers;
  1416. LoggerContext->BuffersAvailable = LoggerContext->NumberOfBuffers;
  1417. #ifdef NTPERF
  1418. if (PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  1419. //
  1420. // Logging to Perfmem. The Maximum should be the perfmem size.
  1421. //
  1422. LoggerContext->MaximumBuffers = PerfQueryBufferSizeBytes()/LoggerContext->BufferSize;
  1423. }
  1424. #endif //NTPERF
  1425. //
  1426. // Allocate the buffers now
  1427. //
  1428. #ifdef WMI_NON_BLOCKING
  1429. //
  1430. // Now determine the initial number of buffers
  1431. //
  1432. NumberOfBuffers = LoggerContext->NumberOfBuffers;
  1433. LoggerContext->NumberOfBuffers = 0;
  1434. LoggerContext->BuffersAvailable = 0;
  1435. AllocatedBuffers = WmipAllocateFreeBuffers(LoggerContext,
  1436. NumberOfBuffers);
  1437. if (AllocatedBuffers < NumberOfBuffers) {
  1438. //
  1439. // No enough buffer is allocated.
  1440. //
  1441. WmipFreeTraceBufferPool(LoggerContext);
  1442. return STATUS_NO_MEMORY;
  1443. }
  1444. //
  1445. // Allocate Per Processor Buffer pointers
  1446. //
  1447. LoggerContext->ProcessorBuffers
  1448. = (SLIST_HEADER *)
  1449. WmipExtendBase(LoggerContext,
  1450. sizeof(SLIST_HEADER)*NumberProcessors);
  1451. #else
  1452. BufferSize = LoggerContext->BufferSize;
  1453. for (i=0; i<LoggerContext->NumberOfBuffers; i++) {
  1454. Buffer = (PWMI_BUFFER_HEADER)
  1455. ExAllocatePoolWithTag(LoggerContext->PoolType,
  1456. BufferSize, TRACEPOOLTAG);
  1457. if (Buffer == NULL) { // need to free previously allocated buffers
  1458. WmipFreeTraceBufferPool(LoggerContext);
  1459. return STATUS_NO_MEMORY;
  1460. }
  1461. //
  1462. // Initialize newly created buffer
  1463. //
  1464. RtlZeroMemory(Buffer, sizeof(WMI_BUFFER_HEADER));
  1465. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  1466. KeQuerySystemTime(&Buffer->TimeStamp);
  1467. InsertTailList(
  1468. &LoggerContext->FreeList,
  1469. &Buffer->Entry);
  1470. TraceDebug((2, "WmipAllocateTraceBuffer: %d Allocated %X Entry %X\n",
  1471. LoggerContext->LoggerId, Buffer, Buffer->Entry));
  1472. }
  1473. //
  1474. // Allocate Per Processor Buffer pointers
  1475. //
  1476. LoggerContext->ProcessorBuffers
  1477. = (PWMI_BUFFER_HEADER *)
  1478. WmipExtendBase(LoggerContext,
  1479. sizeof(PWMI_BUFFER_HEADER)*NumberProcessors);
  1480. #endif //WMI_NON_BLOCKING
  1481. if (LoggerContext->ProcessorBuffers == NULL) {
  1482. WmipFreeTraceBufferPool(LoggerContext);
  1483. return STATUS_NO_MEMORY;
  1484. }
  1485. //
  1486. // NOTE: We already know that we have allocated > number of processors
  1487. // buffers
  1488. //
  1489. for (i=0; i<(LONG)NumberProcessors; i++) {
  1490. #ifdef WMI_NON_BLOCKING
  1491. InitializeSListHead (&LoggerContext->ProcessorBuffers[i]);
  1492. Buffer = (PWMI_BUFFER_HEADER) WmipGetFreeBuffer(LoggerContext);
  1493. InterlockedPushEntrySList (&LoggerContext->ProcessorBuffers[i],
  1494. (PSINGLE_LIST_ENTRY) &Buffer->SlistEntry);
  1495. Buffer->ClientContext.ProcessorNumber = (UCHAR)i;
  1496. #else
  1497. Buffer = (PWMI_BUFFER_HEADER) WmipGetFreeBuffer(LoggerContext);
  1498. LoggerContext->ProcessorBuffers[i] = Buffer;
  1499. Buffer->ClientContext.ProcessorNumber = (UCHAR)i;
  1500. #endif //WMI_NON_BLOCKING
  1501. }
  1502. return STATUS_SUCCESS;
  1503. }
  1504. NTSTATUS
  1505. WmipFreeTraceBufferPool(
  1506. IN PWMI_LOGGER_CONTEXT LoggerContext
  1507. )
  1508. {
  1509. ULONG i;
  1510. #ifdef WMI_NON_BLOCKING
  1511. PSINGLE_LIST_ENTRY Entry;
  1512. SLIST_HEADER* ProcessorBuffers;
  1513. PWMI_BUFFER_HEADER Buffer;
  1514. #else
  1515. PWMI_BUFFER_HEADER* Buffers;
  1516. PLIST_ENTRY Entry;
  1517. #endif //WMI_NON_BLOCKING
  1518. PAGED_CODE();
  1519. #ifdef WMI_NON_BLOCKING
  1520. TraceDebug((2, "Free Buffer Pool: %2d, Free: %d, InUse: %d, Dirty: %d, Total: %d\n",
  1521. LoggerContext->LoggerId,
  1522. LoggerContext->BuffersAvailable,
  1523. LoggerContext->BuffersInUse,
  1524. LoggerContext->BuffersDirty,
  1525. LoggerContext->NumberOfBuffers));
  1526. while (Entry = InterlockedPopEntrySList(&LoggerContext->FreeList)) {
  1527. Buffer = CONTAINING_RECORD(Entry,
  1528. WMI_BUFFER_HEADER,
  1529. SlistEntry);
  1530. InterlockedDecrement(&LoggerContext->NumberOfBuffers);
  1531. InterlockedDecrement(&LoggerContext->BuffersAvailable);
  1532. TraceDebug((2, "WmipFreeTraceBufferPool (Free): %2d, %p, Free: %d, InUse: %d, Dirty: %d, Total: %d\n",
  1533. LoggerContext->LoggerId,
  1534. Buffer,
  1535. LoggerContext->BuffersAvailable,
  1536. LoggerContext->BuffersInUse,
  1537. LoggerContext->BuffersDirty,
  1538. LoggerContext->NumberOfBuffers));
  1539. #ifdef NTPERF
  1540. if (!PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  1541. #endif //NTPERF
  1542. ExFreePool(Buffer);
  1543. #ifdef NTPERF
  1544. }
  1545. #endif //NTPERF
  1546. }
  1547. while (Entry = InterlockedPopEntrySList(&LoggerContext->FlushList)) {
  1548. Buffer = CONTAINING_RECORD(Entry,
  1549. WMI_BUFFER_HEADER,
  1550. SlistEntry);
  1551. InterlockedDecrement(&LoggerContext->NumberOfBuffers);
  1552. InterlockedDecrement(&LoggerContext->BuffersDirty);
  1553. TraceDebug((2, "WmipFreeTraceBufferPool (Flush): %2d, %p, Free: %d, InUse: %d, Dirty: %d, Total: %d\n",
  1554. LoggerContext->LoggerId,
  1555. Buffer,
  1556. LoggerContext->BuffersAvailable,
  1557. LoggerContext->BuffersInUse,
  1558. LoggerContext->BuffersDirty,
  1559. LoggerContext->NumberOfBuffers));
  1560. #ifdef NTPERF
  1561. if (!PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  1562. #endif //NTPERF
  1563. ExFreePool(Buffer);
  1564. #ifdef NTPERF
  1565. }
  1566. #endif //NTPERF
  1567. }
  1568. ProcessorBuffers = LoggerContext->ProcessorBuffers;
  1569. if (ProcessorBuffers != NULL) {
  1570. for (i=0; i<(ULONG)KeNumberProcessors; i++) {
  1571. while (Entry = InterlockedPopEntrySList(&ProcessorBuffers[i])) {
  1572. Buffer = CONTAINING_RECORD(Entry,
  1573. WMI_BUFFER_HEADER,
  1574. SlistEntry);
  1575. InterlockedDecrement(&LoggerContext->NumberOfBuffers);
  1576. InterlockedDecrement(&LoggerContext->BuffersInUse);
  1577. TraceDebug((2, "WmipFreeTraceBufferPool (CPU %2d): %2d, %p, Free: %d, InUse: %d, Dirty: %d, Total: %d\n",
  1578. i,
  1579. LoggerContext->LoggerId,
  1580. Buffer,
  1581. LoggerContext->BuffersAvailable,
  1582. LoggerContext->BuffersInUse,
  1583. LoggerContext->BuffersDirty,
  1584. LoggerContext->NumberOfBuffers));
  1585. #ifdef NTPERF
  1586. if (!PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  1587. #endif //NTPERF
  1588. ExFreePool(Buffer);
  1589. #ifdef NTPERF
  1590. }
  1591. #endif //NTPERF
  1592. }
  1593. }
  1594. }
  1595. ASSERT(LoggerContext->BuffersAvailable == 0);
  1596. ASSERT(LoggerContext->BuffersInUse == 0);
  1597. ASSERT(LoggerContext->BuffersDirty == 0);
  1598. ASSERT(LoggerContext->NumberOfBuffers == 0);
  1599. #else
  1600. while (Entry = ExInterlockedRemoveHeadList(
  1601. &LoggerContext->FreeList,
  1602. &LoggerContext->BufferSpinLock)) {
  1603. PWMI_BUFFER_HEADER Buffer;
  1604. Buffer = CONTAINING_RECORD(Entry, WMI_BUFFER_HEADER, Entry);
  1605. TraceDebug((2, "WmipFreeTraceBufferPool: Freeing %d %X Entry %X\n",
  1606. LoggerContext->LoggerId, Buffer, Entry));
  1607. if (Buffer != NULL) {
  1608. ExFreePool(Buffer);
  1609. }
  1610. }
  1611. for (i=0; i<(ULONG)LoggerContext->NumberOfBuffers; i++) {
  1612. PLIST_ENTRY Entry;
  1613. if (IsListEmpty(&LoggerContext->FlushList))
  1614. break;
  1615. Entry = RemoveTailList( &LoggerContext->FlushList );
  1616. InsertTailList( &LoggerContext->FreeList, Entry );
  1617. TraceDebug((1,
  1618. "WmipFreeTraceBufferPool: Move entry %X from flush to free\n",
  1619. Entry));
  1620. }
  1621. Buffers = LoggerContext->ProcessorBuffers;
  1622. if (Buffers != NULL) {
  1623. for (i=0; i<(ULONG)KeNumberProcessors; i++) {
  1624. if (Buffers[i] != NULL) {
  1625. TraceDebug((1,
  1626. "WmipFreeTraceBufferPool: Freeing buffer %X for CPU%d\n",
  1627. Buffers[i], i));
  1628. ExFreePool(Buffers[i]);
  1629. Buffers[i] = NULL;
  1630. }
  1631. }
  1632. }
  1633. #endif //WMI_NON_BLOCKING
  1634. return STATUS_SUCCESS;
  1635. }
  1636. NTSTATUS
  1637. WmipLookupLoggerIdByName(
  1638. IN PUNICODE_STRING Name,
  1639. OUT PULONG LoggerId
  1640. )
  1641. {
  1642. ULONG i;
  1643. PWMI_LOGGER_CONTEXT *ContextTable;
  1644. PAGED_CODE();
  1645. if (Name == NULL) {
  1646. *LoggerId = (ULONG) -1;
  1647. return STATUS_WMI_INSTANCE_NOT_FOUND;
  1648. }
  1649. ContextTable = (PWMI_LOGGER_CONTEXT *) &WmipLoggerContext[0];
  1650. for (i=0; i<MAXLOGGERS; i++) {
  1651. if (ContextTable[i] == NULL ||
  1652. ContextTable[i] == (PWMI_LOGGER_CONTEXT) ContextTable)
  1653. continue;
  1654. if (RtlEqualUnicodeString(&ContextTable[i]->LoggerName, Name, TRUE) ) {
  1655. *LoggerId = i;
  1656. return STATUS_SUCCESS;
  1657. }
  1658. }
  1659. *LoggerId = (ULONG) -1;
  1660. return STATUS_WMI_INSTANCE_NOT_FOUND;
  1661. }
  1662. NTSTATUS
  1663. WmipShutdown(
  1664. IN PDEVICE_OBJECT DeviceObject,
  1665. IN PIRP Irp
  1666. )
  1667. //
  1668. // Shutdown all loggers cleanly. If a logger is in transition, it may
  1669. // not be stopped properly.
  1670. //
  1671. {
  1672. ULONG LoggerCount;
  1673. USHORT i;
  1674. PWMI_LOGGER_CONTEXT LoggerContext;
  1675. WMI_LOGGER_INFORMATION LoggerInfo;
  1676. UNREFERENCED_PARAMETER(DeviceObject);
  1677. UNREFERENCED_PARAMETER(Irp);
  1678. PAGED_CODE();
  1679. TraceDebug((2, "WmipShutdown called\n"));
  1680. if (WmipLoggerCount > 0) {
  1681. RtlZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
  1682. LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
  1683. LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  1684. LoggerCount = 0;
  1685. for (i=0; i<MAXLOGGERS; i++) {
  1686. LoggerContext = WmipLoggerContext[i];
  1687. if ((LoggerContext != NULL) &&
  1688. (LoggerContext != (PWMI_LOGGER_CONTEXT)&WmipLoggerContext[0])) {
  1689. WmiSetLoggerId(i, &LoggerInfo.Wnode.HistoricalContext);
  1690. LoggerInfo.Wnode.Guid = LoggerContext->InstanceGuid;
  1691. WmiStopTrace(&LoggerInfo);
  1692. if (++LoggerCount == WmipLoggerCount)
  1693. break;
  1694. }
  1695. #if DBG
  1696. else if (LoggerContext
  1697. == (PWMI_LOGGER_CONTEXT)&WmipLoggerContext[0]) {
  1698. TraceDebug((4, "WmipShutdown: Logger %d in transition\n", i));
  1699. }
  1700. #endif
  1701. }
  1702. }
  1703. Irp->IoStatus.Status = STATUS_SUCCESS;
  1704. Irp->IoStatus.Information = 0;
  1705. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1706. return STATUS_SUCCESS;
  1707. }
  1708. NTSTATUS
  1709. WmipFlushLogger(
  1710. IN OUT PWMI_LOGGER_CONTEXT LoggerContext,
  1711. IN ULONG Wait
  1712. )
  1713. {
  1714. LARGE_INTEGER TimeOut = {(ULONG)(-20 * 1000 * 1000 * 10), -1};
  1715. NTSTATUS Status;
  1716. PAGED_CODE();
  1717. //
  1718. // To Protect against an earlier caller timing out
  1719. // and resetting the event before it was set by the
  1720. // logger thread.
  1721. //
  1722. KeResetEvent(&LoggerContext->FlushEvent);
  1723. LoggerContext->RequestFlag |= REQUEST_FLAG_FLUSH_BUFFERS;
  1724. Status = WmipNotifyLogger(LoggerContext);
  1725. if (!NT_SUCCESS(Status))
  1726. return Status;
  1727. if (Wait) {
  1728. Status = KeWaitForSingleObject(
  1729. &LoggerContext->FlushEvent,
  1730. Executive,
  1731. KernelMode,
  1732. FALSE,
  1733. & TimeOut
  1734. );
  1735. #if DBG
  1736. if (Status == STATUS_TIMEOUT) {
  1737. TraceDebug((1, "WmiFlushLogger: Wait status=%X\n",Status));
  1738. }
  1739. #endif
  1740. KeResetEvent(&LoggerContext->FlushEvent);
  1741. Status = LoggerContext->LoggerStatus;
  1742. }
  1743. return Status;
  1744. }
  1745. NTSTATUS
  1746. FASTCALL
  1747. WmipNotifyLogger(
  1748. IN PWMI_LOGGER_CONTEXT LoggerContext
  1749. )
  1750. // Routine can be called at DISPATCH_LEVEL
  1751. {
  1752. LONG SemCount = KeReadStateSemaphore(&LoggerContext->LoggerSemaphore);
  1753. if (SemCount >= SEMAPHORE_LIMIT/2) {
  1754. return STATUS_UNSUCCESSFUL;
  1755. }
  1756. {
  1757. KeReleaseSemaphore(&LoggerContext->LoggerSemaphore, 0, 1, FALSE);
  1758. return STATUS_SUCCESS;
  1759. }
  1760. }
  1761. PVOID
  1762. WmipGetTraceBuffer(
  1763. IN PWMI_LOGGER_CONTEXT LoggerContext,
  1764. IN HANDLE LogFileHandle,
  1765. IN PWMI_BUFFER_HEADER Buffer,
  1766. IN ULONG GroupType,
  1767. IN ULONG RequiredSize,
  1768. OUT PULONG GuidMapBuffers
  1769. )
  1770. {
  1771. PSYSTEM_TRACE_HEADER Header;
  1772. NTSTATUS Status;
  1773. ULONG BytesUsed;
  1774. PETHREAD Thread;
  1775. PAGED_CODE();
  1776. RequiredSize += sizeof (SYSTEM_TRACE_HEADER); // add in header
  1777. RequiredSize = (ULONG) ALIGN_TO_POWER2(RequiredSize, WmiTraceAlignment);
  1778. if (RequiredSize > LoggerContext->BufferSize - sizeof(WMI_BUFFER_HEADER)) {
  1779. return NULL;
  1780. }
  1781. if (RequiredSize > (LoggerContext->BufferSize - Buffer->Offset)) {
  1782. IO_STATUS_BLOCK IoStatus;
  1783. if (Buffer->Offset < LoggerContext->BufferSize) {
  1784. RtlFillMemory(
  1785. (char *) Buffer + Buffer->Offset,
  1786. LoggerContext->BufferSize - Buffer->Offset,
  1787. 0xFF);
  1788. }
  1789. Status = ZwWriteFile(
  1790. LogFileHandle,
  1791. NULL,
  1792. NULL,
  1793. NULL,
  1794. &IoStatus,
  1795. Buffer,
  1796. LoggerContext->BufferSize,
  1797. &LoggerContext->ByteOffset,
  1798. NULL);
  1799. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  1800. LoggerContext->ByteOffset.QuadPart += LoggerContext->BufferSize;
  1801. if (!NT_SUCCESS(Status)) {
  1802. return NULL;
  1803. }
  1804. *GuidMapBuffers++;
  1805. }
  1806. Header = (PSYSTEM_TRACE_HEADER) ((char*)Buffer + Buffer->Offset);
  1807. Header->Header = (GroupType << 16) + RequiredSize;
  1808. Header->Marker = SYSTEM_TRACE_MARKER;
  1809. Thread = PsGetCurrentThread();
  1810. Header->SystemTime.QuadPart = (*LoggerContext->GetCpuClock)();
  1811. Header->ThreadId = HandleToUlong(Thread->Cid.UniqueThread);
  1812. Header->ProcessId = HandleToUlong(Thread->Cid.UniqueProcess);
  1813. Header->KernelTime = Thread->Tcb.KernelTime;
  1814. Header->UserTime = Thread->Tcb.UserTime;
  1815. Header->Packet.Size = (USHORT) RequiredSize;
  1816. Buffer->Offset += RequiredSize;
  1817. // If there is room, throw in a end of buffer marker.
  1818. BytesUsed = Buffer->Offset;
  1819. if ( BytesUsed <= (LoggerContext->BufferSize-sizeof(ULONG)) ) {
  1820. *((long*)((char*)Buffer+Buffer->Offset)) = -1;
  1821. }
  1822. return (PVOID) ( (char*) Header + sizeof(SYSTEM_TRACE_HEADER) );
  1823. }
  1824. ULONG
  1825. WmipDumpGuidMaps(
  1826. IN PWMI_LOGGER_CONTEXT LoggerContext,
  1827. IN PLIST_ENTRY TraceGMHeadPtr
  1828. )
  1829. {
  1830. PWMI_BUFFER_HEADER Buffer;
  1831. HANDLE LogFileHandle = NULL;
  1832. PWCHAR LogFileName = NULL;
  1833. NTSTATUS Status;
  1834. ULONG BufferSize;
  1835. ULONG GuidMapBuffers = 0;
  1836. PGUIDMAPENTRY GuidMap;
  1837. PLIST_ENTRY GuidMapList;
  1838. IO_STATUS_BLOCK IoStatus;
  1839. PAGED_CODE();
  1840. if ( (LoggerContext == NULL) || (TraceGMHeadPtr == NULL) )
  1841. return 0;
  1842. //
  1843. // If this a realtime logger only, then simply free the GuidMaps.
  1844. //
  1845. if ( (LoggerContext->LoggerMode & EVENT_TRACE_REAL_TIME_MODE) &&
  1846. ((LoggerContext->LogFileName.Buffer == NULL) ||
  1847. (LoggerContext->LogFileName.Length == 0)) ){
  1848. GuidMapList = TraceGMHeadPtr->Flink;
  1849. while (GuidMapList != TraceGMHeadPtr)
  1850. {
  1851. GuidMap = CONTAINING_RECORD(GuidMapList,
  1852. GUIDMAPENTRY,
  1853. Entry);
  1854. GuidMapList = GuidMapList->Flink;
  1855. RemoveEntryList(&GuidMap->Entry);
  1856. WmipFree(GuidMap);
  1857. }
  1858. return 0;
  1859. }
  1860. BufferSize = LoggerContext->BufferSize;
  1861. if ( BufferSize == 0)
  1862. return 0;
  1863. Buffer = ExAllocatePoolWithTag(PagedPool,
  1864. BufferSize, TRACEPOOLTAG);
  1865. if (Buffer == NULL) {
  1866. //
  1867. // No buffer available.
  1868. //
  1869. return 0;
  1870. }
  1871. RtlZeroMemory(Buffer, BufferSize);
  1872. Buffer->CurrentOffset = sizeof(WMI_BUFFER_HEADER);
  1873. Buffer->Offset = sizeof(WMI_BUFFER_HEADER);
  1874. Buffer->Wnode.BufferSize = BufferSize;
  1875. Buffer->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  1876. Buffer->ClientContext.Alignment = (UCHAR)WmiTraceAlignment;
  1877. Buffer->Wnode.Guid = LoggerContext->InstanceGuid;
  1878. KeQuerySystemTime(&Buffer->TimeStamp);
  1879. Status = WmipCreateNtFileName( LoggerContext->LogFileName.Buffer,
  1880. &LogFileName);
  1881. if (!NT_SUCCESS(Status)) {
  1882. ExFreePool(Buffer);
  1883. return 0;
  1884. }
  1885. Status = WmipCreateDirectoryFile (
  1886. LogFileName,
  1887. FALSE,
  1888. &LogFileHandle,
  1889. TRUE );
  1890. if (NT_SUCCESS(Status)) {
  1891. PULONG AuxInfo;
  1892. if ((LoggerContext->LoggerMode & EVENT_TRACE_FILE_MODE_PREALLOCATE) &&
  1893. (LoggerContext->MaximumFileSize > (((LONGLONG) LoggerContext->BuffersWritten * (LONGLONG) LoggerContext->BufferSize) / (1024 * 1024)))) {
  1894. LoggerContext->ByteOffset.QuadPart = ((LONGLONG) LoggerContext->BufferSize) *
  1895. ((LONGLONG) LoggerContext->BuffersWritten);
  1896. }
  1897. else {
  1898. FILE_STANDARD_INFORMATION FileSize;
  1899. Status = ZwQueryInformationFile(
  1900. LogFileHandle,
  1901. &IoStatus,
  1902. &FileSize,
  1903. sizeof (FILE_STANDARD_INFORMATION),
  1904. FileStandardInformation
  1905. );
  1906. if (!NT_SUCCESS(Status)) {
  1907. ZwClose(LogFileHandle);
  1908. ExFreePool(LogFileName);
  1909. ExFreePool(Buffer);
  1910. return 0;
  1911. }
  1912. LoggerContext->ByteOffset = FileSize.EndOfFile;
  1913. }
  1914. //
  1915. // Do the RunDown of GuidMaps
  1916. //
  1917. GuidMapList = TraceGMHeadPtr->Flink;
  1918. while (GuidMapList != TraceGMHeadPtr)
  1919. {
  1920. GuidMap = CONTAINING_RECORD(GuidMapList,
  1921. GUIDMAPENTRY,
  1922. Entry);
  1923. GuidMapList = GuidMapList->Flink;
  1924. RemoveEntryList(&GuidMap->Entry);
  1925. AuxInfo = (PULONG) WmipGetTraceBuffer(LoggerContext,
  1926. LogFileHandle,
  1927. Buffer,
  1928. EVENT_TRACE_GROUP_HEADER + EVENT_TRACE_TYPE_GUIDMAP,
  1929. sizeof(TRACEGUIDMAP),
  1930. &GuidMapBuffers
  1931. );
  1932. if (AuxInfo != NULL) {
  1933. RtlCopyMemory(AuxInfo, &GuidMap->GuidMap, sizeof(TRACEGUIDMAP) );
  1934. }
  1935. WmipFree(GuidMap);
  1936. }
  1937. //
  1938. // Flush the last buffer if needed
  1939. //
  1940. if (Buffer->Offset > sizeof(WMI_BUFFER_HEADER) ) {
  1941. Status = ZwWriteFile(
  1942. LogFileHandle,
  1943. NULL,
  1944. NULL,
  1945. NULL,
  1946. &IoStatus,
  1947. Buffer,
  1948. LoggerContext->BufferSize,
  1949. &LoggerContext->ByteOffset,
  1950. NULL);
  1951. LoggerContext->ByteOffset.QuadPart += LoggerContext->BufferSize;
  1952. GuidMapBuffers++;
  1953. }
  1954. ZwClose(LogFileHandle);
  1955. }
  1956. ExFreePool(LogFileName);
  1957. ExFreePool(Buffer);
  1958. return GuidMapBuffers;
  1959. }
  1960. NTSTATUS
  1961. WmipNtDllLoggerInfo(
  1962. IN OUT PWMINTDLLLOGGERINFO Buffer
  1963. )
  1964. {
  1965. NTSTATUS Status = STATUS_SUCCESS;
  1966. KPROCESSOR_MODE RequestorMode;
  1967. PBGUIDENTRY GuidEntry;
  1968. ULONG SizeNeeded;
  1969. GUID Guid;
  1970. PAGED_CODE();
  1971. RequestorMode = KeGetPreviousMode();
  1972. SizeNeeded = sizeof(WMI_LOGGER_INFORMATION);
  1973. __try {
  1974. if (RequestorMode != KernelMode){
  1975. ProbeForRead(Buffer->LoggerInfo, SizeNeeded, sizeof(ULONGLONG));
  1976. }
  1977. RtlCopyMemory(&Guid, &Buffer->LoggerInfo->Wnode.Guid, sizeof(GUID));
  1978. if(!IsEqualGUID(&Guid, &NtdllTraceGuid)){
  1979. return STATUS_UNSUCCESSFUL;
  1980. }
  1981. SizeNeeded = Buffer->LoggerInfo->Wnode.BufferSize;
  1982. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1983. return GetExceptionCode();
  1984. }
  1985. WmipEnterTLCritSection();
  1986. WmipEnterSMCritSection();
  1987. GuidEntry = WmipFindGEByGuid(&Guid, FALSE);
  1988. if(Buffer->IsGet){
  1989. if( GuidEntry ){
  1990. if(GuidEntry->LoggerInfo){
  1991. SizeNeeded = GuidEntry->LoggerInfo->Wnode.BufferSize;
  1992. __try {
  1993. if (RequestorMode != KernelMode){
  1994. ProbeForWrite(Buffer->LoggerInfo, SizeNeeded, sizeof(ULONGLONG));
  1995. }
  1996. RtlCopyMemory(Buffer->LoggerInfo,GuidEntry->LoggerInfo,SizeNeeded);
  1997. } __except(EXCEPTION_EXECUTE_HANDLER) {
  1998. WmipUnreferenceGE(GuidEntry);
  1999. WmipLeaveSMCritSection();
  2000. WmipLeaveTLCritSection();
  2001. return GetExceptionCode();
  2002. }
  2003. }
  2004. WmipUnreferenceGE(GuidEntry);
  2005. } else {
  2006. Status = STATUS_UNSUCCESSFUL;
  2007. }
  2008. } else {
  2009. if(SizeNeeded){
  2010. if(GuidEntry == NULL){
  2011. GuidEntry = WmipAllocGuidEntry();
  2012. if (GuidEntry){
  2013. //
  2014. // Initialize the guid entry and keep the ref count
  2015. // from creation. When tracelog enables we take a ref
  2016. // count and when it disables we release it
  2017. //
  2018. GuidEntry->Guid = Guid;
  2019. GuidEntry->EventRefCount = 1;
  2020. GuidEntry->Flags |= GE_NOTIFICATION_TRACE_FLAG;
  2021. InsertHeadList(WmipGEHeadPtr, &GuidEntry->MainGEList);
  2022. //
  2023. // Take Extra Refcount so that we release it at stoplogger call
  2024. //
  2025. WmipReferenceGE(GuidEntry);
  2026. } else {
  2027. Status = STATUS_INSUFFICIENT_RESOURCES;
  2028. }
  2029. }
  2030. if(NT_SUCCESS(Status)){
  2031. if(GuidEntry->LoggerInfo) {
  2032. Status = STATUS_UNSUCCESSFUL;
  2033. } else {
  2034. GuidEntry->LoggerInfo = NULL;
  2035. GuidEntry->LoggerInfo = WmipAlloc(SizeNeeded);
  2036. if(GuidEntry->LoggerInfo){
  2037. WMITRACEENABLEDISABLEINFO TraceEnableInfo;
  2038. __try {
  2039. RtlCopyMemory(GuidEntry->LoggerInfo,Buffer->LoggerInfo,SizeNeeded);
  2040. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2041. WmipUnreferenceGE(GuidEntry);
  2042. WmipLeaveSMCritSection();
  2043. WmipLeaveTLCritSection();
  2044. return GetExceptionCode();
  2045. }
  2046. TraceEnableInfo.Guid = GuidEntry->Guid;
  2047. TraceEnableInfo.Enable = TRUE;
  2048. Status = WmipEnableDisableTrace(IOCTL_WMI_ENABLE_DISABLE_TRACELOG, &TraceEnableInfo);
  2049. } else {
  2050. Status = STATUS_INSUFFICIENT_RESOURCES;
  2051. }
  2052. }
  2053. WmipUnreferenceGE(GuidEntry);
  2054. }
  2055. } else {
  2056. //
  2057. // This is stop logger call.
  2058. //
  2059. if(GuidEntry){
  2060. WMITRACEENABLEDISABLEINFO TraceEnableInfo;
  2061. if(GuidEntry->LoggerInfo) {
  2062. __try{
  2063. if (RequestorMode != KernelMode){
  2064. ProbeForWrite(Buffer->LoggerInfo, sizeof(WMI_LOGGER_INFORMATION), sizeof(ULONGLONG));
  2065. }
  2066. Buffer->LoggerInfo->BufferSize = GuidEntry->LoggerInfo->BufferSize;
  2067. Buffer->LoggerInfo->MinimumBuffers = GuidEntry->LoggerInfo->MinimumBuffers;
  2068. Buffer->LoggerInfo->MaximumBuffers = GuidEntry->LoggerInfo->MaximumBuffers;
  2069. WmipFree(GuidEntry->LoggerInfo);
  2070. GuidEntry->LoggerInfo = NULL;
  2071. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2072. WmipUnreferenceGE(GuidEntry);
  2073. WmipLeaveSMCritSection();
  2074. WmipLeaveTLCritSection();
  2075. return GetExceptionCode();
  2076. }
  2077. }
  2078. TraceEnableInfo.Guid = GuidEntry->Guid;
  2079. TraceEnableInfo.Enable = FALSE;
  2080. //
  2081. // The Extra Refcount taken at logger start is released by calling
  2082. // Disable trace.
  2083. //
  2084. Status = WmipEnableDisableTrace(IOCTL_WMI_ENABLE_DISABLE_TRACELOG, &TraceEnableInfo);
  2085. WmipUnreferenceGE(GuidEntry);
  2086. }
  2087. }
  2088. }
  2089. WmipLeaveSMCritSection();
  2090. WmipLeaveTLCritSection();
  2091. return Status;
  2092. }
  2093. VOID
  2094. WmipValidateClockType(
  2095. IN OUT PWMI_LOGGER_INFORMATION LoggerInfo
  2096. )
  2097. /*++
  2098. Routine Description:
  2099. This routine is called to validate the requested clock type in the
  2100. LoggerInfo. If the requested type can not be handled, we will override
  2101. to a type that this system will support.
  2102. This routine assumes that LoggerInfo pointer is a valid one.
  2103. Arguments:
  2104. LoggerInfo - a pointer to the structure for the logger's control
  2105. and status information
  2106. Returned Value:
  2107. Status of STATUS_SUCCESS
  2108. --*/
  2109. {
  2110. #ifdef NTPERF
  2111. //
  2112. // For private kernel, use EVENT_TRACE_CLOCK_CPUCYCLE no matter
  2113. // what the user sets
  2114. // This mechanism need to considered again
  2115. //
  2116. LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_CPUCYCLE;
  2117. #else
  2118. //
  2119. // For retail kernel, if not EVENT_TRACE_CLOCK_SYSTEMTIME,
  2120. // force it to be EVENT_TRACE_CLOCK_PERFCOUNTER.
  2121. //
  2122. if (LoggerInfo->Wnode.ClientContext != EVENT_TRACE_CLOCK_SYSTEMTIME) {
  2123. LoggerInfo->Wnode.ClientContext = EVENT_TRACE_CLOCK_PERFCOUNTER;
  2124. }
  2125. #endif //NTPERF
  2126. }