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.

2781 lines
90 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. Mca.c
  5. Abstract:
  6. Machine Check Architecture interface
  7. Author:
  8. AlanWar
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #if defined(_IA64_)
  14. #include "wmikmp.h"
  15. #include <mce.h>
  16. #include "hal.h"
  17. #include "ntiologc.h"
  18. #define SAL_30_ERROR_REVISION 0x0002
  19. #define MCA_EVENT_INSTANCE_NAME L"McaEvent"
  20. #define MCA_UNDEFINED_CPU 0xffffffff
  21. #define HalpGetFwMceLogProcessorNumber( /* PERROR_RECORD_HEADER */ _Log ) \
  22. ((UCHAR) (_Log)->TimeStamp.Reserved )
  23. BOOLEAN WmipMceDelivery(
  24. IN PVOID Reserved,
  25. IN PVOID Argument2
  26. );
  27. BOOLEAN WmipCmcDelivery(
  28. IN PVOID Reserved,
  29. IN PVOID Argument2
  30. );
  31. BOOLEAN WmipMcaDelivery(
  32. IN PVOID Reserved,
  33. IN PVOID Argument2
  34. );
  35. BOOLEAN WmipCpeDelivery(
  36. IN PVOID Reserved,
  37. IN PVOID Argument2
  38. );
  39. void WmipMceWorkerRoutine(
  40. IN PVOID Context // Not Used
  41. );
  42. NTSTATUS WmipGetLogFromHal(
  43. HAL_QUERY_INFORMATION_CLASS InfoClass,
  44. PVOID Token,
  45. PWNODE_SINGLE_INSTANCE *Wnode,
  46. PERROR_LOGRECORD *Mca,
  47. PULONG McaSize,
  48. ULONG MaxSize,
  49. LPGUID Guid
  50. );
  51. NTSTATUS WmipRegisterMcaHandler(
  52. ULONG Phase
  53. );
  54. NTSTATUS WmipBuildMcaCmcEvent(
  55. OUT PWNODE_SINGLE_INSTANCE Wnode,
  56. IN LPGUID EventGuid,
  57. IN PERROR_LOGRECORD McaCmcEvent,
  58. IN ULONG McaCmcSize
  59. );
  60. NTSTATUS WmipGetRawMCAInfo(
  61. OUT PUCHAR Buffer,
  62. IN OUT PULONG BufferSize
  63. );
  64. NTSTATUS WmipSetCPEPolling(
  65. IN BOOLEAN Enabled,
  66. IN ULONG Interval
  67. );
  68. NTSTATUS WmipWriteMCAEventLogEvent(
  69. PUCHAR Event
  70. );
  71. NTSTATUS WmipSetupWaitForWbem(
  72. void
  73. );
  74. void WmipIsWbemRunningDispatch(
  75. IN PKDPC Dpc,
  76. IN PVOID DeferredContext, // Not Used
  77. IN PVOID SystemArgument1, // Not Used
  78. IN PVOID SystemArgument2 // Not Used
  79. );
  80. void WmipIsWbemRunningWorker(
  81. PVOID Context
  82. );
  83. BOOLEAN WmipCheckIsWbemRunning(
  84. void
  85. );
  86. void WmipProcessPrevMcaLogs(
  87. void
  88. );
  89. #ifdef MCE_INSERTION
  90. NTSTATUS WmipQuerySystemInformation(
  91. IN HAL_QUERY_INFORMATION_CLASS InformationClass,
  92. IN ULONG BufferSize,
  93. IN OUT PVOID Buffer,
  94. OUT PULONG ReturnedLength
  95. );
  96. #endif
  97. #ifdef ALLOC_PRAGMA
  98. #pragma alloc_text(PAGE,WmipSetCPEPolling)
  99. #pragma alloc_text(PAGE,WmipRegisterMcaHandler)
  100. #pragma alloc_text(PAGE,WmipMceWorkerRoutine)
  101. #pragma alloc_text(PAGE,WmipGetLogFromHal)
  102. #pragma alloc_text(PAGE,WmipBuildMcaCmcEvent)
  103. #pragma alloc_text(PAGE,WmipGetRawMCAInfo)
  104. #pragma alloc_text(PAGE,WmipWriteMCAEventLogEvent)
  105. #pragma alloc_text(PAGE,WmipGenerateMCAEventlog)
  106. #pragma alloc_text(PAGE,WmipIsWbemRunningWorker)
  107. #pragma alloc_text(PAGE,WmipCheckIsWbemRunning)
  108. #pragma alloc_text(PAGE,WmipSetupWaitForWbem)
  109. #pragma alloc_text(PAGE,WmipProcessPrevMcaLogs)
  110. #endif
  111. //
  112. // Set to TRUE when the registry indicates that popups should be
  113. // disabled. HKLM\System\CurrentControlSet\Control\WMI\DisableMCAPopups
  114. //
  115. ULONG WmipDisableMCAPopups;
  116. //
  117. // Guids for the various RAW MCA/CMC/CPE events
  118. //
  119. GUID WmipMSMCAEvent_CPUErrorGuid = MSMCAEvent_CPUErrorGuid;
  120. GUID WmipMSMCAEvent_MemoryErrorGuid = MSMCAEvent_MemoryErrorGuid;
  121. GUID WmipMSMCAEvent_PCIBusErrorGuid = MSMCAEvent_PCIBusErrorGuid;
  122. GUID WmipMSMCAEvent_PCIComponentErrorGuid = MSMCAEvent_PCIComponentErrorGuid;
  123. GUID WmipMSMCAEvent_SystemEventErrorGuid = MSMCAEvent_SystemEventErrorGuid;
  124. GUID WmipMSMCAEvent_SMBIOSErrorGuid = MSMCAEvent_SMBIOSErrorGuid;
  125. GUID WmipMSMCAEvent_PlatformSpecificErrorGuid = MSMCAEvent_PlatformSpecificErrorGuid;
  126. GUID WmipMSMCAEvent_InvalidErrorGuid = MSMCAEvent_InvalidErrorGuid;
  127. //
  128. // GUIDs for the different error sections within a MCA
  129. //
  130. GUID WmipErrorProcessorGuid = ERROR_PROCESSOR_GUID;
  131. GUID WmipErrorMemoryGuid = ERROR_MEMORY_GUID;
  132. GUID WmipErrorPCIBusGuid = ERROR_PCI_BUS_GUID;
  133. GUID WmipErrorPCIComponentGuid = ERROR_PCI_COMPONENT_GUID;
  134. GUID WmipErrorSELGuid = ERROR_SYSTEM_EVENT_LOG_GUID;
  135. GUID WmipErrorSMBIOSGuid = ERROR_SMBIOS_GUID;
  136. GUID WmipErrorSpecificGuid = ERROR_PLATFORM_SPECIFIC_GUID;
  137. //
  138. // Each type of MCE has a control structure that is used to determine
  139. // whether to poll or wait for an interrupt to determine when to query
  140. // for the logs. This is needed since we can get a callback from the
  141. // HAL at high IRQL to inform us that a MCE log is available.
  142. // Additionally the IoTimer used for polling will call us at DPC level.
  143. // So in the case of an interrupt we will queue a DPC. Within the DPC
  144. // routine we will queue a work item so that we can get back to
  145. // passive level and be able to call the hal to get the logs (Can only
  146. // call hal at passive). The DPC and work item routines are common so a
  147. // MCEQUERYINFO struct is passed around so that it can operate on the
  148. // correct log type. Note that this implies that there may be multiple
  149. // work items querying the hal for different log types at the same
  150. // time. In addition this struct also contains useful log related
  151. // information including the maximum log size (as reported by the HAL),
  152. // the token that must be passed to the HAL when querying for the
  153. // logs and the HAL InfoClass to use when querying for the logs.
  154. //
  155. // PollCounter keeps track of the number of seconds before initiating a
  156. // query. If it is 0 (HAL_CPE_DISABLED / HAL_CMC_DISABLED) then no
  157. // polling occurs and if it is -1 (HAL_CPE_INTERRUPTS_BASED /
  158. // HAL_CMC_INTERRUPTS_BASED) then no polling occurs either. There is
  159. // only one work item active for each log type and this is enforced via
  160. // ItemsOutstanding in that only whenever it transitions from 0 to 1 is
  161. // the work item queued.
  162. //
  163. #define DEFAULT_MAX_MCA_SIZE 0x1000
  164. #define DEFAULT_MAX_CMC_SIZE 0x1000
  165. #define DEFAULT_MAX_CPE_SIZE 0x1000
  166. typedef struct
  167. {
  168. ULONG PollCounter; // Countdown in seconds
  169. HAL_QUERY_INFORMATION_CLASS InfoClass; // HAL Info class to use in MCE query
  170. PVOID Token; // HAL Token to use in MCE Queries
  171. ULONG ItemsOutstanding; // Number of interrupts or poll requests to process
  172. ULONG PollFrequency; // Frequency (in sec) to poll for CMC
  173. ULONG MaxSize; // Max size for log (as reported by HAL)
  174. GUID WnodeGuid; // GUID to use for the raw data event
  175. KDPC Dpc; // DPC to handle delivery
  176. WORK_QUEUE_ITEM WorkItem; // Work item used to query for log
  177. #ifdef MCE_INSERTION
  178. LIST_ENTRY LogHead;
  179. #endif
  180. } MCEQUERYINFO, *PMCEQUERYINFO;
  181. MCEQUERYINFO WmipMcaQueryInfo =
  182. {
  183. HAL_MCA_DISABLED,
  184. HalMcaLogInformation,
  185. 0,
  186. 0,
  187. HAL_MCA_DISABLED,
  188. DEFAULT_MAX_MCA_SIZE,
  189. MSMCAInfo_RawMCAEventGuid
  190. };
  191. MCEQUERYINFO WmipCmcQueryInfo =
  192. {
  193. HAL_CMC_DISABLED,
  194. HalCmcLogInformation,
  195. 0,
  196. 0,
  197. HAL_CMC_DISABLED,
  198. DEFAULT_MAX_CMC_SIZE,
  199. MSMCAInfo_RawCMCEventGuid
  200. };
  201. MCEQUERYINFO WmipCpeQueryInfo =
  202. {
  203. HAL_CPE_DISABLED,
  204. HalCpeLogInformation,
  205. 0,
  206. 0,
  207. HAL_CPE_DISABLED,
  208. DEFAULT_MAX_CPE_SIZE,
  209. MSMCAInfo_RawCorrectedPlatformEventGuid
  210. };
  211. //
  212. // First replace the PollFrequency and then the PollCounter. Do this
  213. // since the PollCounter gets reloaded from PollFrequency. We don't
  214. // want the situation where the PollCounter gets changed here and on
  215. // another thread the PollCounter gets reloaded with the old
  216. // PollFrequency before the PollFrequency gets updated here. This
  217. // could result in a situation where a poll could occur while this code
  218. // is in progress. This should be ok since disabling polling is not
  219. // synchronous, however if we need to do this then we need to reset the
  220. // PollCounter first, then the PollFrequency and then the PollCounter
  221. // again.
  222. //
  223. #define WmipSetQueryPollOrInt( /* PMCEQUERYINFO */ QueryInfo, \
  224. /* ULONG */ PollValue) \
  225. InterlockedExchange(&((QueryInfo)->PollFrequency), PollValue); \
  226. InterlockedExchange(&((QueryInfo)->PollCounter), PollValue);
  227. //
  228. // Used for waiting until WBEM is ready to receive events
  229. //
  230. KTIMER WmipIsWbemRunningTimer;
  231. KDPC WmipIsWbemRunningDpc;
  232. WORK_QUEUE_ITEM WmipIsWbemRunningWorkItem;
  233. LIST_ENTRY WmipWaitingMCAEvents = {&WmipWaitingMCAEvents, &WmipWaitingMCAEvents};
  234. #define WBEM_STATUS_UNKNOWN 0 // Polling process for waiting is not started
  235. #define WBEM_IS_RUNNING 1 // WBEM is currently running
  236. #define WAITING_FOR_WBEM 2 // Polling process for waiting is started
  237. UCHAR WmipIsWbemRunningFlag;
  238. #ifdef ALLOC_DATA_PRAGMA
  239. #pragma data_seg("PAGEDATA")
  240. #endif
  241. //
  242. // MCA information obtained at boot and holds the MCA that caused the
  243. // system to bugcheck on the previous boot
  244. //
  245. ULONG WmipRawMCASize;
  246. PMCA_EXCEPTION WmipRawMCA;
  247. //
  248. // Status of the MCE registration process
  249. //
  250. #define MCE_STATE_UNINIT 0
  251. #define MCE_STATE_REGISTERED 1
  252. #define MCE_STATE_RUNNING 2
  253. #define MCE_STATE_ERROR -1
  254. ULONG WmipMCEState;
  255. NTSTATUS WmipBuildMcaCmcEvent(
  256. OUT PWNODE_SINGLE_INSTANCE Wnode,
  257. IN LPGUID EventGuid,
  258. IN PERROR_LOGRECORD McaCmcEvent,
  259. IN ULONG McaCmcSize
  260. )
  261. /*++
  262. Routine Description:
  263. This routine will take a MCA or CMC log and build a
  264. WNODE_EVENT_ITEM for it.
  265. This routine may be called at DPC
  266. Arguments:
  267. Wnode is the wnode buffer in which to build the event
  268. EventGuid is the guid to use in the event wnode
  269. McaCmcEvent is the MCA, CMC or CPE data payload to put into the
  270. event
  271. McaCmcSize is the size of the event data
  272. Return Value:
  273. NT status code
  274. --*/
  275. {
  276. PULONG Ptr;
  277. PAGED_CODE();
  278. RtlZeroMemory(Wnode, sizeof(WNODE_SINGLE_INSTANCE));
  279. Wnode->WnodeHeader.BufferSize = McaCmcSize + sizeof(WNODE_SINGLE_INSTANCE);
  280. Wnode->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId(WmipServiceDeviceObject);
  281. KeQuerySystemTime(&Wnode->WnodeHeader.TimeStamp);
  282. Wnode->WnodeHeader.Guid = *EventGuid;
  283. Wnode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  284. WNODE_FLAG_EVENT_ITEM |
  285. WNODE_FLAG_STATIC_INSTANCE_NAMES;
  286. Wnode->DataBlockOffset = FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
  287. VariableData);
  288. Wnode->SizeDataBlock = McaCmcSize;
  289. Ptr = (PULONG)&Wnode->VariableData;
  290. *Ptr++ = 1; // 1 Record in this event
  291. *Ptr++ = McaCmcSize; // Size of log record in bytes
  292. if (McaCmcEvent != NULL)
  293. {
  294. RtlCopyMemory(Ptr, McaCmcEvent, McaCmcSize);
  295. }
  296. return(STATUS_SUCCESS);
  297. }
  298. NTSTATUS WmipQueryLogAndFireEvent(
  299. PMCEQUERYINFO QueryInfo
  300. )
  301. /*++
  302. Routine Description:
  303. Utility routine that will query the hal for a log and then if one
  304. is returned successfully then will fire the appropriate WMI events
  305. Arguments:
  306. QueryInfo is a pointer to the MCEQUERYINFO for the type of log that
  307. needs to be queried.
  308. Return Value:
  309. --*/
  310. {
  311. PWNODE_SINGLE_INSTANCE Wnode;
  312. NTSTATUS Status, Status2;
  313. ULONG Size;
  314. PERROR_LOGRECORD Log;
  315. PAGED_CODE();
  316. //
  317. // Call HAL to get the log
  318. //
  319. Status = WmipGetLogFromHal(QueryInfo->InfoClass,
  320. QueryInfo->Token,
  321. &Wnode,
  322. &Log,
  323. &Size,
  324. QueryInfo->MaxSize,
  325. &QueryInfo->WnodeGuid);
  326. if (NT_SUCCESS(Status))
  327. {
  328. //
  329. // Look at the event and fire it off as WMI events that
  330. // will generate eventlog events
  331. //
  332. WmipGenerateMCAEventlog((PUCHAR)Log,
  333. Size,
  334. FALSE);
  335. //
  336. // Fire the log off as a WMI event
  337. //
  338. Status2 = IoWMIWriteEvent(Wnode);
  339. if (! NT_SUCCESS(Status2))
  340. {
  341. //
  342. // IoWMIWriteEvent will free the wnode back to pool,
  343. // but not if it fails
  344. //
  345. ExFreePool(Wnode);
  346. }
  347. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  348. DPFLTR_MCA_LEVEL,
  349. "WMI: MCE Event fired to WMI -> %x\n",
  350. Status));
  351. } else {
  352. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  353. DPFLTR_MCA_LEVEL,
  354. "WMI: MCE Event for %p not available %x\n",
  355. QueryInfo, Status));
  356. }
  357. return(Status);
  358. }
  359. void WmipMceWorkerRoutine(
  360. IN PVOID Context // MCEQUERYINFO
  361. )
  362. /*++
  363. Routine Description:
  364. Worker routine that handles polling for corrected MCA, CMC and CPE
  365. logs from the HAL and then firing them as WMI events.
  366. Arguments:
  367. Context is a pointer to the MCEQUERYINFO for the type of log that
  368. needs to be queried.
  369. Return Value:
  370. --*/
  371. {
  372. PMCEQUERYINFO QueryInfo = (PMCEQUERYINFO)Context;
  373. NTSTATUS Status;
  374. ULONG x;
  375. PAGED_CODE();
  376. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  377. "WMI: WmipMceWorkerRoutine %p enter\n",
  378. QueryInfo));
  379. WmipAssert(QueryInfo->ItemsOutstanding > 0);
  380. //
  381. // Check to see if access has already been disabled
  382. //
  383. if (QueryInfo->PollCounter != HAL_CPE_DISABLED)
  384. {
  385. if (QueryInfo->PollCounter == HAL_CPE_INTERRUPTS_BASED)
  386. {
  387. //
  388. // We need to loop until all logs from all interrupts are read
  389. // and processed.
  390. //
  391. do
  392. {
  393. Status = WmipQueryLogAndFireEvent(QueryInfo);
  394. x = InterlockedDecrement(&QueryInfo->ItemsOutstanding);
  395. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  396. "WMI: %p transitions back to %d\n",
  397. QueryInfo, x));
  398. } while (x != 0);
  399. } else {
  400. //
  401. // We accomplish polling by calling into the hal and querying
  402. // for the logs until the hal returns an error
  403. //
  404. do
  405. {
  406. Status = WmipQueryLogAndFireEvent(QueryInfo);
  407. } while (NT_SUCCESS(Status));
  408. //
  409. // Reset flag to indicate that a new worker routine should be
  410. // created at the next polling interval. Note we ignore the result
  411. // since if a polling interval elasped while we were processing we
  412. // just ignore it as there is no point in polling again right now.
  413. //
  414. InterlockedExchange(&QueryInfo->ItemsOutstanding,
  415. 0);
  416. }
  417. }
  418. }
  419. void WmipMceDispatchRoutine(
  420. PMCEQUERYINFO QueryInfo
  421. )
  422. {
  423. ULONG x;
  424. //
  425. // Increment the number of items that are outstanding for this info
  426. // class. If the number of items outstanding transitions from 0 to
  427. // 1 then this implies that a work item for this info class needs
  428. // to be queued
  429. //
  430. x = InterlockedIncrement(&QueryInfo->ItemsOutstanding);
  431. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  432. "WMI: WmipMceDispatchRoutine %p transition to %d\n",
  433. QueryInfo,
  434. x));
  435. if (x == 1)
  436. {
  437. ExQueueWorkItem(&QueryInfo->WorkItem,
  438. DelayedWorkQueue);
  439. }
  440. }
  441. void WmipMceDpcRoutine(
  442. IN PKDPC Dpc,
  443. IN PVOID DeferredContext, // Not Used
  444. IN PVOID SystemArgument1, // MCEQUERYINFO
  445. IN PVOID SystemArgument2 // Not Used
  446. )
  447. {
  448. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  449. "WMI: WmipMceDpcRoutine %p Enter\n",
  450. SystemArgument1));
  451. WmipMceDispatchRoutine((PMCEQUERYINFO)SystemArgument1);
  452. }
  453. VOID
  454. WmipMceTimerRoutine(
  455. IN PDEVICE_OBJECT DeviceObject,
  456. IN PVOID Context
  457. )
  458. /*++
  459. Routine Description:
  460. This routine is the once a second timer that is used to poll for
  461. CPE. It is called at DPC.
  462. Arguments:
  463. DeviceObject is the device object for the WMI service device object
  464. Context is not used
  465. Return Value:
  466. --*/
  467. {
  468. //
  469. // We get called every second so count down until we need to do our
  470. // polling for CPE and CMC
  471. //
  472. if ((WmipCpeQueryInfo.PollCounter != HAL_CPE_DISABLED) &&
  473. (WmipCpeQueryInfo.PollCounter != HAL_CPE_INTERRUPTS_BASED) &&
  474. (InterlockedDecrement(&WmipCpeQueryInfo.PollCounter) == 0))
  475. {
  476. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  477. "WMI: CpeTimer expired\n"));
  478. WmipMceDispatchRoutine(&WmipCpeQueryInfo);
  479. WmipCpeQueryInfo.PollCounter = WmipCpeQueryInfo.PollFrequency;
  480. }
  481. if ((WmipCmcQueryInfo.PollCounter != HAL_CMC_DISABLED) &&
  482. (WmipCmcQueryInfo.PollCounter != HAL_CMC_INTERRUPTS_BASED) &&
  483. (InterlockedDecrement(&WmipCmcQueryInfo.PollCounter) == 0))
  484. {
  485. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  486. "WMI: CmcTimer expired\n"));
  487. WmipMceDispatchRoutine(&WmipCmcQueryInfo);
  488. WmipCmcQueryInfo.PollCounter = WmipCmcQueryInfo.PollFrequency;
  489. }
  490. }
  491. BOOLEAN WmipCommonMceDelivery(
  492. IN PMCEQUERYINFO QueryInfo,
  493. IN PVOID Token
  494. )
  495. /*++
  496. Routine Description:
  497. This routine is called at high IRQL and handles interrupt based
  498. access to the MCE logs
  499. Arguments:
  500. QueryInfo is the structure that has info about the type of log
  501. Token is the HAL token for the log type
  502. Return Value:
  503. TRUE to indicate that we handled the delivery
  504. --*/
  505. {
  506. BOOLEAN ret;
  507. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  508. "WMI: MceDelivery %p\n",
  509. QueryInfo));
  510. //
  511. // Store the HAL token which is needed to retrieve the logs from
  512. // the hal
  513. //
  514. QueryInfo->Token = Token;
  515. //
  516. // If we are ready to handle the logs and we are dealing with thse
  517. // logs on an interrupt basis, then go ahead and queue a DPC to handle
  518. // processing the log
  519. //
  520. if ((WmipMCEState == MCE_STATE_RUNNING) &&
  521. (QueryInfo->PollCounter == HAL_CMC_INTERRUPTS_BASED))
  522. {
  523. KeInsertQueueDpc(&QueryInfo->Dpc,
  524. QueryInfo,
  525. NULL);
  526. ret = TRUE;
  527. } else {
  528. ret = FALSE;
  529. }
  530. return(ret);
  531. }
  532. BOOLEAN WmipMcaDelivery(
  533. IN PVOID Reserved,
  534. IN PVOID Argument2
  535. )
  536. /*++
  537. Routine Description:
  538. This routine is called by the HAL when a MCA is discovered.
  539. It is called at high irql.
  540. Arguments:
  541. Reserved is the MCA token
  542. Argument2 is not used
  543. Return Value:
  544. TRUE to indicate that we handled the delivery
  545. --*/
  546. {
  547. BOOLEAN ret;
  548. ret = WmipCommonMceDelivery(&WmipMcaQueryInfo,
  549. Reserved);
  550. return(ret);
  551. }
  552. BOOLEAN WmipCmcDelivery(
  553. IN PVOID Reserved,
  554. IN PVOID Argument2
  555. )
  556. /*++
  557. Routine Description:
  558. This routine is called by the HAL when a CMC or CPE occurs. It is called
  559. at high irql
  560. Arguments:
  561. Reserved is the CMC token
  562. Argument2 is not used
  563. Return Value:
  564. TRUE to indicate that we handled the delivery
  565. --*/
  566. {
  567. BOOLEAN ret;
  568. ret = WmipCommonMceDelivery(&WmipCmcQueryInfo,
  569. Reserved);
  570. return(ret);
  571. }
  572. BOOLEAN WmipCpeDelivery(
  573. IN PVOID Reserved,
  574. IN PVOID Argument2
  575. )
  576. /*++
  577. Routine Description:
  578. This routine is called by the HAL when a CMC or CPE occurs. It is called
  579. at high irql
  580. Arguments:
  581. Reserved is the CPE token
  582. Argument2 is not used
  583. Return Value:
  584. TRUE to indicate that we handled the delivery
  585. --*/
  586. {
  587. BOOLEAN ret;
  588. ret = WmipCommonMceDelivery(&WmipCpeQueryInfo,
  589. Reserved);
  590. return(ret);
  591. }
  592. BOOLEAN WmipMceDelivery(
  593. IN PVOID Reserved,
  594. IN PVOID Argument2
  595. )
  596. /*++
  597. Routine Description:
  598. This routine is called by the HAL when a situation occurs between
  599. the HAL and SAL interface. It is called at high irql
  600. Arguments:
  601. Reserved has the Operation and EventType
  602. Argument2 has the SAL return code
  603. Return Value:
  604. --*/
  605. {
  606. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  607. "WMI: MCEDelivery\n"));
  608. return(FALSE);
  609. }
  610. void WmipProcessPrevMcaLogs(
  611. void
  612. )
  613. /*++
  614. Routine Description:
  615. This routine will flush out any of the previous MCA logs and then
  616. hang onto them for WMI to report.
  617. Arguments:
  618. Return Value:
  619. --*/
  620. {
  621. NTSTATUS status, status2;
  622. PERROR_LOGRECORD log;
  623. ULONG size;
  624. PWNODE_SINGLE_INSTANCE wnode;
  625. LIST_ENTRY list;
  626. ULONG prevLogCount;
  627. PULONG ptr;
  628. ULONG sizeNeeded;
  629. PAGED_CODE();
  630. InitializeListHead(&list);
  631. sizeNeeded = sizeof(ULONG);
  632. prevLogCount = 0;
  633. do
  634. {
  635. //
  636. // Read a log out of the HAL
  637. //
  638. status = WmipGetLogFromHal(HalMcaLogInformation,
  639. WmipMcaQueryInfo.Token,
  640. &wnode,
  641. &log,
  642. &size,
  643. WmipMcaQueryInfo.MaxSize,
  644. &WmipMcaQueryInfo.WnodeGuid);
  645. if (NT_SUCCESS(status))
  646. {
  647. //
  648. // Previous logs have a ErrorSeverity of Fatal since they
  649. // were fatal and brought down the system in last boot.
  650. //
  651. //
  652. // This is a fatal MCA so we just hang onto it and keep
  653. // track of how much memory we will need
  654. //
  655. prevLogCount++;
  656. sizeNeeded += sizeof(ULONG) + ((size +3)&~3);
  657. InsertTailList(&list, (PLIST_ENTRY)wnode);
  658. WmipGenerateMCAEventlog((PUCHAR)log,
  659. size,
  660. TRUE);
  661. }
  662. } while (NT_SUCCESS(status));
  663. if (! IsListEmpty(&list))
  664. {
  665. //
  666. // We have collected a set of previous logs, so we need to
  667. // build the buffer containing the aggregation of those logs
  668. //
  669. WmipRawMCA = ExAllocatePoolWithTag(PagedPool,
  670. sizeNeeded,
  671. WmipMCAPoolTag);
  672. WmipRawMCASize = sizeNeeded;
  673. //
  674. // Fill in the count of logs that follow
  675. //
  676. ptr = (PULONG)WmipRawMCA;
  677. *ptr++ = prevLogCount;
  678. //
  679. // Loop over all previous logs
  680. //
  681. while (! IsListEmpty(&list))
  682. {
  683. wnode = (PWNODE_SINGLE_INSTANCE)RemoveHeadList(&list);
  684. if (ptr != NULL)
  685. {
  686. //
  687. // Get the log back from within the wnode
  688. //
  689. log = (PERROR_LOGRECORD)OffsetToPtr(wnode, wnode->DataBlockOffset);
  690. size = wnode->SizeDataBlock;
  691. //
  692. // Fill in the size of the log
  693. //
  694. *ptr++ = size;
  695. //
  696. // Copy the log data into our buffer
  697. //
  698. RtlCopyMemory(ptr, log, size);
  699. size = (size +3)&~3;
  700. ptr = (PULONG)( ((PUCHAR)ptr) + size );
  701. }
  702. ExFreePool(wnode);
  703. }
  704. }
  705. }
  706. NTSTATUS WmipRegisterMcaHandler(
  707. ULONG Phase
  708. )
  709. /*++
  710. Routine Description:
  711. This routine will register a kernel MCA and CMC handler with the
  712. hal
  713. Arguments:
  714. Return Value:
  715. NT status code
  716. --*/
  717. {
  718. KERNEL_ERROR_HANDLER_INFO KernelMcaHandlerInfo;
  719. NTSTATUS Status, Status2;
  720. HAL_ERROR_INFO HalErrorInfo;
  721. ULONG ReturnSize;
  722. PAGED_CODE();
  723. if (Phase == 0)
  724. {
  725. //
  726. // Phase 0 initialization is done before device drivers are
  727. // loaded so that the kernel can register its kernel error
  728. // handler before any driver gets a chance to do so.
  729. //
  730. //
  731. // Get the size of the logs and any polling/interrupt policies
  732. //
  733. HalErrorInfo.Version = HAL_ERROR_INFO_VERSION;
  734. Status = HalQuerySystemInformation(HalErrorInformation,
  735. sizeof(HAL_ERROR_INFO),
  736. &HalErrorInfo,
  737. &ReturnSize);
  738. if ((NT_SUCCESS(Status)) &&
  739. (ReturnSize >= sizeof(HAL_ERROR_INFO)))
  740. {
  741. //
  742. // Initialize MCA QueryInfo structure
  743. //
  744. if (HalErrorInfo.McaMaxSize != 0)
  745. {
  746. WmipMcaQueryInfo.MaxSize = HalErrorInfo.McaMaxSize;
  747. }
  748. //
  749. // Corrected MCA are always delivered by interrupts
  750. //
  751. WmipSetQueryPollOrInt(&WmipMcaQueryInfo, HAL_MCA_INTERRUPTS_BASED);
  752. WmipMcaQueryInfo.Token = (PVOID)(ULONG_PTR) HalErrorInfo.McaKernelToken;
  753. //
  754. // Initialize DPC and Workitem for processing
  755. //
  756. KeInitializeDpc(&WmipMcaQueryInfo.Dpc,
  757. WmipMceDpcRoutine,
  758. NULL);
  759. ExInitializeWorkItem(&WmipMcaQueryInfo.WorkItem,
  760. WmipMceWorkerRoutine,
  761. &WmipMcaQueryInfo);
  762. //
  763. // Initialize CMC QueryInfo structure
  764. //
  765. if (HalErrorInfo.CmcMaxSize != 0)
  766. {
  767. WmipCmcQueryInfo.MaxSize = HalErrorInfo.CmcMaxSize;
  768. }
  769. #ifdef MCE_INSERTION
  770. WmipSetQueryPollOrInt(&WmipCmcQueryInfo,
  771. HAL_CMC_INTERRUPTS_BASED);
  772. WmipCmcQueryInfo.LogHead.Flink = &WmipCmcQueryInfo.LogHead;
  773. WmipCmcQueryInfo.LogHead.Blink = &WmipCmcQueryInfo.LogHead;
  774. #else
  775. WmipSetQueryPollOrInt(&WmipCmcQueryInfo,
  776. HalErrorInfo.CmcPollingInterval);
  777. #endif
  778. WmipCmcQueryInfo.Token = (PVOID)(ULONG_PTR) HalErrorInfo.CmcKernelToken;
  779. //
  780. // Initialize DPC and Workitem for processing
  781. //
  782. KeInitializeDpc(&WmipCmcQueryInfo.Dpc,
  783. WmipMceDpcRoutine,
  784. NULL);
  785. ExInitializeWorkItem(&WmipCmcQueryInfo.WorkItem,
  786. WmipMceWorkerRoutine,
  787. &WmipCmcQueryInfo);
  788. //
  789. // Initialize CPE QueryInfo structure
  790. //
  791. if (HalErrorInfo.CpeMaxSize != 0)
  792. {
  793. WmipCpeQueryInfo.MaxSize = HalErrorInfo.CpeMaxSize;
  794. }
  795. #ifdef MCE_INSERTION
  796. WmipSetQueryPollOrInt(&WmipCpeQueryInfo,
  797. 60);
  798. WmipCpeQueryInfo.LogHead.Flink = &WmipCpeQueryInfo.LogHead;
  799. WmipCpeQueryInfo.LogHead.Blink = &WmipCpeQueryInfo.LogHead;
  800. #else
  801. WmipSetQueryPollOrInt(&WmipCpeQueryInfo,
  802. HalErrorInfo.CpePollingInterval);
  803. #endif
  804. WmipCpeQueryInfo.Token = (PVOID)(ULONG_PTR) HalErrorInfo.CpeKernelToken;
  805. //
  806. // Initialize DPC and Workitem for processing
  807. //
  808. KeInitializeDpc(&WmipCpeQueryInfo.Dpc,
  809. WmipMceDpcRoutine,
  810. NULL);
  811. ExInitializeWorkItem(&WmipCpeQueryInfo.WorkItem,
  812. WmipMceWorkerRoutine,
  813. &WmipCpeQueryInfo);
  814. //
  815. // Register our CMC and MCA callbacks. And if interrupt driven CPE
  816. // callbacks are enabled register them too
  817. //
  818. KernelMcaHandlerInfo.Version = KERNEL_ERROR_HANDLER_VERSION;
  819. KernelMcaHandlerInfo.KernelMcaDelivery = WmipMcaDelivery;
  820. KernelMcaHandlerInfo.KernelCmcDelivery = WmipCmcDelivery;
  821. KernelMcaHandlerInfo.KernelCpeDelivery = WmipCpeDelivery;
  822. KernelMcaHandlerInfo.KernelMceDelivery = WmipMceDelivery;
  823. Status = HalSetSystemInformation(HalKernelErrorHandler,
  824. sizeof(KERNEL_ERROR_HANDLER_INFO),
  825. &KernelMcaHandlerInfo);
  826. if (NT_SUCCESS(Status))
  827. {
  828. WmipMCEState = MCE_STATE_REGISTERED;
  829. } else {
  830. WmipMCEState = MCE_STATE_ERROR;
  831. WmipDebugPrintEx((DPFLTR_WMICORE_ID,
  832. DPFLTR_MCA_LEVEL | DPFLTR_ERROR_LEVEL,
  833. "WMI: Error %x registering MCA error handlers\n",
  834. Status));
  835. }
  836. }
  837. } else if (WmipMCEState != MCE_STATE_ERROR) {
  838. //
  839. // Phase 1 initialization is done after all of the boot drivers
  840. // have loaded and have had a chance to register for WMI event
  841. // notifications. At this point it is safe to go ahead and send
  842. // wmi events for MCA, CMC, CPE, etc
  843. //
  844. // If there were any MCA logs generated prior to boot then get
  845. // them out of the HAL and process them. Do this before
  846. // starting any polling since the SAL likes to have the
  847. // previous MCA records removed before being polled for CPE and
  848. // CMC
  849. //
  850. #if 0
  851. // DEBUG
  852. //
  853. // Test code to generate a previous MCA without having
  854. // had generate one previously
  855. //
  856. {
  857. PERROR_SMBIOS s;
  858. UCHAR Buffer[0x400];
  859. PERROR_RECORD_HEADER rh;
  860. PERROR_SECTION_HEADER sh;
  861. #define ERROR_SMBIOS_GUID \
  862. { 0xe429faf5, 0x3cb7, 0x11d4, { 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 }}
  863. ERROR_DEVICE_GUID ErrorSmbiosGuid = ERROR_SMBIOS_GUID;
  864. rh = (PERROR_RECORD_HEADER)Buffer;
  865. rh->Id = 0x12345678;
  866. rh->Revision.Revision = 0x0200;
  867. rh->Valid.Valid = 0;
  868. rh->TimeStamp.TimeStamp = 0x2001031900165323;
  869. sh = (PERROR_SECTION_HEADER)((PUCHAR)rh + sizeof(ERROR_RECORD_HEADER));
  870. memset(sh, 0, sizeof(Buffer));
  871. sh->Revision.Revision = 0x0200;
  872. sh->RecoveryInfo.RecoveryInfo = 0;
  873. sh->Length = sizeof(ERROR_SMBIOS);
  874. sh->Guid = ErrorSmbiosGuid;
  875. s = (PERROR_SMBIOS)sh;
  876. s->Valid.Valid = 0;
  877. s->Valid.EventType = 1;
  878. s->EventType = 0xa0;
  879. rh->Length = sizeof(ERROR_RECORD_HEADER) + sh->Length;
  880. WmipGenerateMCAEventlog(Buffer,
  881. rh->Length,
  882. TRUE);
  883. }
  884. // DEBUG
  885. #endif
  886. HalErrorInfo.Version = HAL_ERROR_INFO_VERSION;
  887. Status = HalQuerySystemInformation(HalErrorInformation,
  888. sizeof(HAL_ERROR_INFO),
  889. &HalErrorInfo,
  890. &ReturnSize);
  891. if ((NT_SUCCESS(Status)) &&
  892. (ReturnSize >= sizeof(HAL_ERROR_INFO)))
  893. {
  894. if (HalErrorInfo.McaPreviousEventsCount != 0)
  895. {
  896. //
  897. // We need to flush out any previous MCA logs and then
  898. // make them available via WMI
  899. //
  900. WmipProcessPrevMcaLogs();
  901. }
  902. }
  903. if (((WmipCmcQueryInfo.PollCounter != HAL_CMC_DISABLED) &&
  904. (WmipCmcQueryInfo.PollCounter != HAL_CMC_INTERRUPTS_BASED)) ||
  905. ((WmipCpeQueryInfo.PollCounter != HAL_CPE_DISABLED) &&
  906. (WmipCpeQueryInfo.PollCounter != HAL_CPE_INTERRUPTS_BASED)))
  907. {
  908. Status2 = IoInitializeTimer(WmipServiceDeviceObject,
  909. WmipMceTimerRoutine,
  910. NULL);
  911. if (NT_SUCCESS(Status2))
  912. {
  913. //
  914. // Start off timer so that it fires right away in case
  915. // there are any CMC/CPE that were generated before now
  916. //
  917. IoStartTimer(WmipServiceDeviceObject);
  918. } else {
  919. //
  920. // CONSIDER: Figure out another way to poll
  921. //
  922. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  923. "WMI: Cant start IoTimer %x\n",
  924. Status2));
  925. }
  926. }
  927. //
  928. // Flag that we are now able to start firing events
  929. //
  930. WmipMCEState = MCE_STATE_RUNNING;
  931. Status = STATUS_SUCCESS;
  932. }
  933. return(Status);
  934. }
  935. NTSTATUS WmipGetRawMCAInfo(
  936. OUT PUCHAR Buffer,
  937. IN OUT PULONG BufferSize
  938. )
  939. /*++
  940. Routine Description:
  941. Return raw MCA log that was already retrieved from hal
  942. Arguments:
  943. Return Value:
  944. NT status code
  945. --*/
  946. {
  947. ULONG InBufferSize = *BufferSize;
  948. NTSTATUS Status;
  949. PAGED_CODE();
  950. *BufferSize = WmipRawMCASize;
  951. if (InBufferSize >= WmipRawMCASize)
  952. {
  953. RtlCopyMemory(Buffer, WmipRawMCA, WmipRawMCASize);
  954. Status = STATUS_SUCCESS;
  955. } else {
  956. Status = STATUS_BUFFER_TOO_SMALL;
  957. }
  958. return(Status);
  959. }
  960. NTSTATUS WmipGetLogFromHal(
  961. IN HAL_QUERY_INFORMATION_CLASS InfoClass,
  962. IN PVOID Token,
  963. IN OUT PWNODE_SINGLE_INSTANCE *Wnode,
  964. OUT PERROR_LOGRECORD *Mca,
  965. OUT PULONG McaSize,
  966. IN ULONG MaxSize,
  967. IN LPGUID Guid
  968. )
  969. /*++
  970. Routine Description:
  971. This routine will call the HAL to get a log and possibly build a
  972. wnode event for it.
  973. Arguments:
  974. InfoClass is the HalInformationClass that specifies the log
  975. information to retrieve
  976. Token is the HAL token for the log type
  977. *Wnode returns a pointer to a WNODE_EVENT_ITEM containing the log
  978. information if Wnode is not NULL
  979. *Mca returns a pointer to the log read from the hal. It may point
  980. into the memory pointed to by *Wnode
  981. *McaSize returns with the size of the log infomration.
  982. MaxSize has the maximum size to allocate for the log data
  983. Guid points to the guid to use if a Wnode is built
  984. Return Value:
  985. NT status code
  986. --*/
  987. {
  988. NTSTATUS Status;
  989. PERROR_LOGRECORD Log;
  990. PWNODE_SINGLE_INSTANCE WnodeSI;
  991. PULONG Ptr;
  992. ULONG Size, LogSize, WnodeSize;
  993. PAGED_CODE();
  994. //
  995. // If we are reading directly into a wnode then set this up
  996. //
  997. if (Wnode != NULL)
  998. {
  999. WnodeSize = FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData) +
  1000. 2 * sizeof(ULONG);
  1001. } else {
  1002. WnodeSize = 0;
  1003. }
  1004. //
  1005. // Allocate a buffer to store the log reported from the hal. Note
  1006. // that this must be in non paged pool as per the HAL.
  1007. //
  1008. Size = MaxSize + WnodeSize;
  1009. Ptr = ExAllocatePoolWithTag(NonPagedPool,
  1010. Size,
  1011. WmipMCAPoolTag);
  1012. if (Ptr != NULL)
  1013. {
  1014. Log = (PERROR_LOGRECORD)((PUCHAR)Ptr + WnodeSize);
  1015. LogSize = Size - WnodeSize;
  1016. *(PVOID *)Log = Token;
  1017. #ifdef MCE_INSERTION
  1018. Status = WmipQuerySystemInformation(InfoClass,
  1019. LogSize,
  1020. Log,
  1021. &LogSize);
  1022. #else
  1023. Status = HalQuerySystemInformation(InfoClass,
  1024. LogSize,
  1025. Log,
  1026. &LogSize);
  1027. #endif
  1028. if (Status == STATUS_BUFFER_TOO_SMALL)
  1029. {
  1030. //
  1031. // If our buffer was too small then the Hal lied to us when
  1032. // it told us the maximum buffer size. This is ok as we'll
  1033. // handle this situation by reallocating and trying again
  1034. //
  1035. ExFreePool(Log);
  1036. //
  1037. // Reallocate the buffer and call the hal to get the log
  1038. //
  1039. Size = LogSize + WnodeSize;
  1040. Ptr = ExAllocatePoolWithTag(NonPagedPool,
  1041. Size,
  1042. WmipMCAPoolTag);
  1043. if (Ptr != NULL)
  1044. {
  1045. Log = (PERROR_LOGRECORD)((PUCHAR)Ptr + WnodeSize);
  1046. LogSize = Size - WnodeSize;
  1047. *(PVOID *)Log = Token;
  1048. Status = HalQuerySystemInformation(InfoClass,
  1049. LogSize,
  1050. Log,
  1051. &LogSize);
  1052. //
  1053. // The hal gave us a buffer size needed that was too
  1054. // small, so lets stop right here and let him know]
  1055. //
  1056. WmipAssert(Status != STATUS_BUFFER_TOO_SMALL);
  1057. } else {
  1058. Status = STATUS_INSUFFICIENT_RESOURCES;
  1059. }
  1060. }
  1061. if (NT_SUCCESS(Status))
  1062. {
  1063. //
  1064. // We sucessfully read the data from the hal so build up
  1065. // output buffers.
  1066. //
  1067. if (Wnode != NULL)
  1068. {
  1069. //
  1070. // Caller requested buffer returned within a WNODE, so
  1071. // build up the wnode around the log data
  1072. //
  1073. WnodeSI = (PWNODE_SINGLE_INSTANCE)Ptr;
  1074. Status = WmipBuildMcaCmcEvent(WnodeSI,
  1075. Guid,
  1076. NULL,
  1077. LogSize);
  1078. *Wnode = WnodeSI;
  1079. }
  1080. *Mca = Log;
  1081. *McaSize = LogSize;
  1082. }
  1083. if ((! NT_SUCCESS(Status)) && (Ptr != NULL))
  1084. {
  1085. //
  1086. // If the function failed, but we have an allocated buffer
  1087. // then clean it up
  1088. //
  1089. ExFreePool(Ptr);
  1090. }
  1091. } else {
  1092. Status = STATUS_INSUFFICIENT_RESOURCES;
  1093. }
  1094. return(Status);
  1095. }
  1096. typedef enum
  1097. {
  1098. CpuStateCheckCache = 0,
  1099. CpuStateCheckTLB = 1,
  1100. CpuStateCheckBus = 2,
  1101. CpuStateCheckRegFile = 3,
  1102. CpuStateCheckMS = 4
  1103. };
  1104. void WmipGenerateMCAEventlog(
  1105. PUCHAR ErrorLog,
  1106. ULONG ErrorLogSize,
  1107. BOOLEAN IsFatal
  1108. )
  1109. {
  1110. PERROR_RECORD_HEADER RecordHeader;
  1111. PERROR_SECTION_HEADER SectionHeader;
  1112. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  1113. PWCHAR w;
  1114. ULONG BufferSize, SizeUsed;
  1115. PUCHAR Buffer, RawPtr;
  1116. PWNODE_SINGLE_INSTANCE Wnode;
  1117. PMSMCAEvent_Header Header;
  1118. ULONG CpuErrorState = CpuStateCheckCache;
  1119. ULONG CpuErrorIndex = 0;
  1120. BOOLEAN AdvanceSection;
  1121. PERROR_MODINFO ModInfo;
  1122. BOOLEAN FirstError;
  1123. PAGED_CODE();
  1124. RecordHeader = (PERROR_RECORD_HEADER)ErrorLog;
  1125. //
  1126. // Allocate a buffer large enough to accomodate any type of MCA.
  1127. // Right now the largest is MSMCAEvent_MemoryError. If this changes
  1128. // then this code should be updated
  1129. //
  1130. BufferSize = ((sizeof(WNODE_SINGLE_INSTANCE) +
  1131. (sizeof(USHORT) + sizeof(MCA_EVENT_INSTANCE_NAME)) +7) & ~7) +
  1132. sizeof(MSMCAEvent_MemoryError) +
  1133. ErrorLogSize;
  1134. //
  1135. // Allocate a buffer to build the event
  1136. //
  1137. Buffer = ExAllocatePoolWithTag(PagedPool,
  1138. BufferSize,
  1139. WmipMCAPoolTag);
  1140. if (Buffer != NULL)
  1141. {
  1142. //
  1143. // Fill in the common fields of the WNODE
  1144. //
  1145. Wnode = (PWNODE_SINGLE_INSTANCE)Buffer;
  1146. Wnode->WnodeHeader.BufferSize = BufferSize;
  1147. Wnode->WnodeHeader.Linkage = 0;
  1148. WmiInsertTimestamp(&Wnode->WnodeHeader);
  1149. Wnode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE |
  1150. WNODE_FLAG_EVENT_ITEM;
  1151. Wnode->OffsetInstanceName = sizeof(WNODE_SINGLE_INSTANCE);
  1152. Wnode->DataBlockOffset = ((sizeof(WNODE_SINGLE_INSTANCE) +
  1153. (sizeof(USHORT) + sizeof(MCA_EVENT_INSTANCE_NAME)) +7) & ~7);
  1154. w = (PWCHAR)OffsetToPtr(Wnode, Wnode->OffsetInstanceName);
  1155. *w++ = sizeof(MCA_EVENT_INSTANCE_NAME);
  1156. wcscpy(w, MCA_EVENT_INSTANCE_NAME);
  1157. //
  1158. // Fill in the common fields of the event data
  1159. //
  1160. Header = (PMSMCAEvent_Header)OffsetToPtr(Wnode, Wnode->DataBlockOffset);
  1161. Header->Cpu = MCA_UNDEFINED_CPU; // assume CPU will be undefined
  1162. Header->AdditionalErrors = 0;
  1163. if ((ErrorLogSize < sizeof(ERROR_RECORD_HEADER)) ||
  1164. (RecordHeader->Revision.Revision != SAL_30_ERROR_REVISION) ||
  1165. (RecordHeader->Length > ErrorLogSize))
  1166. {
  1167. //
  1168. // Record header is not SAL 3.0 compliant so we do not try
  1169. // to interpert the record
  1170. //
  1171. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1172. "WMI: Invalid MCA Record revision %x or size %d at %p\n"
  1173. "do !mca %p to dump MCA record\n",
  1174. RecordHeader->Revision,
  1175. RecordHeader->Length,
  1176. RecordHeader,
  1177. RecordHeader));
  1178. Status = STATUS_INVALID_PARAMETER;
  1179. } else {
  1180. //
  1181. // Valid 3.0 record, gather the record id and severity from
  1182. // the header
  1183. //
  1184. Header->RecordId = RecordHeader->Id;
  1185. Header->ErrorSeverity = RecordHeader->ErrorSeverity;
  1186. Header->Cpu = HalpGetFwMceLogProcessorNumber(RecordHeader);
  1187. //
  1188. // Use the error severity value in the record header to
  1189. // determine if the error was fatal. If the value is
  1190. // ErrorRecoverable then assume that the error was fatal
  1191. // since the HAL will change this value to ErrorCorrected
  1192. //
  1193. IsFatal = (RecordHeader->ErrorSeverity != ErrorCorrected);
  1194. //
  1195. // Loop over all sections within the record.
  1196. //
  1197. // CONSIDER: Is it possible to have a record that only has a record
  1198. // header and no sections
  1199. //
  1200. SizeUsed = sizeof(ERROR_RECORD_HEADER);
  1201. ModInfo = NULL;
  1202. FirstError = TRUE;
  1203. while (SizeUsed < ErrorLogSize)
  1204. {
  1205. //
  1206. // Advance to the next section in the record
  1207. //
  1208. SectionHeader = (PERROR_SECTION_HEADER)(ErrorLog + SizeUsed);
  1209. AdvanceSection = TRUE;
  1210. Header->AdditionalErrors++;
  1211. //
  1212. // First validate that this is a 3.0 section
  1213. //
  1214. if (((SizeUsed + sizeof(ERROR_SECTION_HEADER)) > ErrorLogSize) ||
  1215. (SectionHeader->Revision.Revision != SAL_30_ERROR_REVISION) ||
  1216. ((SizeUsed + SectionHeader->Length) > ErrorLogSize))
  1217. {
  1218. //
  1219. // Not 3.0 section header so we'll give up on
  1220. // the whole record
  1221. //
  1222. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1223. "WMI: Invalid MCA SectionHeader revision %d or length %d at %p\n"
  1224. "do !mca %p to dump MCA record\n",
  1225. SectionHeader->Revision,
  1226. SectionHeader->Length,
  1227. SectionHeader,
  1228. RecordHeader));
  1229. //
  1230. // We'll break out of the loop since we don't know how to
  1231. // move on to the next MCA section since we don't
  1232. // understand any format previous to 3.0
  1233. //
  1234. Status = STATUS_INVALID_PARAMETER;
  1235. break;
  1236. } else {
  1237. //
  1238. // Now determine what type of section we have got. This is
  1239. // determined by looking at the guid in the section header.
  1240. // Each section type has a unique guid value
  1241. //
  1242. if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorProcessorGuid))
  1243. {
  1244. //
  1245. // Build event for CPU eventlog MCA
  1246. //
  1247. PMSMCAEvent_CPUError Event;
  1248. PERROR_PROCESSOR Processor;
  1249. ULONG TotalSectionSize;
  1250. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1251. sizeof(MSMCAEvent_CPUError) );
  1252. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1253. "WMI: MCA Section %p indicates processor error\n",
  1254. SectionHeader));
  1255. //
  1256. // Validate that the section length is large
  1257. // enough to accomodate all of the information
  1258. // that it declares
  1259. //
  1260. if (SectionHeader->Length >= sizeof(ERROR_PROCESSOR))
  1261. {
  1262. Event = (PMSMCAEvent_CPUError)Header;
  1263. Processor = (PERROR_PROCESSOR)SectionHeader;
  1264. //
  1265. // Validate that section is large enough to
  1266. // handle all specified ERROR_MODINFO
  1267. // structs
  1268. //
  1269. TotalSectionSize = sizeof(ERROR_PROCESSOR) +
  1270. ((Processor->Valid.CacheCheckNum +
  1271. Processor->Valid.TlbCheckNum +
  1272. Processor->Valid.BusCheckNum +
  1273. Processor->Valid.RegFileCheckNum +
  1274. Processor->Valid.MsCheckNum) *
  1275. sizeof(ERROR_MODINFO));
  1276. if (SectionHeader->Length >= TotalSectionSize)
  1277. {
  1278. //
  1279. // Initialize pointer to the current ERROR_MOFINFO
  1280. //
  1281. if (ModInfo == NULL)
  1282. {
  1283. ModInfo = (PERROR_MODINFO)((PUCHAR)Processor +
  1284. sizeof(ERROR_PROCESSOR));
  1285. } else {
  1286. ModInfo++;
  1287. }
  1288. switch (CpuErrorState)
  1289. {
  1290. case CpuStateCheckCache:
  1291. {
  1292. ERROR_CACHE_CHECK Check;
  1293. if (Processor->Valid.CacheCheckNum > CpuErrorIndex)
  1294. {
  1295. //
  1296. // We have a cache error that we need to
  1297. // handle.
  1298. // Advance to next error in the section,
  1299. // but don't advance the section
  1300. //
  1301. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1302. "WMI: MCA ModInfo %p indicates cache error index %d\n",
  1303. ModInfo,
  1304. CpuErrorIndex));
  1305. CpuErrorIndex++;
  1306. AdvanceSection = FALSE;
  1307. if (FirstError)
  1308. {
  1309. Event->Type = IsFatal ? MCA_ERROR_CACHE :
  1310. MCA_WARNING_CACHE;
  1311. Check.CacheCheck = ModInfo->CheckInfo.CheckInfo;
  1312. Event->Level = (ULONG)Check.Level;
  1313. }
  1314. break;
  1315. } else {
  1316. CpuErrorState = CpuStateCheckTLB;
  1317. CpuErrorIndex = 0;
  1318. // Fall through and see if there are any
  1319. // TLB errors
  1320. }
  1321. }
  1322. case CpuStateCheckTLB:
  1323. {
  1324. ERROR_TLB_CHECK Check;
  1325. if (Processor->Valid.TlbCheckNum > CpuErrorIndex)
  1326. {
  1327. //
  1328. // We have a cache error that we need to
  1329. // handle.
  1330. // Advance to next error in the section,
  1331. // but don't advance the section
  1332. //
  1333. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1334. "WMI: MCA ModInfo %p indicates TLB error index %d\n",
  1335. ModInfo,
  1336. CpuErrorIndex));
  1337. CpuErrorIndex++;
  1338. AdvanceSection = FALSE;
  1339. if (FirstError)
  1340. {
  1341. Event->Type = IsFatal ? MCA_ERROR_TLB :
  1342. MCA_WARNING_TLB;
  1343. Check.TlbCheck = ModInfo->CheckInfo.CheckInfo;
  1344. Event->Level = (ULONG)Check.Level;
  1345. }
  1346. break;
  1347. } else {
  1348. CpuErrorState = CpuStateCheckBus;
  1349. CpuErrorIndex = 0;
  1350. // Fall through and see if there are any
  1351. // CPU Bus errors
  1352. }
  1353. }
  1354. case CpuStateCheckBus:
  1355. {
  1356. if (Processor->Valid.BusCheckNum > CpuErrorIndex)
  1357. {
  1358. //
  1359. // We have a cache error that we need to
  1360. // handle.
  1361. // Advance to next error in the section,
  1362. // but don't advance the section
  1363. //
  1364. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1365. "WMI: MCA ModInfo %p indicates bus error index %d\n",
  1366. ModInfo,
  1367. CpuErrorIndex));
  1368. CpuErrorIndex++;
  1369. AdvanceSection = FALSE;
  1370. if (FirstError)
  1371. {
  1372. Event->Type = IsFatal ? MCA_ERROR_CPU_BUS :
  1373. MCA_WARNING_CPU_BUS;
  1374. }
  1375. break;
  1376. } else {
  1377. CpuErrorState = CpuStateCheckRegFile;
  1378. CpuErrorIndex = 0;
  1379. // Fall through and see if there are any
  1380. // REG FILE errors
  1381. }
  1382. }
  1383. case CpuStateCheckRegFile:
  1384. {
  1385. if (Processor->Valid.RegFileCheckNum > CpuErrorIndex)
  1386. {
  1387. //
  1388. // We have a cache error that we need to
  1389. // handle.
  1390. // Advance to next error in the section,
  1391. // but don't advance the section
  1392. //
  1393. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1394. "WMI: MCA ModInfo %p indicates reg file error index %d\n",
  1395. ModInfo,
  1396. CpuErrorIndex));
  1397. CpuErrorIndex++;
  1398. AdvanceSection = FALSE;
  1399. if (FirstError)
  1400. {
  1401. Event->Type = IsFatal ? MCA_ERROR_REGISTER_FILE :
  1402. MCA_WARNING_REGISTER_FILE;
  1403. }
  1404. break;
  1405. } else {
  1406. CpuErrorState = CpuStateCheckMS;
  1407. CpuErrorIndex = 0;
  1408. // Fall through and see if there are any
  1409. // Micro Architecture errors
  1410. }
  1411. }
  1412. case CpuStateCheckMS:
  1413. {
  1414. if (Processor->Valid.MsCheckNum > CpuErrorIndex)
  1415. {
  1416. //
  1417. // We have a cache error that we need to
  1418. // handle.
  1419. // Advance to next error in the section,
  1420. // but don't advance the section
  1421. //
  1422. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1423. "WMI: MCA ModInfo %p indicates MAS error index %d\n",
  1424. ModInfo,
  1425. CpuErrorIndex));
  1426. CpuErrorIndex++;
  1427. AdvanceSection = FALSE;
  1428. if (FirstError)
  1429. {
  1430. Event->Type = IsFatal ? MCA_ERROR_MAS :
  1431. MCA_WARNING_MAS;
  1432. }
  1433. break;
  1434. } else {
  1435. //
  1436. // There are no more errors left in the
  1437. // error section so we don't want to
  1438. // generate anything.
  1439. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1440. "WMI: MCA ModInfo %p indicates no error index %d\n",
  1441. ModInfo,
  1442. CpuErrorIndex));
  1443. Header->AdditionalErrors--;
  1444. goto DontGenerate;
  1445. }
  1446. }
  1447. }
  1448. if (FirstError)
  1449. {
  1450. Event->Size = ErrorLogSize;
  1451. RawPtr = Event->RawRecord;
  1452. //
  1453. // Finish filling in WNODE fields
  1454. //
  1455. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_CPUErrorGuid;
  1456. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_CPUError,
  1457. RawRecord) +
  1458. ErrorLogSize;
  1459. }
  1460. Status = STATUS_SUCCESS;
  1461. }
  1462. } else {
  1463. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1464. "WMI: MCA Processor Error Section %p has invalid size %d\n",
  1465. SectionHeader,
  1466. SectionHeader->Length));
  1467. Status = STATUS_INVALID_PARAMETER;
  1468. break;
  1469. }
  1470. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorMemoryGuid)) {
  1471. //
  1472. // Build event for MEMORY error eventlog MCA
  1473. //
  1474. PMSMCAEvent_MemoryError Event;
  1475. PERROR_MEMORY Memory;
  1476. ERROR_MEMORY_VALID Base, Mask;
  1477. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1478. "WMI: MCA Section %p indicates memory error\n",
  1479. SectionHeader));
  1480. Status = STATUS_SUCCESS;
  1481. if (FirstError)
  1482. {
  1483. //
  1484. // Ensure the record contains all of the
  1485. // fields that it is supposed to
  1486. //
  1487. if (SectionHeader->Length >= sizeof(ERROR_MEMORY))
  1488. {
  1489. Event = (PMSMCAEvent_MemoryError)Header;
  1490. Memory = (PERROR_MEMORY)SectionHeader;
  1491. //
  1492. // Fill in the data from the MCA within the WMI event
  1493. //
  1494. if ((Memory->Valid.PhysicalAddress == 1) &&
  1495. (Memory->Valid.AddressMask == 1) &&
  1496. (Memory->Valid.Card == 1) &&
  1497. (Memory->Valid.Module == 1))
  1498. {
  1499. Event->Type = IsFatal ? MCA_ERROR_MEM_1_2_5_4 :
  1500. MCA_WARNING_MEM_1_2_5_4;
  1501. } else if ((Memory->Valid.PhysicalAddress == 1) &&
  1502. (Memory->Valid.AddressMask == 1) &&
  1503. (Memory->Valid.Module == 1))
  1504. {
  1505. Event->Type = IsFatal ? MCA_ERROR_MEM_1_2_5 :
  1506. MCA_WARNING_MEM_1_2_5;
  1507. } else if ((Memory->Valid.PhysicalAddress == 1) &&
  1508. (Memory->Valid.AddressMask == 1))
  1509. {
  1510. Event->Type = IsFatal ? MCA_ERROR_MEM_1_2:
  1511. MCA_WARNING_MEM_1_2;
  1512. } else {
  1513. Event->Type = IsFatal ? MCA_ERROR_MEM_UNKNOWN:
  1514. MCA_WARNING_MEM_UNKNOWN;
  1515. }
  1516. Event->VALIDATION_BITS = Memory->Valid.Valid;
  1517. Event->MEM_ERROR_STATUS = Memory->ErrorStatus.Status;
  1518. Event->MEM_PHYSICAL_ADDR = Memory->PhysicalAddress;
  1519. Event->MEM_PHYSICAL_MASK = Memory->PhysicalAddressMask;
  1520. Event->RESPONDER_ID = Memory->ResponderId;
  1521. Event->TARGET_ID = Memory->TargetId;
  1522. Event->REQUESTOR_ID = Memory->RequestorId;
  1523. Event->BUS_SPECIFIC_DATA = Memory->BusSpecificData;
  1524. Event->MEM_NODE = Memory->Node;
  1525. Event->MEM_CARD = Memory->Card;
  1526. Event->MEM_BANK = Memory->Bank;
  1527. Event->xMEM_DEVICE = Memory->Device;
  1528. Event->MEM_MODULE = Memory->Module;
  1529. Event->MEM_ROW = Memory->Row;
  1530. Event->MEM_COLUMN = Memory->Column;
  1531. Event->MEM_BIT_POSITION = Memory->BitPosition;
  1532. Event->Size = ErrorLogSize;
  1533. RawPtr = Event->RawRecord;
  1534. //
  1535. // Finish filling in WNODE fields
  1536. //
  1537. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_MemoryErrorGuid;
  1538. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_MemoryError,
  1539. RawRecord) +
  1540. ErrorLogSize;
  1541. } else {
  1542. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1543. "WMI: MCA Memory Error Section %p has invalid size %d\n",
  1544. SectionHeader,
  1545. SectionHeader->Length));
  1546. Status = STATUS_INVALID_PARAMETER;
  1547. break;
  1548. }
  1549. }
  1550. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorPCIBusGuid)) {
  1551. //
  1552. // Build event for PCI Component MCA
  1553. //
  1554. PMSMCAEvent_PCIBusError Event;
  1555. PERROR_PCI_BUS PciBus;
  1556. ULONG PCIBusErrorTypes[] = {
  1557. MCA_WARNING_PCI_BUS_PARITY,
  1558. MCA_ERROR_PCI_BUS_PARITY,
  1559. MCA_WARNING_PCI_BUS_SERR,
  1560. MCA_ERROR_PCI_BUS_SERR,
  1561. MCA_WARNING_PCI_BUS_MASTER_ABORT,
  1562. MCA_ERROR_PCI_BUS_MASTER_ABORT,
  1563. MCA_WARNING_PCI_BUS_TIMEOUT,
  1564. MCA_ERROR_PCI_BUS_TIMEOUT,
  1565. MCA_WARNING_PCI_BUS_PARITY,
  1566. MCA_ERROR_PCI_BUS_PARITY,
  1567. MCA_WARNING_PCI_BUS_PARITY,
  1568. MCA_ERROR_PCI_BUS_PARITY,
  1569. MCA_WARNING_PCI_BUS_PARITY,
  1570. MCA_ERROR_PCI_BUS_PARITY
  1571. };
  1572. ULONG PCIBusErrorTypesNoInfo[] = {
  1573. MCA_WARNING_PCI_BUS_PARITY_NO_INFO,
  1574. MCA_ERROR_PCI_BUS_PARITY_NO_INFO,
  1575. MCA_WARNING_PCI_BUS_SERR_NO_INFO,
  1576. MCA_ERROR_PCI_BUS_SERR_NO_INFO,
  1577. MCA_WARNING_PCI_BUS_MASTER_ABORT_NO_INFO,
  1578. MCA_ERROR_PCI_BUS_MASTER_ABORT_NO_INFO,
  1579. MCA_WARNING_PCI_BUS_TIMEOUT_NO_INFO,
  1580. MCA_ERROR_PCI_BUS_TIMEOUT_NO_INFO,
  1581. MCA_WARNING_PCI_BUS_PARITY_NO_INFO,
  1582. MCA_ERROR_PCI_BUS_PARITY_NO_INFO,
  1583. MCA_WARNING_PCI_BUS_PARITY_NO_INFO,
  1584. MCA_ERROR_PCI_BUS_PARITY_NO_INFO,
  1585. MCA_WARNING_PCI_BUS_PARITY_NO_INFO,
  1586. MCA_ERROR_PCI_BUS_PARITY_NO_INFO
  1587. };
  1588. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1589. sizeof(MSMCAEvent_PCIBusError) );
  1590. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1591. "WMI: MCA Section %p indicates PCI Bus error\n",
  1592. SectionHeader));
  1593. Status = STATUS_SUCCESS;
  1594. if (FirstError)
  1595. {
  1596. if (SectionHeader->Length >= sizeof(ERROR_PCI_BUS))
  1597. {
  1598. Event = (PMSMCAEvent_PCIBusError)Header;
  1599. PciBus = (PERROR_PCI_BUS)SectionHeader;
  1600. //
  1601. // Fill in the data from the MCA within the WMI event
  1602. //
  1603. if ((PciBus->Type.Type >= PciBusDataParityError) &&
  1604. (PciBus->Type.Type <= PciCommandParityError))
  1605. {
  1606. if ((PciBus->Valid.CmdType == 1) &&
  1607. (PciBus->Valid.Address == 1) &&
  1608. (PciBus->Valid.Id == 1))
  1609. {
  1610. Event->Type = PCIBusErrorTypes[(2 * (PciBus->Type.Type-1)) +
  1611. (IsFatal ? 1 : 0)];
  1612. } else {
  1613. Event->Type = PCIBusErrorTypesNoInfo[(2 * (PciBus->Type.Type-1)) +
  1614. (IsFatal ? 1 : 0)];
  1615. }
  1616. } else {
  1617. Event->Type = IsFatal ? MCA_ERROR_PCI_BUS_UNKNOWN :
  1618. MCA_WARNING_PCI_BUS_UNKNOWN;
  1619. }
  1620. Event->VALIDATION_BITS = PciBus->Valid.Valid;
  1621. Event->PCI_BUS_ERROR_STATUS = PciBus->ErrorStatus.Status;
  1622. Event->PCI_BUS_ADDRESS = PciBus->Address;
  1623. Event->PCI_BUS_DATA = PciBus->Data;
  1624. Event->PCI_BUS_CMD = PciBus->CmdType;
  1625. Event->PCI_BUS_REQUESTOR_ID = PciBus->RequestorId;
  1626. Event->PCI_BUS_RESPONDER_ID = PciBus->ResponderId;
  1627. Event->PCI_BUS_TARGET_ID = PciBus->TargetId;
  1628. Event->PCI_BUS_ERROR_TYPE = PciBus->Type.Type;
  1629. Event->PCI_BUS_ID_BusNumber = PciBus->Id.BusNumber;
  1630. Event->PCI_BUS_ID_SegmentNumber = PciBus->Id.SegmentNumber;
  1631. Event->Size = ErrorLogSize;
  1632. RawPtr = Event->RawRecord;
  1633. //
  1634. // Finish filling in WNODE fields
  1635. //
  1636. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_PCIBusErrorGuid;
  1637. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_PCIBusError,
  1638. RawRecord) +
  1639. ErrorLogSize;
  1640. } else {
  1641. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1642. "WMI: PCI Bus Error Section %p has invalid size %d\n",
  1643. SectionHeader,
  1644. SectionHeader->Length));
  1645. Status = STATUS_INVALID_PARAMETER;
  1646. break;
  1647. }
  1648. }
  1649. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorPCIComponentGuid)) {
  1650. //
  1651. // Build event for PCI Component MCA
  1652. //
  1653. PMSMCAEvent_PCIComponentError Event;
  1654. PERROR_PCI_COMPONENT PciComp;
  1655. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1656. "WMI: MCA Section %p indicates PCI Component error\n",
  1657. SectionHeader));
  1658. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1659. sizeof(MSMCAEvent_PCIComponentError) );
  1660. Status = STATUS_SUCCESS;
  1661. if (FirstError)
  1662. {
  1663. if (SectionHeader->Length >= sizeof(ERROR_PCI_COMPONENT))
  1664. {
  1665. Event = (PMSMCAEvent_PCIComponentError)Header;
  1666. PciComp = (PERROR_PCI_COMPONENT)SectionHeader;
  1667. //
  1668. // Fill in the data from the MCA within the WMI event
  1669. //
  1670. Event->Type = IsFatal ? MCA_ERROR_PCI_DEVICE :
  1671. MCA_WARNING_PCI_DEVICE;
  1672. Event->VALIDATION_BITS = PciComp->Valid.Valid;
  1673. Event->PCI_COMP_ERROR_STATUS = PciComp->ErrorStatus.Status;
  1674. Event->PCI_COMP_INFO_VendorId = (USHORT)PciComp->Info.VendorId;
  1675. Event->PCI_COMP_INFO_DeviceId = (USHORT)PciComp->Info.DeviceId;
  1676. Event->PCI_COMP_INFO_ClassCodeInterface = PciComp->Info.ClassCodeInterface;
  1677. Event->PCI_COMP_INFO_ClassCodeSubClass = PciComp->Info.ClassCodeSubClass;
  1678. Event->PCI_COMP_INFO_ClassCodeBaseClass = PciComp->Info.ClassCodeBaseClass;
  1679. Event->PCI_COMP_INFO_FunctionNumber = (UCHAR)PciComp->Info.FunctionNumber;
  1680. Event->PCI_COMP_INFO_DeviceNumber = (UCHAR)PciComp->Info.DeviceNumber;
  1681. Event->PCI_COMP_INFO_BusNumber = (UCHAR)PciComp->Info.BusNumber;
  1682. Event->PCI_COMP_INFO_SegmentNumber = (UCHAR)PciComp->Info.SegmentNumber;
  1683. Event->Size = ErrorLogSize;
  1684. RawPtr = Event->RawRecord;
  1685. //
  1686. // Finish filling in WNODE fields
  1687. //
  1688. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_PCIComponentErrorGuid;
  1689. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_PCIComponentError,
  1690. RawRecord) +
  1691. ErrorLogSize;
  1692. } else {
  1693. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1694. "WMI: PCI Component Error Section %p has invalid size %d\n",
  1695. SectionHeader,
  1696. SectionHeader->Length));
  1697. Status = STATUS_INVALID_PARAMETER;
  1698. break;
  1699. }
  1700. }
  1701. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorSELGuid)) {
  1702. //
  1703. // Build event for System Eventlog MCA
  1704. //
  1705. PMSMCAEvent_SystemEventError Event;
  1706. PERROR_SYSTEM_EVENT_LOG Sel;
  1707. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1708. sizeof(MSMCAEvent_SystemEventError) );
  1709. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1710. "WMI: MCA Section %p indicates SEL error\n",
  1711. SectionHeader));
  1712. Status = STATUS_SUCCESS;
  1713. if (FirstError)
  1714. {
  1715. if (SectionHeader->Length >= sizeof(ERROR_SYSTEM_EVENT_LOG))
  1716. {
  1717. Event = (PMSMCAEvent_SystemEventError)Header;
  1718. Sel = (PERROR_SYSTEM_EVENT_LOG)SectionHeader;
  1719. //
  1720. // Fill in the data from the MCA within the WMI event
  1721. //
  1722. Event->Type = IsFatal ? MCA_ERROR_SYSTEM_EVENT :
  1723. MCA_WARNING_SYSTEM_EVENT;
  1724. Event->VALIDATION_BITS = Sel->Valid.Valid;
  1725. Event->SEL_RECORD_ID = Sel->RecordId;
  1726. Event->SEL_RECORD_TYPE = Sel->RecordType;
  1727. Event->SEL_TIME_STAMP = Sel->TimeStamp;
  1728. Event->SEL_GENERATOR_ID = Sel->GeneratorId;
  1729. Event->SEL_EVM_REV = Sel->EVMRevision;
  1730. Event->SEL_SENSOR_TYPE = Sel->SensorType;
  1731. Event->SEL_SENSOR_NUM = Sel->SensorNumber;
  1732. Event->SEL_EVENT_DIR_TYPE = Sel->EventDir;
  1733. Event->SEL_DATA1 = Sel->Data1;
  1734. Event->SEL_DATA2 = Sel->Data2;
  1735. Event->SEL_DATA3 = Sel->Data3;
  1736. Event->Size = ErrorLogSize;
  1737. RawPtr = Event->RawRecord;
  1738. //
  1739. // Finish filling in WNODE fields
  1740. //
  1741. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_SystemEventErrorGuid;
  1742. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_SystemEventError,
  1743. RawRecord) +
  1744. ErrorLogSize;
  1745. } else {
  1746. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1747. "WMI: System Eventlog Error Section %p has invalid size %d\n",
  1748. SectionHeader,
  1749. SectionHeader->Length));
  1750. Status = STATUS_INVALID_PARAMETER;
  1751. break;
  1752. }
  1753. }
  1754. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorSMBIOSGuid)) {
  1755. //
  1756. // Build event for SMBIOS MCA
  1757. //
  1758. PMSMCAEvent_SMBIOSError Event;
  1759. PERROR_SMBIOS Smbios;
  1760. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1761. sizeof(MSMCAEvent_SMBIOSError) );
  1762. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1763. "WMI: MCA Section %p indicates smbios error\n",
  1764. SectionHeader));
  1765. Status = STATUS_SUCCESS;
  1766. if (FirstError)
  1767. {
  1768. if (SectionHeader->Length >= sizeof(ERROR_SMBIOS))
  1769. {
  1770. Event = (PMSMCAEvent_SMBIOSError)Header;
  1771. Smbios = (PERROR_SMBIOS)SectionHeader;
  1772. //
  1773. // Fill in the data from the MCA within the WMI event
  1774. //
  1775. Event->Type = IsFatal ? MCA_ERROR_SMBIOS :
  1776. MCA_WARNING_SMBIOS;
  1777. Event->VALIDATION_BITS = Smbios->Valid.Valid;
  1778. Event->SMBIOS_EVENT_TYPE = Smbios->EventType;
  1779. Event->Size = ErrorLogSize;
  1780. RawPtr = Event->RawRecord;
  1781. //
  1782. // Finish filling in WNODE fields
  1783. //
  1784. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_SMBIOSErrorGuid;
  1785. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_SMBIOSError,
  1786. RawRecord) +
  1787. ErrorLogSize;
  1788. } else {
  1789. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1790. "WMI: SMBIOS Error Section %p has invalid size %d\n",
  1791. SectionHeader,
  1792. SectionHeader->Length));
  1793. Status = STATUS_INVALID_PARAMETER;
  1794. break;
  1795. }
  1796. }
  1797. } else if (IsEqualGUID(&SectionHeader->Guid, &WmipErrorSpecificGuid)) {
  1798. //
  1799. // Build event for Platform Specific MCA
  1800. //
  1801. PMSMCAEvent_PlatformSpecificError Event;
  1802. PERROR_PLATFORM_SPECIFIC Specific;
  1803. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1804. sizeof(MSMCAEvent_PlatformSpecificError) );
  1805. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1806. "WMI: MCA Section %p indicates platform specific error\n",
  1807. SectionHeader));
  1808. Status = STATUS_SUCCESS;
  1809. if (FirstError)
  1810. {
  1811. if (SectionHeader->Length >= sizeof(ERROR_PLATFORM_SPECIFIC))
  1812. {
  1813. Event = (PMSMCAEvent_PlatformSpecificError)Header;
  1814. Specific = (PERROR_PLATFORM_SPECIFIC)SectionHeader;
  1815. //
  1816. // Fill in the data from the MCA within the WMI event
  1817. //
  1818. Event->Type = IsFatal ? MCA_ERROR_PLATFORM_SPECIFIC :
  1819. MCA_WARNING_PLATFORM_SPECIFIC;
  1820. Event->VALIDATION_BITS = Specific->Valid.Valid;
  1821. Event->PLATFORM_ERROR_STATUS = Specific->ErrorStatus.Status;
  1822. #if 0
  1823. // TODO: Wait until we figure this out
  1824. Event->PLATFORM_REQUESTOR_ID = Specific->;
  1825. Event->PLATFORM_RESPONDER_ID = Specific->;
  1826. Event->PLATFORM_TARGET_ID = Specific->;
  1827. Event->PLATFORM_BUS_SPECIFIC_DATA = Specific->;
  1828. Event->OEM_COMPONENT_ID = Specific->[16];
  1829. #endif
  1830. Event->Size = ErrorLogSize;
  1831. RawPtr = Event->RawRecord;
  1832. //
  1833. // Finish filling in WNODE fields
  1834. //
  1835. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_PlatformSpecificErrorGuid;
  1836. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_PlatformSpecificError,
  1837. RawRecord) +
  1838. ErrorLogSize;
  1839. } else {
  1840. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1841. "WMI: Platform specific Error Section %p has invalid size %d\n",
  1842. SectionHeader,
  1843. SectionHeader->Length));
  1844. Status = STATUS_INVALID_PARAMETER;
  1845. break;
  1846. }
  1847. }
  1848. } else {
  1849. //
  1850. // We don't recognize the guid, so we use a very generic
  1851. // eventlog message for it
  1852. //
  1853. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  1854. "WMI: Unknown Error GUID at %p\n",
  1855. &SectionHeader->Guid));
  1856. //
  1857. // If we've already analyzed an error then we
  1858. // don't really care that this one can't be
  1859. // analyzed
  1860. //
  1861. if (FirstError)
  1862. {
  1863. Status = STATUS_INVALID_PARAMETER;
  1864. }
  1865. }
  1866. }
  1867. //
  1868. // Advance to the next section within the Error record
  1869. //
  1870. DontGenerate:
  1871. if (AdvanceSection)
  1872. {
  1873. SizeUsed += SectionHeader->Length;
  1874. ModInfo = NULL;
  1875. }
  1876. //
  1877. // If we've successfully parsed an error section then
  1878. // we want to remember that. Only the first error gets
  1879. // analyzed while we calculate the number of additional
  1880. // errors following
  1881. //
  1882. if (NT_SUCCESS(Status))
  1883. {
  1884. FirstError = FALSE;
  1885. }
  1886. }
  1887. }
  1888. //
  1889. // If we were not able to build a specific event type then
  1890. // we fallback and fire a generic one
  1891. //
  1892. if (! NT_SUCCESS(Status))
  1893. {
  1894. //
  1895. // Build event for Unknown MCA
  1896. //
  1897. PMSMCAEvent_InvalidError Event;
  1898. WmipAssert( sizeof(MSMCAEvent_MemoryError) >=
  1899. sizeof(MSMCAEvent_InvalidError) );
  1900. Event = (PMSMCAEvent_InvalidError)Header;
  1901. //
  1902. // Fill in the data from the MCA within the WMI event
  1903. //
  1904. if (Header->Cpu == MCA_UNDEFINED_CPU)
  1905. {
  1906. Event->Type = IsFatal ? MCA_ERROR_UNKNOWN_NO_CPU :
  1907. MCA_WARNING_UNKNOWN_NO_CPU;
  1908. } else {
  1909. Event->Type = IsFatal ? MCA_ERROR_UNKNOWN :
  1910. MCA_WARNING_UNKNOWN;
  1911. }
  1912. Event->Size = ErrorLogSize;
  1913. RawPtr = Event->RawRecord;
  1914. //
  1915. // Finish filling in WNODE fields
  1916. //
  1917. Wnode->WnodeHeader.Guid = WmipMSMCAEvent_InvalidErrorGuid;
  1918. Wnode->SizeDataBlock = FIELD_OFFSET(MSMCAEvent_InvalidError,
  1919. RawRecord) +
  1920. ErrorLogSize;
  1921. }
  1922. //
  1923. // Adjust the Error event count
  1924. //
  1925. if (Header->AdditionalErrors > 0)
  1926. {
  1927. Header->AdditionalErrors--;
  1928. }
  1929. //
  1930. // Put the entire MCA record into the event
  1931. //
  1932. RtlCopyMemory(RawPtr,
  1933. RecordHeader,
  1934. ErrorLogSize);
  1935. //
  1936. // Now go and fire off the event
  1937. Status = WmipWriteMCAEventLogEvent((PUCHAR)Wnode);
  1938. if (! NT_SUCCESS(Status))
  1939. {
  1940. ExFreePool(Wnode);
  1941. }
  1942. if (WmipDisableMCAPopups == 0)
  1943. {
  1944. IoRaiseInformationalHardError(STATUS_MCA_OCCURED,
  1945. NULL,
  1946. NULL);
  1947. }
  1948. } else {
  1949. //
  1950. // Not enough memory to do a full MCA event so lets just do a
  1951. // generic one
  1952. //
  1953. PIO_ERROR_LOG_PACKET ErrLog;
  1954. ErrLog = IoAllocateErrorLogEntry(WmipServiceDeviceObject,
  1955. sizeof(IO_ERROR_LOG_PACKET));
  1956. if (ErrLog != NULL) {
  1957. //
  1958. // Fill it in and write it out as a single string.
  1959. //
  1960. ErrLog->ErrorCode = IsFatal ? MCA_WARNING_UNKNOWN_NO_CPU :
  1961. MCA_ERROR_UNKNOWN_NO_CPU;
  1962. ErrLog->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  1963. ErrLog->StringOffset = 0;
  1964. ErrLog->NumberOfStrings = 0;
  1965. IoWriteErrorLogEntry(ErrLog);
  1966. }
  1967. }
  1968. }
  1969. //
  1970. // Check if WBEM is already running and if not check if we've already
  1971. // kicked off the timer that will wait for wbem to start
  1972. //
  1973. #define WmipIsWbemRunning() ((WmipIsWbemRunningFlag == WBEM_IS_RUNNING) ? \
  1974. TRUE : \
  1975. FALSE)
  1976. NTSTATUS WmipWriteMCAEventLogEvent(
  1977. PUCHAR Event
  1978. )
  1979. {
  1980. PWNODE_HEADER Wnode = (PWNODE_HEADER)Event;
  1981. NTSTATUS Status;
  1982. PAGED_CODE();
  1983. WmipEnterSMCritSection();
  1984. if (WmipIsWbemRunning() ||
  1985. WmipCheckIsWbemRunning())
  1986. {
  1987. //
  1988. // We know WBEM is running so we can just fire off our event
  1989. //
  1990. WmipLeaveSMCritSection();
  1991. Status = IoWMIWriteEvent(Event);
  1992. } else {
  1993. //
  1994. // WBEM is not currently running and so startup a timer that
  1995. // will keep polling it
  1996. //
  1997. if (WmipIsWbemRunningFlag == WBEM_STATUS_UNKNOWN)
  1998. {
  1999. //
  2000. // No one has kicked off the waiting process for wbem so we
  2001. // do that here. Note we need to maintain the critical
  2002. // section to guard angainst another thread that might be
  2003. // trying to startup the waiting process as well. Note that
  2004. // if the setup fails we want to stay in the unknown state
  2005. // so that the next time an event is fired we can retry
  2006. // waiting for wbem
  2007. //
  2008. Status = WmipSetupWaitForWbem();
  2009. if (NT_SUCCESS(Status))
  2010. {
  2011. WmipIsWbemRunningFlag = WAITING_FOR_WBEM;
  2012. }
  2013. }
  2014. Wnode->ClientContext = Wnode->BufferSize;
  2015. InsertTailList(&WmipWaitingMCAEvents,
  2016. (PLIST_ENTRY)Event);
  2017. WmipLeaveSMCritSection();
  2018. Status = STATUS_SUCCESS;
  2019. }
  2020. return(Status);
  2021. }
  2022. ULONG WmipWbemMinuteWait = 1;
  2023. NTSTATUS WmipSetupWaitForWbem(
  2024. void
  2025. )
  2026. {
  2027. LARGE_INTEGER TimeOut;
  2028. NTSTATUS Status;
  2029. PAGED_CODE();
  2030. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  2031. "WMI: SetupWaitForWbem starting\n"));
  2032. //
  2033. // Initialize a kernel time to fire periodically so we can
  2034. // check if WBEM has started or not
  2035. //
  2036. KeInitializeTimer(&WmipIsWbemRunningTimer);
  2037. KeInitializeDpc(&WmipIsWbemRunningDpc,
  2038. WmipIsWbemRunningDispatch,
  2039. NULL);
  2040. ExInitializeWorkItem(&WmipIsWbemRunningWorkItem,
  2041. WmipIsWbemRunningWorker,
  2042. NULL);
  2043. TimeOut.HighPart = -1;
  2044. TimeOut.LowPart = -1 * (WmipWbemMinuteWait * 60 * 1000 * 10000); // 1 minutes
  2045. KeSetTimer(&WmipIsWbemRunningTimer,
  2046. TimeOut,
  2047. &WmipIsWbemRunningDpc);
  2048. Status = STATUS_SUCCESS;
  2049. return(Status);
  2050. }
  2051. void WmipIsWbemRunningDispatch(
  2052. IN PKDPC Dpc,
  2053. IN PVOID DeferredContext, // Not Used
  2054. IN PVOID SystemArgument1, // Not Used
  2055. IN PVOID SystemArgument2 // Not Used
  2056. )
  2057. {
  2058. ExQueueWorkItem(&WmipIsWbemRunningWorkItem,
  2059. DelayedWorkQueue);
  2060. }
  2061. void WmipIsWbemRunningWorker(
  2062. PVOID Context
  2063. )
  2064. {
  2065. LARGE_INTEGER TimeOut;
  2066. PAGED_CODE();
  2067. if (! WmipCheckIsWbemRunning())
  2068. {
  2069. //
  2070. // WBEM is not yet started, so timeout in another minute to
  2071. // check again
  2072. //
  2073. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  2074. "WMI: IsWbemRunningWorker starting -> WBEM not started\n"));
  2075. TimeOut.HighPart = -1;
  2076. TimeOut.LowPart = -1 * (1 *60 *1000 *10000); // 1 minutes
  2077. KeSetTimer(&WmipIsWbemRunningTimer,
  2078. TimeOut,
  2079. &WmipIsWbemRunningDpc);
  2080. } else {
  2081. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  2082. "WMI: WbemRunningWorker found wbem started\n"));
  2083. }
  2084. }
  2085. BOOLEAN WmipCheckIsWbemRunning(
  2086. void
  2087. )
  2088. {
  2089. OBJECT_ATTRIBUTES Obj;
  2090. UNICODE_STRING Name;
  2091. HANDLE Handle;
  2092. LARGE_INTEGER TimeOut;
  2093. BOOLEAN IsWbemRunning = FALSE;
  2094. NTSTATUS Status;
  2095. PWNODE_HEADER Wnode;
  2096. PAGED_CODE();
  2097. RtlInitUnicodeString(&Name,
  2098. L"\\BaseNamedObjects\\WBEM_ESS_OPEN_FOR_BUSINESS");
  2099. InitializeObjectAttributes(
  2100. &Obj,
  2101. &Name,
  2102. FALSE,
  2103. NULL,
  2104. NULL
  2105. );
  2106. Status = ZwOpenEvent(
  2107. &Handle,
  2108. SYNCHRONIZE,
  2109. &Obj
  2110. );
  2111. if (NT_SUCCESS(Status))
  2112. {
  2113. TimeOut.QuadPart = 0;
  2114. Status = ZwWaitForSingleObject(Handle,
  2115. FALSE,
  2116. &TimeOut);
  2117. if (Status == STATUS_SUCCESS)
  2118. {
  2119. IsWbemRunning = TRUE;
  2120. //
  2121. // We've determined that WBEM is running so now lets see if
  2122. // another thread has made that dermination as well. If not
  2123. // then we can flush the MCA event queue and set the flag
  2124. // that WBEM is running
  2125. //
  2126. WmipEnterSMCritSection();
  2127. if (WmipIsWbemRunningFlag != WBEM_IS_RUNNING)
  2128. {
  2129. //
  2130. // Flush the list of all MCA events waiting to be fired
  2131. //
  2132. while (! IsListEmpty(&WmipWaitingMCAEvents))
  2133. {
  2134. Wnode = (PWNODE_HEADER)RemoveHeadList(&WmipWaitingMCAEvents);
  2135. WmipLeaveSMCritSection();
  2136. Wnode->BufferSize = Wnode->ClientContext;
  2137. Wnode->Linkage = 0;
  2138. Status = IoWMIWriteEvent(Wnode);
  2139. if (! NT_SUCCESS(Status))
  2140. {
  2141. ExFreePool(Wnode);
  2142. }
  2143. WmipEnterSMCritSection();
  2144. }
  2145. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  2146. "WMI: WBEM is Running and queus flushed\n"));
  2147. WmipIsWbemRunningFlag = WBEM_IS_RUNNING;
  2148. }
  2149. WmipLeaveSMCritSection();
  2150. }
  2151. ZwClose(Handle);
  2152. }
  2153. return(IsWbemRunning);
  2154. }
  2155. #ifdef GENERATE_MCA
  2156. NTSTATUS WmipGenerateMCE(
  2157. IN ULONG Id
  2158. )
  2159. {
  2160. UCHAR buffer[sizeof(KERNEL_ERROR_HANDLER_INFO) + sizeof(GUID)];
  2161. PKERNEL_ERROR_HANDLER_INFO kernelInfo;
  2162. LPGUID guid;
  2163. NTSTATUS status;
  2164. RtlZeroMemory(buffer, sizeof(buffer));
  2165. kernelInfo = (PKERNEL_ERROR_HANDLER_INFO)buffer;
  2166. guid = (LPGUID)((PUCHAR)buffer + sizeof(KERNEL_ERROR_HANDLER_INFO));
  2167. kernelInfo->Version = KERNEL_ERROR_HANDLER_VERSION;
  2168. kernelInfo->Padding = Id;
  2169. *guid = WmipGenerateMCEGuid;
  2170. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_MCA_LEVEL,
  2171. "WMI: Generating MCE type %x\n", Id));
  2172. status = HalSetSystemInformation(HalKernelErrorHandler,
  2173. sizeof(buffer),
  2174. buffer);
  2175. return(status);
  2176. }
  2177. #ifdef MCE_INSERTION
  2178. typedef struct
  2179. {
  2180. LIST_ENTRY List;
  2181. ULONG LogSize;
  2182. UCHAR Log[1];
  2183. } BUFFERED_LOG, *PBUFFERED_LOG;
  2184. NTSTATUS WmipInsertMce(
  2185. PMCEQUERYINFO QueryInfo,
  2186. ULONG LogSize,
  2187. PUCHAR Log
  2188. )
  2189. {
  2190. PBUFFERED_LOG BufferedLog;
  2191. PLIST_ENTRY LogList;
  2192. NTSTATUS Status;
  2193. KIRQL OldIrql;
  2194. ULONG SizeNeeded;
  2195. SizeNeeded = FIELD_OFFSET(BUFFERED_LOG, Log) + LogSize;
  2196. BufferedLog = ExAllocatePoolWithTag(PagedPool,
  2197. SizeNeeded,
  2198. 'zimW');
  2199. if (BufferedLog != NULL)
  2200. {
  2201. RtlCopyMemory(BufferedLog->Log, Log, LogSize);
  2202. BufferedLog->LogSize = LogSize;
  2203. WmipEnterSMCritSection();
  2204. InsertTailList(&QueryInfo->LogHead, &BufferedLog->List);
  2205. WmipLeaveSMCritSection();
  2206. if (QueryInfo->PollCounter == HAL_CPE_INTERRUPTS_BASED)
  2207. {
  2208. KeRaiseIrql(CLOCK_LEVEL, &OldIrql);
  2209. switch(QueryInfo->InfoClass)
  2210. {
  2211. case HalMcaLogInformation:
  2212. {
  2213. WmipMcaDelivery(0, 0);
  2214. break;
  2215. }
  2216. case HalCmcLogInformation:
  2217. {
  2218. WmipCmcDelivery(0, 0);
  2219. break;
  2220. }
  2221. case HalCpeLogInformation:
  2222. {
  2223. WmipCpeDelivery(0, 0);
  2224. break;
  2225. }
  2226. }
  2227. KeLowerIrql(OldIrql);
  2228. }
  2229. Status = STATUS_SUCCESS;
  2230. } else {
  2231. Status = STATUS_INSUFFICIENT_RESOURCES;
  2232. }
  2233. return(Status);
  2234. }
  2235. NTSTATUS WmipRemoveMce(
  2236. PMCEQUERYINFO QueryInfo,
  2237. PUCHAR Log,
  2238. PULONG LogSize
  2239. )
  2240. {
  2241. NTSTATUS Status;
  2242. PBUFFERED_LOG BufferedLog;
  2243. PLIST_ENTRY LogList;
  2244. WmipEnterSMCritSection();
  2245. if (! IsListEmpty(&QueryInfo->LogHead))
  2246. {
  2247. LogList = RemoveHeadList(&QueryInfo->LogHead);
  2248. BufferedLog = (PBUFFERED_LOG)CONTAINING_RECORD(LogList,
  2249. BUFFERED_LOG,
  2250. List);
  2251. if (*LogSize < BufferedLog->LogSize)
  2252. {
  2253. InsertHeadList(&QueryInfo->LogHead,
  2254. LogList);
  2255. *LogSize = BufferedLog->LogSize;
  2256. WmipLeaveSMCritSection();
  2257. Status = STATUS_BUFFER_TOO_SMALL;
  2258. } else {
  2259. WmipLeaveSMCritSection();
  2260. RtlCopyMemory(Log, BufferedLog->Log, BufferedLog->LogSize);
  2261. *LogSize = BufferedLog->LogSize;
  2262. ExFreePool(BufferedLog);
  2263. Status = STATUS_SUCCESS;
  2264. }
  2265. } else {
  2266. WmipLeaveSMCritSection();
  2267. Status = STATUS_UNSUCCESSFUL;
  2268. }
  2269. return(Status);
  2270. }
  2271. NTSTATUS WmipQuerySystemInformation(
  2272. IN HAL_QUERY_INFORMATION_CLASS InformationClass,
  2273. IN ULONG BufferSize,
  2274. IN OUT PVOID Buffer,
  2275. OUT PULONG ReturnedLength
  2276. )
  2277. {
  2278. PMCEQUERYINFO QueryInfo;
  2279. NTSTATUS Status;
  2280. ULONG Size;
  2281. switch(InformationClass)
  2282. {
  2283. case HalMcaLogInformation:
  2284. {
  2285. QueryInfo = &WmipMcaQueryInfo;
  2286. break;
  2287. }
  2288. case HalCmcLogInformation:
  2289. {
  2290. QueryInfo = &WmipCmcQueryInfo;
  2291. break;
  2292. }
  2293. case HalCpeLogInformation:
  2294. {
  2295. QueryInfo = &WmipCpeQueryInfo;
  2296. break;
  2297. }
  2298. default:
  2299. {
  2300. WmipAssert(FALSE);
  2301. return(STATUS_INVALID_PARAMETER);
  2302. }
  2303. }
  2304. Size = BufferSize;
  2305. Status = WmipRemoveMce(QueryInfo,
  2306. Buffer,
  2307. &Size);
  2308. *ReturnedLength = Size;
  2309. return(Status);
  2310. }
  2311. #endif
  2312. #endif
  2313. #endif