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.

2028 lines
58 KiB

  1. /*++
  2. Module Name:
  3. ixmca.c
  4. Abstract:
  5. HAL component of the Machine Check Architecture.
  6. All exported MCA functionality is present in this file.
  7. Author:
  8. Srikanth Kambhatla (Intel)
  9. Revision History:
  10. Anil Aggarwal (Intel)
  11. Changes incorporated as per design review with Microsoft
  12. --*/
  13. #include <bugcodes.h>
  14. #include <halp.h>
  15. #include "check.h"
  16. #include "osmca.h"
  17. //
  18. // Default MCA Bank configuration
  19. //
  20. #define MCA_DEFAULT_BANK_CONF 0xFFFFFFFFFFFFFFFF
  21. //
  22. // Bogus define for -1 sal status return
  23. // to get around the bugcheck on bad status
  24. //
  25. #define SAL_STATUS_BOGUS_RETURN -1I64
  26. //
  27. // MCA architecture related defines
  28. //
  29. #define MCA_NUM_REGS 4
  30. #define MCA_CNT_MASK 0xFF
  31. #define MCG_CTL_PRESENT 0x100
  32. #define MCE_VALID 0x01
  33. //
  34. // MSR register addresses for MCA
  35. //
  36. #define MCG_CAP 0x179
  37. #define MCG_STATUS 0x17a
  38. #define MCG_CTL 0x17b
  39. #define MC0_CTL 0x400
  40. #define MC0_STATUS 0x401
  41. #define MC0_ADDR 0x402
  42. #define MC0_MISC 0x403
  43. #define PENTIUM_MC_ADDR 0x0
  44. #define PENTIUM_MC_TYPE 0x1
  45. //
  46. // Writing all 1's to MCG_CTL register enables logging.
  47. //
  48. #define MCA_MCGCTL_ENABLE_LOGGING 0xffffffff
  49. //
  50. // Bit interpretation of MCG_STATUS register
  51. //
  52. #define MCG_MC_INPROGRESS 0x4
  53. #define MCG_EIP_VALID 0x2
  54. #define MCG_RESTART_EIP_VALID 0x1
  55. //
  56. // For the function that reads the error reporting bank log, the type of error we
  57. // are interested in
  58. //
  59. #define MCA_GET_ANY_ERROR 0x1
  60. #define MCA_GET_NONRESTARTABLE_ERROR 0x2
  61. //
  62. // Defines for the size of TSS and the initial stack to operate on
  63. //
  64. #define MINIMUM_TSS_SIZE 0x68
  65. #if DBG
  66. //
  67. // If we use DbgPrint, we need bigger stack
  68. //
  69. #define MCA_EXCEPTION_STACK_SIZE 0x1000
  70. #else
  71. #define MCA_EXCEPTION_STACK_SIZE 0x100
  72. #endif // DBG
  73. //
  74. // Global Variables
  75. //
  76. extern KAFFINITY HalpActiveProcessors;
  77. // pmdata.c: CPE definitions.
  78. extern ULONG HalpMaxCPEImplemented;
  79. extern UCHAR MsgCMCPending[];
  80. extern UCHAR MsgCPEPending[];
  81. extern WCHAR rgzSessionManager[];
  82. extern WCHAR rgzEnableMCA[];
  83. extern WCHAR rgzEnableCMC[];
  84. extern WCHAR rgzEnableCPE[];
  85. extern WCHAR rgzNoMCABugCheck[];
  86. extern WCHAR rgzEnableMCEOemDrivers[];
  87. extern WCHAR rgzCMCThresholdCount[];
  88. extern WCHAR rgzCMCThresholdTime[];
  89. extern WCHAR rgzCPEThresholdCount[];
  90. extern WCHAR rgzCPEThresholdTime[];
  91. //
  92. // Internal prototypes
  93. //
  94. NTSTATUS
  95. HalpMcaReadProcessorException (
  96. OUT PMCA_EXCEPTION Exception,
  97. IN BOOLEAN NonRestartableOnly
  98. );
  99. VOID
  100. HalpMcaGetConfiguration (
  101. OUT PULONG MCAEnabled,
  102. OUT PULONG CMCEnabled,
  103. OUT PULONG CPEEnabled,
  104. OUT PULONG NoMCABugCheck,
  105. OUT PULONG MCEOemDriversEnabled,
  106. OUT PULONG CMCThresholdCount,
  107. OUT PULONG CMCThresholdTime,
  108. OUT PULONG CPEThresholdCount,
  109. OUT PULONG CPEThresholdTime
  110. );
  111. #define IsMceKernelQuery( _buffer ) \
  112. ( (((ULONG_PTR)(*((PULONG_PTR)Buffer))) == (ULONG_PTR)HALP_KERNEL_TOKEN) ? TRUE : FALSE )
  113. #ifdef ALLOC_PRAGMA
  114. #pragma alloc_text(INIT, HalpMcaInit)
  115. #pragma alloc_text(INIT, HalpMcaGetConfiguration)
  116. #endif
  117. VOID
  118. HalpMcaInit (
  119. VOID
  120. )
  121. /*++
  122. Routine Description:
  123. This routine is called to do the initialization of the HAL private
  124. IA64 ERROR management. Called at end of phase 1 from HalReportResourceUsage().
  125. Arguments:
  126. None
  127. Return Value:
  128. None
  129. --*/
  130. {
  131. ULONG MCAEnabled, CMCEnabled, CPEEnabled, NoMCABugCheck, MCEOemDriversEnabled;
  132. ULONG CMCThresholdCount, CMCThresholdTime;
  133. ULONG CPEThresholdCount, CPEThresholdTime;
  134. LARGE_INTEGER TicksPerSecond;
  135. C_ASSERT( HALP_CMC_MINIMUM_POLLING_INTERVAL > 1 );
  136. C_ASSERT( HALP_CPE_MINIMUM_POLLING_INTERVAL > 1 );
  137. //
  138. // If the default HAL features do not support IA64 Errors handling -
  139. // defined as the inclusion of MCA, CMC, CPE handling - we return immediately.
  140. //
  141. if ( (!(HalpFeatureBits & HAL_MCA_PRESENT)) &&
  142. (!(HalpFeatureBits & HAL_CMC_PRESENT)) &&
  143. (!(HalpFeatureBits & HAL_CPE_PRESENT)) ) {
  144. return;
  145. }
  146. //
  147. // Gather regisry settings for IA64 Errors handling.
  148. //
  149. HalpMcaGetConfiguration( &MCAEnabled, &CMCEnabled, &CPEEnabled,
  150. &NoMCABugCheck, &MCEOemDriversEnabled,
  151. &CMCThresholdCount, &CMCThresholdTime,
  152. &CPEThresholdCount, &CPEThresholdTime);
  153. //
  154. //
  155. //
  156. if ( HalpFeatureBits & HAL_MCA_PRESENT ) {
  157. if ( !MCAEnabled ) {
  158. //
  159. // Registry setting has disabled MCA handling.
  160. //
  161. // Thierry 08/00: We ignore this registry setting.
  162. //
  163. HalDebugPrint(( HAL_INFO, "HAL: MCA handling is disabled via registry.\n" ));
  164. HalDebugPrint(( HAL_INFO, "HAL: Disabling MCA handling is ignored currently...\n" ));
  165. }
  166. if ( NoMCABugCheck ) {
  167. //
  168. // Flag HalpMcaInfo, so HalpMcaBugCheck will not call KeBugCheckEx().
  169. //
  170. HalpMcaInfo.NoBugCheck++;
  171. }
  172. //
  173. // Execute other required MCA initialization here...
  174. //
  175. }
  176. else {
  177. HalDebugPrint(( HAL_INFO, "HAL: MCA handling is disabled.\n" ));
  178. }
  179. //
  180. // At this time of the HAL initialization, the default HAL CMC model is initialized as:
  181. // - non-present if SAL reported invalid CMC max log sizes.
  182. // - present & interrupt-based if SAL reported valid CMC max log sizes.
  183. //
  184. KeQueryPerformanceCounter(&TicksPerSecond);
  185. if ( HalpFeatureBits & HAL_CMC_PRESENT ) {
  186. if ( CMCEnabled ) {
  187. if ( (CMCEnabled == HAL_CMC_INTERRUPTS_BASED) || (CMCEnabled == (ULONG)1) ) {
  188. //
  189. // In this case, we do not change the default HAL CMC handling.
  190. //
  191. if (CMCThresholdCount == 1)
  192. {
  193. //
  194. // At a minimum we need to track receiving 2 in a row.
  195. //
  196. CMCThresholdCount = 2;
  197. }
  198. HalpCmcInfo.ThresholdMaximum = CMCThresholdCount;
  199. //
  200. // ThresholdTime is in units of 100ns (1ns = 10-9 sec)
  201. //
  202. HalpCmcInfo.ThresholdTime.QuadPart = (CMCThresholdTime *
  203. TicksPerSecond.QuadPart);
  204. }
  205. else {
  206. //
  207. // Registry setting enables CMC Polling mode.
  208. // Polling interval is registry specified value with mininum value
  209. // checked with HAL_CMC_MINIMUM_POLLING_INTERVAL.
  210. //
  211. if ( CMCEnabled < HALP_CMC_MINIMUM_POLLING_INTERVAL ) {
  212. CMCEnabled = HALP_CMC_MINIMUM_POLLING_INTERVAL;
  213. }
  214. HalDebugPrint(( HAL_INFO, "HAL: CMC Polling mode enabled via registry.\n" ));
  215. HalpCMCDisableForAllProcessors();
  216. HalpCmcInfo.Stats.PollingInterval = CMCEnabled;
  217. }
  218. }
  219. else {
  220. //
  221. // Registry setting has disabled CMC handling.
  222. //
  223. HalDebugPrint(( HAL_INFO, "HAL: CMC handling is disabled via registry.\n" ));
  224. HalpCMCDisableForAllProcessors();
  225. HalpFeatureBits &= ~HAL_CMC_PRESENT;
  226. }
  227. //
  228. // Execute other required CMC initialization here...
  229. //
  230. }
  231. else {
  232. HalDebugPrint(( HAL_INFO, "HAL: CMC handling is disabled.\n" ));
  233. }
  234. //
  235. // At this time of the HAL initialization, the default HAL CPE model is initialized as:
  236. // - non-present if SAL reported invalid CPE max log sizes.
  237. // - present & interrupt-based if SAPIC Platform Interrupt Sources exist.
  238. // - present & polled-based if there is no SAPIC Platform Interrupt Source.
  239. // Polling interval is: HALP_CPE_DEFAULT_POLLING_INTERVAL.
  240. //
  241. if ( HalpFeatureBits & HAL_CPE_PRESENT ) {
  242. if ( CPEEnabled ) {
  243. if ( (CPEEnabled == HAL_CPE_INTERRUPTS_BASED) || (CPEEnabled == (ULONG)1) ) {
  244. //
  245. // In this case, we do not change the default HAL CPE handling.
  246. //
  247. if ( HalpMaxCPEImplemented == 0 ) {
  248. HalDebugPrint(( HAL_INFO, "HAL: registry setting enabling CPE interrupt mode but no platform interrupt sources.\n" ));
  249. } else {
  250. if (CPEThresholdCount == 1)
  251. {
  252. //
  253. // At a minimum we need to track receiving 2 in a row
  254. //
  255. CPEThresholdCount = 2;
  256. }
  257. HalpCpeInfo.ThresholdMaximum = CPEThresholdCount;
  258. //
  259. // ThresholdTime is in units of 100ns (1ns = 10-9 sec)
  260. //
  261. HalpCpeInfo.ThresholdTime.QuadPart = (CPEThresholdTime *
  262. TicksPerSecond.QuadPart);
  263. }
  264. }
  265. else {
  266. //
  267. // Registry setting enables CPE Polling mode.
  268. // Polling interval is registry specified value with mininum value
  269. // checked with HAL_CPE_MINIMUM_POLLING_INTERVAL.
  270. //
  271. if ( CPEEnabled < HALP_CPE_MINIMUM_POLLING_INTERVAL ) {
  272. CPEEnabled = HALP_CPE_MINIMUM_POLLING_INTERVAL;
  273. }
  274. HalDebugPrint(( HAL_INFO, "HAL: CPE Polling mode enabled via registry.\n" ));
  275. HalpCPEDisable();
  276. HalpCpeInfo.Stats.PollingInterval = CPEEnabled;
  277. }
  278. }
  279. else {
  280. //
  281. // Registry setting has disabled CPE handling.
  282. //
  283. HalDebugPrint(( HAL_INFO, "HAL: CPE handling is disabled via registry.\n" ));
  284. HalpCPEDisable();
  285. HalpFeatureBits &= ~HAL_CPE_PRESENT;
  286. HalpCpeInfo.Stats.PollingInterval = HAL_CPE_DISABLED;
  287. }
  288. //
  289. // Execute other required CPE initialization here...
  290. //
  291. }
  292. else {
  293. HalDebugPrint(( HAL_INFO, "HAL: CPE handling is disabled.\n" ));
  294. }
  295. //
  296. // 06/09/01: OEM MCE Drivers registration is disabled by default in the HAL and
  297. // should be enabled using the registry. See HalpMcaGetConfiguration().
  298. // This was decided by the MS IA64 MCA Product Manager for Windows XP,
  299. // after consideration of the IA64 platforms FWs and little testing done
  300. // on this path.
  301. //
  302. if ( MCEOemDriversEnabled ) {
  303. HalpFeatureBits |= HAL_MCE_OEMDRIVERS_ENABLED;
  304. HalDebugPrint(( HAL_INFO, "HAL: OEM MCE Drivers registration enabled via registry.\n" ));
  305. }
  306. //
  307. // Initialize HALP_INFO required members.
  308. // This is done regardless of the enabled set of features.
  309. //
  310. HalpInitializeMceMutex();
  311. HalpInitializeMcaInfo();
  312. HalpInitializeInitMutex();
  313. HalpInitializeCmcInfo();
  314. HalpInitializeCpeInfo();
  315. return;
  316. } // HalpMcaInit()
  317. NTSTATUS
  318. HalpMceRegisterKernelDriver(
  319. IN PKERNEL_ERROR_HANDLER_INFO DriverInfo,
  320. IN ULONG InfoSize
  321. )
  322. /*++
  323. Routine Description:
  324. This routine is called by the kernel (via HalSetSystemInformation)
  325. to register its presence. This is mostly for WMI callbacks registration.
  326. Arguments:
  327. DriverInfo: Contains kernel info about the callbacks and associated objects.
  328. Return Value:
  329. Unless a MCA driver is already registered OR one of the two callback
  330. routines are NULL, this routine returns Success.
  331. Implementation Notes:
  332. - the current implementation assumes the kernel registers its callbacks
  333. earlier than a driver will. The current kernel registration is done by
  334. WMI and should be done at WMI-Phase 0.
  335. - the registrations do not consider if the HAL supports or not the MCA,CMC,CPE
  336. functionalities. It simply registers the callbacks if no other callback was
  337. registered before. This allows us to allow some flexibility if a machine event
  338. functionality is enabled AFTER the hal initialization (e.g. HalpGetFeatureBits())
  339. through the mean of a registry key or driver event, for example.
  340. --*/
  341. {
  342. NTSTATUS status;
  343. NTSTATUS statusMcaRegistration;
  344. NTSTATUS statusCmcRegistration;
  345. NTSTATUS statusCpeRegistration;
  346. PAGED_CODE();
  347. if ( !DriverInfo ) {
  348. status = STATUS_INVALID_PARAMETER;
  349. return status;
  350. }
  351. //
  352. // Backward compatibility only.
  353. //
  354. if ( DriverInfo->Version && (DriverInfo->Version > KERNEL_ERROR_HANDLER_VERSION) ) {
  355. status = STATUS_REVISION_MISMATCH;
  356. return status;
  357. }
  358. statusMcaRegistration = statusCmcRegistration = statusCpeRegistration = STATUS_UNSUCCESSFUL;
  359. //
  360. // Acquire HAL-wide mutex for MCA/CMC/CPE operations.
  361. //
  362. //
  363. // Register Kernel MCA notification.
  364. //
  365. HalpAcquireMcaMutex();
  366. if ( !HalpMcaInfo.KernelDelivery ) {
  367. HalpMcaInfo.KernelDelivery = DriverInfo->KernelMcaDelivery;
  368. statusMcaRegistration = STATUS_SUCCESS;
  369. }
  370. HalpReleaseMcaMutex();
  371. //
  372. // Register Kernel CMC notification.
  373. //
  374. HalpAcquireCmcMutex();
  375. if ( !HalpCmcInfo.KernelDelivery ) {
  376. HalpCmcInfo.KernelDelivery = DriverInfo->KernelCmcDelivery;
  377. statusCmcRegistration = STATUS_SUCCESS;
  378. }
  379. HalpReleaseCmcMutex();
  380. //
  381. // Register Kernel CPE notification.
  382. //
  383. HalpAcquireCpeMutex();
  384. if ( !HalpCpeInfo.KernelDelivery ) {
  385. HalpCpeInfo.KernelDelivery = DriverInfo->KernelCpeDelivery;
  386. statusCpeRegistration = STATUS_SUCCESS;
  387. }
  388. HalpReleaseCpeMutex();
  389. //
  390. // Register Kernel MCE notification.
  391. //
  392. HalpAcquireMceMutex();
  393. if ( !HalpMceKernelDelivery ) {
  394. HalpMceKernelDelivery = DriverInfo->KernelMceDelivery;
  395. }
  396. HalpReleaseMceMutex();
  397. //
  398. // If Kernel-WMI MCA registration was sucessful and we have Previous logs, notify the
  399. // Kernel-WMI component before returning.
  400. //
  401. if ( (statusMcaRegistration == STATUS_SUCCESS) && HalpMcaInfo.Stats.McaPreviousCount ) {
  402. InterlockedExchange( &HalpMcaInfo.DpcNotification, 1 );
  403. }
  404. //
  405. // return status determined by the success of the different registrations.
  406. //
  407. // Note: the 'OR'ing is valid because STATUS_SUCCESS and STATUS_UNSUCCESSFUL are only used.
  408. //
  409. status = (NTSTATUS)(statusMcaRegistration | statusCmcRegistration | statusCpeRegistration);
  410. return status;
  411. } // HalpMceRegisterKernelDriver()
  412. NTSTATUS
  413. HalpMcaRegisterDriver(
  414. IN PMCA_DRIVER_INFO DriverInfo
  415. )
  416. /*++
  417. Routine Description:
  418. This routine is called by the driver (via HalSetSystemInformation)
  419. to register its presence. Only one driver can be registered at a time.
  420. Arguments:
  421. DriverInfo: Contains info about the callback routine and the DeviceObject
  422. Return Value:
  423. Unless a MCA driver is already registered OR one of the two callback
  424. routines are NULL, this routine returns Success.
  425. --*/
  426. {
  427. NTSTATUS status;
  428. PAGED_CODE();
  429. status = STATUS_UNSUCCESSFUL;
  430. if ( (HalpFeatureBits & (HAL_MCE_OEMDRIVERS_ENABLED | HAL_MCA_PRESENT)) !=
  431. (HAL_MCE_OEMDRIVERS_ENABLED | HAL_MCA_PRESENT) ) {
  432. return STATUS_UNSUCCESSFUL;
  433. }
  434. if (DriverInfo->DpcCallback != NULL) {
  435. HalpAcquireMcaMutex();
  436. //
  437. // Register driver
  438. //
  439. if ( !HalpMcaInfo.DriverInfo.DpcCallback ) {
  440. //
  441. // Initialize the DPC object
  442. //
  443. KeInitializeDpc(
  444. &HalpMcaInfo.DriverDpc,
  445. DriverInfo->DpcCallback,
  446. DriverInfo->DeviceContext
  447. );
  448. //
  449. // register driver
  450. //
  451. HalpMcaInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
  452. HalpMcaInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
  453. HalpMcaInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
  454. status = STATUS_SUCCESS;
  455. }
  456. HalpReleaseMcaMutex();
  457. }
  458. else {
  459. //
  460. // Deregistring the callbacks is the only allowed operation.
  461. //
  462. HalpAcquireMcaMutex();
  463. if (HalpMcaInfo.DriverInfo.DeviceContext == DriverInfo->DeviceContext) {
  464. HalpMcaInfo.DriverInfo.ExceptionCallback = NULL;
  465. HalpMcaInfo.DriverInfo.DpcCallback = NULL;
  466. HalpMcaInfo.DriverInfo.DeviceContext = NULL;
  467. status = STATUS_SUCCESS;
  468. }
  469. HalpReleaseMcaMutex();
  470. }
  471. return status;
  472. } // HalpMcaRegisterDriver()
  473. NTSTATUS
  474. HalpCmcRegisterDriver(
  475. IN PCMC_DRIVER_INFO DriverInfo
  476. )
  477. /*++
  478. Routine Description:
  479. This routine is called by the driver (via HalSetSystemInformation)
  480. to register its presence. Only one driver can be registered at a time.
  481. Arguments:
  482. DriverInfo: Contains info about the callback routine and the DeviceObject
  483. Return Value:
  484. Unless a MCA driver is already registered OR one of the two callback
  485. routines are NULL, this routine returns Success.
  486. --*/
  487. {
  488. NTSTATUS status;
  489. PAGED_CODE();
  490. status = STATUS_UNSUCCESSFUL;
  491. if ( (HalpFeatureBits & (HAL_MCE_OEMDRIVERS_ENABLED | HAL_CMC_PRESENT)) !=
  492. (HAL_MCE_OEMDRIVERS_ENABLED | HAL_CMC_PRESENT) ) {
  493. return STATUS_UNSUCCESSFUL;
  494. }
  495. if (DriverInfo->DpcCallback != NULL) {
  496. HalpAcquireCmcMutex();
  497. //
  498. // Register driver
  499. //
  500. if ( !HalpCmcInfo.DriverInfo.DpcCallback ) {
  501. //
  502. // Initialize the DPC object
  503. //
  504. KeInitializeDpc(
  505. &HalpCmcInfo.DriverDpc,
  506. DriverInfo->DpcCallback,
  507. DriverInfo->DeviceContext
  508. );
  509. //
  510. // register driver
  511. //
  512. HalpCmcInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
  513. HalpCmcInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
  514. HalpCmcInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
  515. status = STATUS_SUCCESS;
  516. }
  517. HalpReleaseCmcMutex();
  518. } else {
  519. //
  520. // Deregistring the callbacks is the only allowed operation.
  521. //
  522. HalpAcquireCmcMutex();
  523. if (HalpCmcInfo.DriverInfo.DeviceContext == DriverInfo->DeviceContext) {
  524. HalpCmcInfo.DriverInfo.ExceptionCallback = NULL;
  525. HalpCmcInfo.DriverInfo.DpcCallback = NULL;
  526. HalpCmcInfo.DriverInfo.DeviceContext = NULL;
  527. status = STATUS_SUCCESS;
  528. }
  529. HalpReleaseCmcMutex();
  530. }
  531. return status;
  532. } // HalpCmcRegisterDriver()
  533. NTSTATUS
  534. HalpCpeRegisterDriver(
  535. IN PCPE_DRIVER_INFO DriverInfo
  536. )
  537. /*++
  538. Routine Description:
  539. This routine is called by the driver (via HalSetSystemInformation)
  540. to register its presence. Only one driver can be registered at a time.
  541. Arguments:
  542. DriverInfo: Contains info about the callback routine and the DeviceObject
  543. Return Value:
  544. Unless a MCA driver is already registered OR one of the two callback
  545. routines are NULL, this routine returns Success.
  546. --*/
  547. {
  548. NTSTATUS status;
  549. PAGED_CODE();
  550. status = STATUS_UNSUCCESSFUL;
  551. if ( (HalpFeatureBits & (HAL_MCE_OEMDRIVERS_ENABLED | HAL_CPE_PRESENT)) !=
  552. (HAL_MCE_OEMDRIVERS_ENABLED | HAL_CPE_PRESENT) ) {
  553. return STATUS_UNSUCCESSFUL;
  554. }
  555. if (DriverInfo->DpcCallback != NULL) {
  556. HalpAcquireCpeMutex();
  557. //
  558. // Register driver
  559. //
  560. if ( !HalpCpeInfo.DriverInfo.DpcCallback ) {
  561. //
  562. // Initialize the DPC object
  563. //
  564. KeInitializeDpc(
  565. &HalpCpeInfo.DriverDpc,
  566. DriverInfo->DpcCallback,
  567. DriverInfo->DeviceContext
  568. );
  569. //
  570. // register driver
  571. //
  572. HalpCpeInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
  573. HalpCpeInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
  574. HalpCpeInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
  575. status = STATUS_SUCCESS;
  576. }
  577. HalpReleaseCpeMutex();
  578. } else {
  579. //
  580. // Deregistring the callbacks is the only allowed operation.
  581. //
  582. HalpAcquireCpeMutex();
  583. if (HalpCpeInfo.DriverInfo.DeviceContext == DriverInfo->DeviceContext) {
  584. HalpCpeInfo.DriverInfo.ExceptionCallback = NULL;
  585. HalpCpeInfo.DriverInfo.DpcCallback = NULL;
  586. HalpCpeInfo.DriverInfo.DeviceContext = NULL;
  587. status = STATUS_SUCCESS;
  588. }
  589. HalpReleaseCpeMutex();
  590. }
  591. return status;
  592. } // HalpCpeRegisterDriver()
  593. VOID
  594. HalpSaveMceLog(
  595. IN PHALP_MCELOGS_HEADER LogsHeader,
  596. IN PERROR_RECORD_HEADER Record,
  597. IN ULONG RecordLength
  598. )
  599. {
  600. PSINGLE_LIST_ENTRY entry, previousEntry;
  601. PERROR_RECORD_HEADER savedLog;
  602. if ( LogsHeader->Count >= LogsHeader->MaxCount ) {
  603. LogsHeader->Overflow++;
  604. return;
  605. }
  606. entry = ExAllocatePoolWithTag( PagedPool, RecordLength + sizeof(*entry), LogsHeader->Tag );
  607. if ( !entry ) {
  608. LogsHeader->AllocateFails++;
  609. return;
  610. }
  611. entry->Next = NULL;
  612. previousEntry = &LogsHeader->Logs;
  613. while( previousEntry->Next != NULL ) {
  614. previousEntry = previousEntry->Next;
  615. }
  616. previousEntry->Next = entry;
  617. savedLog = HalpMceLogFromListEntry( entry );
  618. RtlCopyMemory( savedLog, Record, RecordLength );
  619. LogsHeader->Count++;
  620. return;
  621. } // HalpSaveMceLog()
  622. PSINGLE_LIST_ENTRY
  623. HalpGetSavedMceLog(
  624. PHALP_MCELOGS_HEADER LogsHeader,
  625. PSINGLE_LIST_ENTRY *LastEntry
  626. )
  627. {
  628. PSINGLE_LIST_ENTRY entry, previousEntry;
  629. ASSERTMSG( "HAL!HalpGetSavedMceLog: LogsHeader->Count = 0!\n", LogsHeader->Count );
  630. entry = NULL;
  631. *LastEntry = previousEntry = &LogsHeader->Logs;
  632. while( previousEntry->Next ) {
  633. entry = previousEntry;
  634. previousEntry = previousEntry->Next;
  635. }
  636. if ( entry ) {
  637. *LastEntry = entry;
  638. return( previousEntry );
  639. }
  640. return( NULL );
  641. } // HalpGetSavedMceLog()
  642. NTSTATUS
  643. HalpGetFwMceLog(
  644. ULONG MceType,
  645. PERROR_RECORD_HEADER Record,
  646. PHALP_MCELOGS_STATS MceLogsStats,
  647. BOOLEAN DoClearLog
  648. )
  649. {
  650. NTSTATUS status;
  651. SAL_PAL_RETURN_VALUES rv;
  652. LONGLONG salStatus;
  653. PERROR_RECORD_HEADER log;
  654. //
  655. // Get the currently pending Machine Check Event log.
  656. //
  657. log = Record;
  658. rv = HalpGetStateInfo( MceType, log );
  659. salStatus = rv.ReturnValues[0];
  660. if ( salStatus < 0 ) {
  661. //
  662. // SAL_GET_STATE_INFO failed.
  663. //
  664. if ( salStatus == SAL_STATUS_NO_INFORMATION_AVAILABLE || salStatus == SAL_STATUS_BOGUS_RETURN) {
  665. return ( STATUS_NOT_FOUND );
  666. }
  667. MceLogsStats->GetStateFails++;
  668. if ( HalpMceKernelDelivery ) {
  669. HalpMceKernelDelivery(
  670. HalpMceDeliveryArgument1( KERNEL_MCE_OPERATION_GET_STATE_INFO, MceType ),
  671. MceNotification,
  672. (PVOID)(ULONG_PTR)salStatus );
  673. }
  674. return( STATUS_UNSUCCESSFUL );
  675. }
  676. status = STATUS_SUCCESS;
  677. if ( DoClearLog ) {
  678. static ULONGLONG currentClearedLogCount = 0UI64;
  679. rv = HalpClearStateInfo( MceType );
  680. salStatus = rv.ReturnValues[0];
  681. if ( salStatus < 0 ) {
  682. //
  683. // SAL_CLEAR_STATE_INFO failed.
  684. //
  685. // We do not modify the status of the log collection. It is still sucessful.
  686. //
  687. if ( MceType == MCA_EVENT ) {
  688. //
  689. // Current consideration for this implementation - 08/2000:
  690. // if clearing the MCA log event fails, we assume that FW has a real
  691. // problem; Continuing will be dangerous. We bugcheck.
  692. //
  693. HalpMcaKeBugCheckEx( HAL_BUGCHECK_MCA_CLEAR_STATEINFO, (PMCA_EXCEPTION)log,
  694. HalpMcaInfo.Stats.MaxLogSize,
  695. salStatus );
  696. // no-return
  697. }
  698. else {
  699. //
  700. // The SAL CLEAR_STATE_INFO interface failed.
  701. // However, we consider that for this event type, it is not worth bugchecking
  702. // the system. We clearly flag it and notify the kernel-WMI if the callback was
  703. // registered.
  704. //
  705. MceLogsStats->ClearStateFails++;
  706. if ( HalpMceKernelDelivery ) {
  707. HalpMceKernelDelivery(
  708. HalpMceDeliveryArgument1( KERNEL_MCE_OPERATION_CLEAR_STATE_INFO, MceType ),
  709. MceNotification,
  710. (PVOID)(ULONG_PTR)salStatus );
  711. }
  712. }
  713. }
  714. else if ( salStatus == SAL_STATUS_SUCCESS_MORE_RECORDS ) {
  715. status = STATUS_MORE_ENTRIES;
  716. }
  717. //
  718. // We are saving the record id. This is a unique monotically increasing ID.
  719. // This is mostly to check that we are not getting the same log because of
  720. // SAL_CLEAR_STATE_INFO failure. Note that we have tried to clear it again.
  721. //
  722. if ( currentClearedLogCount && (log->Id == MceLogsStats->LogId) ) {
  723. status = STATUS_ALREADY_COMMITTED;
  724. }
  725. MceLogsStats->LogId = log->Id;
  726. currentClearedLogCount++;
  727. }
  728. //
  729. // Last sanity check on the record. This is to help the log saving processing and the
  730. // detection of invalid records.
  731. //
  732. if ( log->Length < sizeof(*log) ) { // includes Length == 0.
  733. status = STATUS_BAD_DESCRIPTOR_FORMAT;
  734. }
  735. return( status );
  736. } // HalpGetFwMceLog()
  737. NTSTATUS
  738. HalpGetMcaLog (
  739. OUT PMCA_EXCEPTION Buffer,
  740. IN ULONG BufferSize,
  741. OUT PULONG ReturnedLength
  742. )
  743. /*++
  744. Routine Description:
  745. This function is called by HaliQuerySysteminformation for the HalMcaLogInformation class.
  746. It provides a MCA log to the caller.
  747. Arguments:
  748. Buffer : Buffer into which the error is reported
  749. BufferSize : Size of the passed buffer
  750. ReturnedLength: Length of the log.
  751. Return Value:
  752. Success or failure
  753. --*/
  754. {
  755. ULONG maxLogSize;
  756. BOOLEAN kernelQuery;
  757. KAFFINITY activeProcessors, currentAffinity;
  758. NTSTATUS status;
  759. PERROR_RECORD_HEADER log;
  760. PHALP_MCELOGS_HEADER logsHeader;
  761. PAGED_CODE();
  762. //
  763. // If MCA is not enabled, return immediately.
  764. //
  765. if ( !(HalpFeatureBits & HAL_MCA_PRESENT) ) {
  766. return( STATUS_NO_SUCH_DEVICE );
  767. }
  768. //
  769. // Assertions for the HAL MCA implementation.
  770. //
  771. ASSERTMSG( "HAL!HalpGetMcaLog: ReturnedLength NULL!\n", ReturnedLength );
  772. ASSERTMSG( "HAL!HalpGetMcaLog: HalpMcaInfo.MaxLogSize 0!\n", HalpMcaInfo.Stats.MaxLogSize );
  773. ASSERTMSG( "HAL!HalpGetMcaLog: HalpMcaInfo.MaxLogSize < sizeof(ERROR_RECORD_HEADER)!\n",
  774. HalpMcaInfo.Stats.MaxLogSize >= sizeof(ERROR_RECORD_HEADER) );
  775. //
  776. // Let's the caller know about its passed buffer size or the minimum required size.
  777. //
  778. maxLogSize = HalpMcaInfo.Stats.MaxLogSize;
  779. if ( BufferSize < maxLogSize ) {
  780. *ReturnedLength = maxLogSize;
  781. return( STATUS_INVALID_BUFFER_SIZE );
  782. }
  783. //
  784. // Determine if the caller is the kernel-WMI.
  785. //
  786. kernelQuery = IsMceKernelQuery( Buffer );
  787. logsHeader = ( kernelQuery ) ? &HalpMcaInfo.KernelLogs : &HalpMcaInfo.DriverLogs;
  788. //
  789. // Enable MP protection for MCA logs accesses
  790. //
  791. status = STATUS_NOT_FOUND;
  792. HalpAcquireMcaMutex();
  793. //
  794. // If saved logs exist, pop an entry.
  795. //
  796. if ( logsHeader->Count ) {
  797. PSINGLE_LIST_ENTRY entry, lastEntry;
  798. entry = HalpGetSavedMceLog( logsHeader, &lastEntry );
  799. if ( entry ) {
  800. PERROR_RECORD_HEADER savedLog;
  801. ULONG length;
  802. savedLog = HalpMceLogFromListEntry( entry );
  803. length = savedLog->Length;
  804. if ( length <= BufferSize ) {
  805. ULONG logsCount;
  806. RtlCopyMemory( Buffer, savedLog, length );
  807. ExFreePoolWithTag( entry, logsHeader->Tag );
  808. lastEntry->Next = NULL;
  809. logsCount = (--logsHeader->Count);
  810. HalpReleaseMcaMutex();
  811. *ReturnedLength = length;
  812. if ( logsCount ) {
  813. return( STATUS_MORE_ENTRIES );
  814. }
  815. else {
  816. return( STATUS_SUCCESS );
  817. }
  818. }
  819. else {
  820. HalpReleaseMcaMutex();
  821. *ReturnedLength = length;
  822. return( STATUS_INVALID_BUFFER_SIZE );
  823. }
  824. }
  825. }
  826. //
  827. // Initalize local log pointer after memory allocation if required.
  828. //
  829. if ( kernelQuery ) {
  830. log = (PERROR_RECORD_HEADER)Buffer;
  831. }
  832. else {
  833. //
  834. // The OEM CMC driver HAL interface does not require the CMC driver memory
  835. // for the log buffer to be allocated from NonPagedPool.
  836. // Also, MM does not export memory pool type checking APIs.
  837. // It is safer to allocate in NonPagedPool and pass this buffer to the SAL.
  838. // If the SAL interface is sucessful, we will copy the buffer to the caller's buffer.
  839. //
  840. log = ExAllocatePoolWithTag( NonPagedPool, maxLogSize, 'TacM' );
  841. if ( log == NULL ) {
  842. HalpReleaseMcaMutex();
  843. return( STATUS_NO_MEMORY );
  844. }
  845. }
  846. //
  847. // We did not have any saved log, check if we have notified that FW has logs from
  848. // previous MCAs or corrected MCAs.
  849. //
  850. activeProcessors = HalpActiveProcessors;
  851. for (currentAffinity = 1; activeProcessors; currentAffinity <<= 1) {
  852. if (activeProcessors & currentAffinity) {
  853. activeProcessors &= ~currentAffinity;
  854. KeSetSystemAffinityThread(currentAffinity);
  855. status = HalpGetFwMceLog( MCA_EVENT, log, &HalpMcaInfo.Stats, HALP_FWMCE_DO_CLEAR_LOG );
  856. if ( NT_SUCCESS( status ) ||
  857. ( (status != STATUS_NOT_FOUND) && (status != STATUS_ALREADY_COMMITTED) ) ) {
  858. break;
  859. }
  860. }
  861. }
  862. if ( NT_SUCCESS( status ) ) {
  863. ULONG length = log->Length; // Note: Length was checked in HalpGetMceLog().
  864. if ( kernelQuery ) {
  865. if ( HalpMcaInfo.DriverInfo.DpcCallback ) {
  866. HalpSaveMceLog( &HalpMcaInfo.DriverLogs, log, length );
  867. }
  868. }
  869. else {
  870. RtlCopyMemory( Buffer, log, length );
  871. if ( HalpMcaInfo.KernelDelivery ) {
  872. HalpSaveMceLog( &HalpMcaInfo.KernelLogs, log, length );
  873. }
  874. }
  875. *ReturnedLength = length;
  876. }
  877. //
  878. // Restore threads affinity, release mutex.
  879. //
  880. KeRevertToUserAffinityThread();
  881. HalpReleaseMcaMutex();
  882. //
  883. // If the caller is not the Kernel-WMI, free the allocated NonPagedPool log.
  884. //
  885. if ( !kernelQuery ) {
  886. ExFreePoolWithTag( log, 'TacM' );
  887. }
  888. return status;
  889. } // HalpGetMcaLog()
  890. NTSTATUS
  891. HalpGetCmcLog (
  892. OUT PCMC_EXCEPTION Buffer,
  893. IN ULONG BufferSize,
  894. OUT PULONG ReturnedLength
  895. )
  896. /*++
  897. Routine Description:
  898. This function is called by HaliQuerySysteminformation for the HalCmcLogInformation class.
  899. It provides a CMC log to the caller.
  900. Arguments:
  901. Buffer : Buffer into which the error is reported
  902. BufferSize : Size of the passed buffer
  903. ReturnedLength: Length of the log. This pointer was validated by caller.
  904. Return Value:
  905. Success or failure
  906. --*/
  907. {
  908. ULONG maxLogSize;
  909. BOOLEAN kernelQuery;
  910. KAFFINITY activeProcessors, currentAffinity;
  911. NTSTATUS status;
  912. PERROR_RECORD_HEADER log;
  913. PHALP_MCELOGS_HEADER logsHeader;
  914. PAGED_CODE();
  915. //
  916. // If CMC is not enabled, return immediately.
  917. //
  918. if ( !(HalpFeatureBits & HAL_CMC_PRESENT) ) {
  919. return( STATUS_NO_SUCH_DEVICE );
  920. }
  921. //
  922. // Assertions for the HAL CMC implementation.
  923. //
  924. ASSERTMSG( "HAL!HalpGetCmcLog: ReturnedLength NULL!\n", ReturnedLength );
  925. ASSERTMSG( "HAL!HalpGetCmcLog: HalpCmcInfo.MaxLogSize 0!\n", HalpCmcInfo.Stats.MaxLogSize );
  926. ASSERTMSG( "HAL!HalpGetCmcLog: HalpCmcInfo.MaxLogSize < sizeof(ERROR_RECORD_HEADER)!\n",
  927. HalpCmcInfo.Stats.MaxLogSize >= sizeof(ERROR_RECORD_HEADER) );
  928. //
  929. // Let's the caller know about its passed buffer size or the minimum required size.
  930. //
  931. maxLogSize = HalpCmcInfo.Stats.MaxLogSize;
  932. if ( BufferSize < maxLogSize ) {
  933. *ReturnedLength = maxLogSize;
  934. return( STATUS_INVALID_BUFFER_SIZE );
  935. }
  936. //
  937. // Determine if the caller is the kernel-WMI.
  938. //
  939. kernelQuery = IsMceKernelQuery( Buffer );
  940. logsHeader = ( kernelQuery ) ? &HalpCmcInfo.KernelLogs : &HalpCmcInfo.DriverLogs;
  941. //
  942. // Enable MP protection for CMC logs accesses
  943. //
  944. status = STATUS_NOT_FOUND;
  945. HalpAcquireCmcMutex();
  946. //
  947. // If saved logs exist, pop an entry.
  948. //
  949. if ( logsHeader->Count ) {
  950. PSINGLE_LIST_ENTRY entry, lastEntry;
  951. entry = HalpGetSavedMceLog( logsHeader, &lastEntry );
  952. if ( entry ) {
  953. PERROR_RECORD_HEADER savedLog;
  954. ULONG length;
  955. savedLog = HalpMceLogFromListEntry( entry );
  956. length = savedLog->Length;
  957. if ( length <= BufferSize ) {
  958. ULONG logsCount;
  959. RtlCopyMemory( Buffer, savedLog, length );
  960. ExFreePoolWithTag( entry, logsHeader->Tag );
  961. lastEntry->Next = NULL;
  962. logsCount = (--logsHeader->Count);
  963. HalpReleaseCmcMutex();
  964. *ReturnedLength = length;
  965. if ( logsCount ) {
  966. return( STATUS_MORE_ENTRIES );
  967. }
  968. else {
  969. return( STATUS_SUCCESS );
  970. }
  971. }
  972. else {
  973. HalpReleaseCmcMutex();
  974. *ReturnedLength = length;
  975. return( STATUS_INVALID_BUFFER_SIZE );
  976. }
  977. }
  978. }
  979. //
  980. // Initalize local log pointer after memory allocation if required.
  981. //
  982. if ( kernelQuery ) {
  983. log = (PERROR_RECORD_HEADER)Buffer;
  984. }
  985. else {
  986. //
  987. // The OEM CMC driver HAL interface does not require the CMC driver memory
  988. // for the log buffer to be allocated from NonPagedPool.
  989. // Also, MM does not export memory pool type checking APIs.
  990. // It is safer to allocate in NonPagedPool and pass this buffer to the SAL.
  991. // If the SAL interface is sucessful, we will copy the buffer to the caller's buffer.
  992. //
  993. log = ExAllocatePoolWithTag( NonPagedPool, maxLogSize, 'TcmC' );
  994. if ( log == NULL ) {
  995. HalpReleaseCmcMutex();
  996. return( STATUS_NO_MEMORY );
  997. }
  998. }
  999. //
  1000. // We did not have any saved log, migrate from 1 processor to another to collect
  1001. // the FW logs.
  1002. //
  1003. activeProcessors = HalpActiveProcessors;
  1004. for (currentAffinity = 1; activeProcessors; currentAffinity <<= 1) {
  1005. if (activeProcessors & currentAffinity) {
  1006. activeProcessors &= ~currentAffinity;
  1007. KeSetSystemAffinityThread(currentAffinity);
  1008. status = HalpGetFwMceLog( CMC_EVENT, log, &HalpCmcInfo.Stats, HALP_FWMCE_DO_CLEAR_LOG );
  1009. if ( NT_SUCCESS( status ) ||
  1010. ( (status != STATUS_NOT_FOUND) && (status != STATUS_ALREADY_COMMITTED) ) ) {
  1011. break;
  1012. }
  1013. }
  1014. }
  1015. if ( NT_SUCCESS( status ) ) {
  1016. ULONG length = log->Length; // Note: Length was checked in HalpGetMceLog().
  1017. if ( kernelQuery ) {
  1018. if ( HalpCmcInfo.DriverInfo.DpcCallback ) {
  1019. HalpSaveMceLog( &HalpCmcInfo.DriverLogs, log, length );
  1020. }
  1021. }
  1022. else {
  1023. RtlCopyMemory( Buffer, log, length );
  1024. if ( HalpCmcInfo.KernelDelivery ) {
  1025. HalpSaveMceLog( &HalpCmcInfo.KernelLogs, log, length );
  1026. }
  1027. }
  1028. *ReturnedLength = length;
  1029. }
  1030. //
  1031. // Restore threads affinity, release mutex.
  1032. //
  1033. KeRevertToUserAffinityThread();
  1034. HalpReleaseCmcMutex();
  1035. //
  1036. // If the caller is not the Kernel-WMI, free the allocated NonPagedPool log.
  1037. //
  1038. if ( !kernelQuery ) {
  1039. ExFreePoolWithTag( log, 'TcmC' );
  1040. }
  1041. return status;
  1042. } // HalpGetCmcLog()
  1043. NTSTATUS
  1044. HalpGetCpeLog (
  1045. OUT PCPE_EXCEPTION Buffer,
  1046. IN ULONG BufferSize,
  1047. OUT PULONG ReturnedLength
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This function is called by HaliQuerySysteminformation for the HalCpeLogInformation class.
  1052. It provides a CPE log to the caller.
  1053. Arguments:
  1054. Buffer : Buffer into which the error is reported
  1055. BufferSize : Size of the passed buffer
  1056. ReturnedLength: Length of the log. This pointer was validated by caller.
  1057. Return Value:
  1058. Success or failure
  1059. --*/
  1060. {
  1061. ULONG maxLogSize;
  1062. BOOLEAN kernelQuery;
  1063. KAFFINITY activeProcessors, currentAffinity;
  1064. NTSTATUS status;
  1065. PERROR_RECORD_HEADER log;
  1066. PHALP_MCELOGS_HEADER logsHeader;
  1067. PAGED_CODE();
  1068. //
  1069. // If CPE is not enabled, return immediately.
  1070. //
  1071. if ( !(HalpFeatureBits & HAL_CPE_PRESENT) ) {
  1072. return( STATUS_NO_SUCH_DEVICE );
  1073. }
  1074. //
  1075. // Assertions for the HAL CPE implementation.
  1076. //
  1077. ASSERTMSG( "HAL!HalpGetCpeLog: ReturnedLength NULL!\n", ReturnedLength );
  1078. ASSERTMSG( "HAL!HalpGetCpeLog: HalpCpeInfo.MaxLogSize 0!\n", HalpCpeInfo.Stats.MaxLogSize );
  1079. ASSERTMSG( "HAL!HalpGetCpeLog: HalpCpeInfo.MaxLogSize < sizeof(ERROR_RECORD_HEADER)!\n",
  1080. HalpCpeInfo.Stats.MaxLogSize >= sizeof(ERROR_RECORD_HEADER) );
  1081. //
  1082. // Let's the caller know about its passed buffer size or the minimum required size.
  1083. //
  1084. maxLogSize = HalpCpeInfo.Stats.MaxLogSize;
  1085. if ( BufferSize < maxLogSize ) {
  1086. *ReturnedLength = maxLogSize;
  1087. return( STATUS_INVALID_BUFFER_SIZE );
  1088. }
  1089. //
  1090. // Determine if the caller is the kernel-WMI.
  1091. //
  1092. kernelQuery = IsMceKernelQuery( Buffer );
  1093. logsHeader = ( kernelQuery ) ? &HalpCpeInfo.KernelLogs : &HalpCpeInfo.DriverLogs;
  1094. //
  1095. // Enable MP protection for CPE logs accesses
  1096. //
  1097. status = STATUS_NOT_FOUND;
  1098. HalpAcquireCpeMutex();
  1099. //
  1100. // If saved logs exist, pop an entry.
  1101. //
  1102. if ( logsHeader->Count ) {
  1103. PSINGLE_LIST_ENTRY entry, lastEntry;
  1104. entry = HalpGetSavedMceLog( logsHeader, &lastEntry );
  1105. if ( entry ) {
  1106. PERROR_RECORD_HEADER savedLog;
  1107. ULONG length;
  1108. savedLog = HalpMceLogFromListEntry( entry );
  1109. length = savedLog->Length;
  1110. if ( length <= BufferSize ) {
  1111. ULONG logsCount;
  1112. RtlCopyMemory( Buffer, savedLog, length );
  1113. ExFreePoolWithTag( entry, logsHeader->Tag );
  1114. lastEntry->Next = NULL;
  1115. logsCount = (--logsHeader->Count);
  1116. HalpReleaseCpeMutex();
  1117. *ReturnedLength = length;
  1118. if ( logsCount ) {
  1119. return( STATUS_MORE_ENTRIES );
  1120. }
  1121. else {
  1122. return( STATUS_SUCCESS );
  1123. }
  1124. }
  1125. else {
  1126. HalpReleaseCpeMutex();
  1127. *ReturnedLength = length;
  1128. return( STATUS_INVALID_BUFFER_SIZE );
  1129. }
  1130. }
  1131. }
  1132. //
  1133. // Initalize local log pointer after memory allocation if required.
  1134. //
  1135. if ( kernelQuery ) {
  1136. log = (PERROR_RECORD_HEADER)Buffer;
  1137. }
  1138. else {
  1139. //
  1140. // The OEM CPE driver HAL interface does not require the CPE driver memory
  1141. // for the log buffer to be allocated from NonPagedPool.
  1142. // Also, MM does not export memory pool type checking APIs.
  1143. // It is safer to allocate in NonPagedPool and pass this buffer to the SAL.
  1144. // If the SAL interface is sucessful, we will copy the buffer to the caller's buffer.
  1145. //
  1146. log = ExAllocatePoolWithTag( NonPagedPool, maxLogSize, 'TpeC' );
  1147. if ( log == NULL ) {
  1148. HalpReleaseCpeMutex();
  1149. return( STATUS_NO_MEMORY );
  1150. }
  1151. }
  1152. //
  1153. // We did not have any saved log, migrate from 1 processor to another to collect
  1154. // the FW logs.
  1155. //
  1156. activeProcessors = HalpActiveProcessors;
  1157. for (currentAffinity = 1; activeProcessors; currentAffinity <<= 1) {
  1158. if (activeProcessors & currentAffinity) {
  1159. activeProcessors &= ~currentAffinity;
  1160. KeSetSystemAffinityThread(currentAffinity);
  1161. status = HalpGetFwMceLog( CPE_EVENT, log, &HalpCpeInfo.Stats, HALP_FWMCE_DO_CLEAR_LOG );
  1162. if ( NT_SUCCESS( status ) ||
  1163. ( (status != STATUS_NOT_FOUND) && (status != STATUS_ALREADY_COMMITTED) ) ) {
  1164. break;
  1165. }
  1166. }
  1167. }
  1168. if ( NT_SUCCESS( status ) ) {
  1169. ULONG length = log->Length; // Note: Length was checked in HalpGetMceLog().
  1170. if ( kernelQuery ) {
  1171. if ( HalpCpeInfo.DriverInfo.DpcCallback ) {
  1172. HalpSaveMceLog( &HalpCpeInfo.DriverLogs, log, length );
  1173. }
  1174. }
  1175. else {
  1176. RtlCopyMemory( Buffer, log, length );
  1177. if ( HalpCpeInfo.KernelDelivery ) {
  1178. HalpSaveMceLog( &HalpCpeInfo.KernelLogs, log, length );
  1179. }
  1180. }
  1181. *ReturnedLength = length;
  1182. }
  1183. //
  1184. // Restore threads affinity, release mutex.
  1185. //
  1186. KeRevertToUserAffinityThread();
  1187. HalpReleaseCpeMutex();
  1188. //
  1189. // If the caller is not the Kernel-WMI, free the allocated NonPagedPool log.
  1190. //
  1191. if ( !kernelQuery ) {
  1192. ExFreePoolWithTag( log, 'TpeC' );
  1193. }
  1194. //
  1195. // We've retrieved a log from the SAL and cleared it. It should be safe
  1196. // to reenable CPE interrupts if we are in interrupt mode.
  1197. //
  1198. if (HalpCpeInfo.Stats.PollingInterval == HAL_CPE_INTERRUPTS_BASED) {
  1199. HalpCPEEnable();
  1200. }
  1201. return status;
  1202. } // HalpGetCpeLog()
  1203. VOID
  1204. HalpMcaGetConfiguration (
  1205. OUT PULONG MCAEnabled,
  1206. OUT PULONG CMCEnabled,
  1207. OUT PULONG CPEEnabled,
  1208. OUT PULONG NoMCABugCheck,
  1209. OUT PULONG MCEOemDriversEnabled,
  1210. OUT PULONG CMCThresholdCount,
  1211. OUT PULONG CMCThresholdTime,
  1212. OUT PULONG CPEThresholdCount,
  1213. OUT PULONG CPEThresholdTime
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. This routine returns the registry settings for the
  1218. the IA64 Error - MCA, CMC, CPE - configuration information.
  1219. Arguments:
  1220. MCAEnabled - Pointer to the MCAEnabled indicator.
  1221. 0 = False, 1 = True (1 if value not present in Registry).
  1222. CMCEnabled - Pointer to the CMCEnabled indicator.
  1223. 0 = HAL CMC Handling should be disabled.
  1224. Registry value was (present and set to 0) or was not present.
  1225. -1|1 = HAL CMC Interrupt-based mode. See Note 1/ below.
  1226. Other = HAL CMC Polling mode and value is user-specified polling interval.
  1227. CPEEnabled - Pointer to the CPEEnabled indicator.
  1228. 0 = HAL CPE Handling should be disabled.
  1229. Registry value was (present and set to 0) or was not present.
  1230. -1|1 = HAL CPE Interrupt-based mode. See Note 1/ below.
  1231. Other = HAL CPE Polling mode and value is user-specified polling interval.
  1232. NoMCABugCheck - Pointer to the MCA BugCheck indicator.
  1233. 0 = Fatal MCA HAL processing calls the KeBugCheckEx path.
  1234. 1 = Fatal MCA HAL processing does not call the KeBugCheckEx path.
  1235. The system stalls. This is useful for extreme error containment.
  1236. if not present = value is 0, e.g. HAL calls KeBugCheckEx for fatal MCA.
  1237. MCEOemDriversEnabled - Pointer to the MCEOemDriversEnabled indicator.
  1238. 0 = HAL OEM MCE Drivers registration is disabled.
  1239. 1 = HAL OEM MCE Drivers registration is enabled.
  1240. If not present = value is 0, e.g. registration is disabled.
  1241. CMCThresholdCount - Number of CMCs received within a time period
  1242. that will cause a switch from interrupt to
  1243. polled mode
  1244. CMCThresholdTime - Number of seconds within which CMCThresholdCount
  1245. CMCs need to be received before a switch to
  1246. polled mode.
  1247. CPEThresholdCount - Number of CPEs received within a time period
  1248. that will cause a switch from interrupt to
  1249. polled mode
  1250. CPEThresholdTime - Number of seconds within which CPEThresholdCount
  1251. CPEs need to be received before a switch to
  1252. polled mode.
  1253. Return Value:
  1254. None.
  1255. Notes:
  1256. 1/ HAL defines minimum values for polling intervals. These minima are defined > 1, as imposed
  1257. by the C_ASSERTs in HalpMcaInit().
  1258. --*/
  1259. {
  1260. RTL_QUERY_REGISTRY_TABLE parameters[10];
  1261. ULONG defaultDataCMC;
  1262. ULONG defaultDataMCA;
  1263. ULONG defaultDataCPE;
  1264. ULONG defaultNoMCABugCheck;
  1265. ULONG defaultMCEOemDriversEnabled;
  1266. ULONG defaultCMCThresholdTime;
  1267. ULONG defaultCMCThresholdCount;
  1268. ULONG defaultCPEThresholdTime;
  1269. ULONG defaultCPEThresholdCount;
  1270. RtlZeroMemory(parameters, sizeof(parameters));
  1271. defaultDataCMC = *CMCEnabled = 0;
  1272. defaultDataMCA = *MCAEnabled = TRUE;
  1273. defaultDataCPE = *CPEEnabled = 0;
  1274. defaultNoMCABugCheck = *NoMCABugCheck = FALSE;
  1275. defaultMCEOemDriversEnabled = FALSE; // 06/09/01: default chosen by MS IA64 MCA PM.
  1276. defaultCMCThresholdCount = 10; // 10 CMCs
  1277. defaultCMCThresholdTime = 60; // 60 Seconds
  1278. defaultCPEThresholdCount = 10; // 10 CPEs
  1279. defaultCPEThresholdTime = 60; // 60 Seconds
  1280. //
  1281. // Gather all of the "user specified" information from
  1282. // the registry.
  1283. //
  1284. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1285. parameters[0].Name = rgzEnableCMC;
  1286. parameters[0].EntryContext = CMCEnabled;
  1287. parameters[0].DefaultType = REG_DWORD;
  1288. parameters[0].DefaultData = &defaultDataCMC;
  1289. parameters[0].DefaultLength = sizeof(ULONG);
  1290. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1291. parameters[1].Name = rgzEnableMCA;
  1292. parameters[1].EntryContext = MCAEnabled;
  1293. parameters[1].DefaultType = REG_DWORD;
  1294. parameters[1].DefaultData = &defaultDataMCA;
  1295. parameters[1].DefaultLength = sizeof(ULONG);
  1296. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1297. parameters[2].Name = rgzEnableCPE;
  1298. parameters[2].EntryContext = CPEEnabled;
  1299. parameters[2].DefaultType = REG_DWORD;
  1300. parameters[2].DefaultData = &defaultDataCPE;
  1301. parameters[2].DefaultLength = sizeof(ULONG);
  1302. parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1303. parameters[3].Name = rgzNoMCABugCheck;
  1304. parameters[3].EntryContext = NoMCABugCheck;
  1305. parameters[3].DefaultType = REG_DWORD;
  1306. parameters[3].DefaultData = &defaultNoMCABugCheck;
  1307. parameters[3].DefaultLength = sizeof(ULONG);
  1308. parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1309. parameters[4].Name = rgzEnableMCEOemDrivers;
  1310. parameters[4].EntryContext = MCEOemDriversEnabled;
  1311. parameters[4].DefaultType = REG_DWORD;
  1312. parameters[4].DefaultData = &defaultMCEOemDriversEnabled;
  1313. parameters[4].DefaultLength = sizeof(ULONG);
  1314. parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1315. parameters[5].Name = rgzCMCThresholdTime;
  1316. parameters[5].EntryContext = CMCThresholdTime;
  1317. parameters[5].DefaultType = REG_DWORD;
  1318. parameters[5].DefaultData = &defaultCMCThresholdTime;
  1319. parameters[5].DefaultLength = sizeof(ULONG);
  1320. parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1321. parameters[6].Name = rgzCMCThresholdCount;
  1322. parameters[6].EntryContext = CMCThresholdCount;
  1323. parameters[6].DefaultType = REG_DWORD;
  1324. parameters[6].DefaultData = &defaultCMCThresholdCount;
  1325. parameters[6].DefaultLength = sizeof(ULONG);
  1326. parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1327. parameters[7].Name = rgzCPEThresholdTime;
  1328. parameters[7].EntryContext = CPEThresholdTime;
  1329. parameters[7].DefaultType = REG_DWORD;
  1330. parameters[7].DefaultData = &defaultCPEThresholdTime;
  1331. parameters[7].DefaultLength = sizeof(ULONG);
  1332. parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1333. parameters[8].Name = rgzCPEThresholdCount;
  1334. parameters[8].EntryContext = CPEThresholdCount;
  1335. parameters[8].DefaultType = REG_DWORD;
  1336. parameters[8].DefaultData = &defaultCPEThresholdCount;
  1337. parameters[8].DefaultLength = sizeof(ULONG);
  1338. RtlQueryRegistryValues(
  1339. RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
  1340. rgzSessionManager,
  1341. parameters,
  1342. NULL,
  1343. NULL
  1344. );
  1345. return;
  1346. } // HalpMcaGetConfiguration()
  1347. NTSTATUS
  1348. HalpSetMcaLog (
  1349. IN PMCA_EXCEPTION Buffer,
  1350. IN ULONG BufferSize
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. This function is called by HaliSetSysteminformation for the HalMcaLog class.
  1355. It stores the passed MCA record in the HAL.
  1356. This functionality was requested by the MS Test Team to validate the HAL/WMI/WMI consumer
  1357. path with "well-known" logs.
  1358. Arguments:
  1359. Buffer : supplies the MCA log.
  1360. BufferSize : supplies the MCA log size.
  1361. Return Value:
  1362. Success or failure
  1363. Implementation Notes:
  1364. As requested by the WMI and Test Teams, there is mininum HAL processing for the record
  1365. and no validation of the record contents.
  1366. --*/
  1367. {
  1368. ULONG maxLogSize;
  1369. BOOLEAN kernelQuery;
  1370. KAFFINITY activeProcessors, currentAffinity;
  1371. NTSTATUS status;
  1372. PERROR_RECORD_HEADER log;
  1373. PHALP_MCELOGS_HEADER logsHeader;
  1374. KIRQL oldIrql;
  1375. HALP_VALIDATE_LOW_IRQL()
  1376. //
  1377. // Check calling arguments.
  1378. //
  1379. if ( (Buffer == (PMCA_EXCEPTION)0) || (BufferSize == 0) ) {
  1380. return( STATUS_INVALID_PARAMETER );
  1381. }
  1382. //
  1383. // If MCA is not enabled, return immediately.
  1384. //
  1385. if ( !(HalpFeatureBits & HAL_MCA_PRESENT) ) {
  1386. return( STATUS_NO_SUCH_DEVICE );
  1387. }
  1388. //
  1389. // Enable MP protection for MCA logs accesses
  1390. //
  1391. HalpAcquireMcaMutex();
  1392. //
  1393. // Save log on Kernel and Drivers Logs if enabled.
  1394. //
  1395. if ( HalpMcaInfo.KernelDelivery ) {
  1396. HalpSaveMceLog( &HalpMcaInfo.KernelLogs, Buffer, BufferSize );
  1397. }
  1398. if ( HalpMcaInfo.DriverInfo.DpcCallback ) {
  1399. HalpSaveMceLog( &HalpMcaInfo.DriverLogs, Buffer, BufferSize );
  1400. }
  1401. //
  1402. // Let Kernel or OEM MCA driver know about it.
  1403. //
  1404. // There is no model other than INTERRUPTS_BASED for MCA at this date - 05/04/01.
  1405. //
  1406. if ( HalpMcaInfo.KernelDelivery || HalpMcaInfo.DriverInfo.DpcCallback ) {
  1407. InterlockedExchange( &HalpMcaInfo.DpcNotification, 1 );
  1408. }
  1409. //
  1410. // release mutex.
  1411. //
  1412. HalpReleaseMcaMutex();
  1413. return( STATUS_SUCCESS );
  1414. } // HalpSetMcaLog()
  1415. NTSTATUS
  1416. HalpSetCmcLog (
  1417. IN PCMC_EXCEPTION Buffer,
  1418. IN ULONG BufferSize
  1419. )
  1420. /*++
  1421. Routine Description:
  1422. This function is called by HaliSetSysteminformation for the HalCmcLog class.
  1423. It stores the passed CMC record in the HAL.
  1424. This functionality was requested by the MS Test Team to validate the HAL/WMI/WMI consumer
  1425. path with "well-known" logs.
  1426. Arguments:
  1427. Buffer : supplies the CMC log.
  1428. BufferSize : supplies the CMC log size.
  1429. Return Value:
  1430. Success or failure
  1431. Implementation Notes:
  1432. As requested by the WMI and Test Teams, there is mininum HAL processing for the record
  1433. and no validation of the record contents.
  1434. --*/
  1435. {
  1436. ULONG maxLogSize;
  1437. BOOLEAN kernelQuery;
  1438. KAFFINITY activeProcessors, currentAffinity;
  1439. NTSTATUS status;
  1440. PERROR_RECORD_HEADER log;
  1441. PHALP_MCELOGS_HEADER logsHeader;
  1442. KIRQL oldIrql;
  1443. HALP_VALIDATE_LOW_IRQL()
  1444. //
  1445. // Check calling arguments.
  1446. //
  1447. if ( (Buffer == (PCMC_EXCEPTION)0) || (BufferSize == 0) ) {
  1448. return( STATUS_INVALID_PARAMETER );
  1449. }
  1450. //
  1451. // If CMC is not enabled, return immediately.
  1452. //
  1453. if ( !(HalpFeatureBits & HAL_CMC_PRESENT) ) {
  1454. return( STATUS_NO_SUCH_DEVICE );
  1455. }
  1456. //
  1457. // Enable MP protection for CMC logs accesses
  1458. //
  1459. HalpAcquireCmcMutex();
  1460. //
  1461. // Save log on Kernel and Driver Logs if enabled.
  1462. //
  1463. if ( HalpCmcInfo.KernelDelivery ) {
  1464. HalpSaveMceLog( &HalpCmcInfo.KernelLogs, Buffer, BufferSize );
  1465. }
  1466. if ( HalpCmcInfo.DriverInfo.DpcCallback ) {
  1467. HalpSaveMceLog( &HalpCmcInfo.DriverLogs, Buffer, BufferSize );
  1468. }
  1469. //
  1470. // If Interrupt based mode, call directly second-level handler at CMCI level.
  1471. //
  1472. if ( HalpCmcInfo.Stats.PollingInterval == HAL_CMC_INTERRUPTS_BASED ) {
  1473. KeRaiseIrql(CMCI_LEVEL, &oldIrql);
  1474. HalpCmcHandler();
  1475. KeLowerIrql( oldIrql );
  1476. }
  1477. //
  1478. // release mutex.
  1479. //
  1480. HalpReleaseCmcMutex();
  1481. return( STATUS_SUCCESS );
  1482. } // HalpSetCmcLog()
  1483. NTSTATUS
  1484. HalpSetCpeLog (
  1485. IN PCPE_EXCEPTION Buffer,
  1486. IN ULONG BufferSize
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. This function is called by HaliSetSysteminformation for the HalCpeLog class.
  1491. It stores the passed CPE record in the HAL.
  1492. This functionality was requested by the MS Test Team to validate the HAL/WMI/WMI consumer
  1493. path with "well-known" logs.
  1494. Arguments:
  1495. Buffer : supplies the CPE log.
  1496. BufferSize : supplies the CPE log size.
  1497. Return Value:
  1498. Success or failure
  1499. Implementation Notes:
  1500. As requested by the WMI and Test Teams, there is mininum HAL processing for the record
  1501. and no validation of the record contents.
  1502. --*/
  1503. {
  1504. ULONG maxLogSize;
  1505. BOOLEAN kernelQuery;
  1506. KAFFINITY activeProcessors, currentAffinity;
  1507. NTSTATUS status;
  1508. PERROR_RECORD_HEADER log;
  1509. PHALP_MCELOGS_HEADER logsHeader;
  1510. KIRQL oldIrql;
  1511. HALP_VALIDATE_LOW_IRQL()
  1512. //
  1513. // Check calling arguments.
  1514. //
  1515. if ( (Buffer == (PCPE_EXCEPTION)0) || (BufferSize == 0) ) {
  1516. return( STATUS_INVALID_PARAMETER );
  1517. }
  1518. //
  1519. // If CPE is not enabled, return immediately.
  1520. //
  1521. if ( !(HalpFeatureBits & HAL_CPE_PRESENT) ) {
  1522. return( STATUS_NO_SUCH_DEVICE );
  1523. }
  1524. //
  1525. // Enable MP protection for CPE logs accesses
  1526. //
  1527. HalpAcquireCpeMutex();
  1528. //
  1529. // Save log on Kernel and Drivers Logs if enabled.
  1530. //
  1531. if ( HalpCpeInfo.KernelDelivery ) {
  1532. HalpSaveMceLog( &HalpCpeInfo.KernelLogs, Buffer, BufferSize );
  1533. }
  1534. if ( HalpCpeInfo.DriverInfo.DpcCallback ) {
  1535. HalpSaveMceLog( &HalpCpeInfo.DriverLogs, Buffer, BufferSize );
  1536. }
  1537. //
  1538. // If Interrupt based mode, call directly second-level handler at CPEI level.
  1539. //
  1540. if ( HalpCpeInfo.Stats.PollingInterval == HAL_CPE_INTERRUPTS_BASED ) {
  1541. KeRaiseIrql(CPEI_LEVEL, &oldIrql);
  1542. HalpCpeHandler();
  1543. KeLowerIrql( oldIrql );
  1544. }
  1545. //
  1546. // release mutex.
  1547. //
  1548. HalpReleaseCpeMutex();
  1549. return( STATUS_SUCCESS );
  1550. } // HalpSetCpeLog()