Leaked source code of windows server 2003
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.

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