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.

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