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.

1278 lines
30 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 <stdlib.h>
  16. #include <stdio.h>
  17. #include <nthal.h>
  18. //
  19. // Structure to keep track of MCA features available on installed hardware
  20. //
  21. typedef struct _MCA_INFO {
  22. FAST_MUTEX Mutex;
  23. UCHAR NumBanks; // Number of Banks present
  24. ULONGLONG Bank0Config; // Bank0 configuration setup by BIOS.
  25. // This will be used as mask when
  26. // setting up bank 0
  27. MCA_DRIVER_INFO DriverInfo; // Info about registered driver
  28. KDPC Dpc; // DPC object for MCA
  29. } MCA_INFO, *PMCA_INFO;
  30. //
  31. // Default MCA Bank configuration
  32. //
  33. #define MCA_DEFAULT_BANK_CONF 0xFFFFFFFFFFFFFFFF
  34. //
  35. // MCA architecture related defines
  36. //
  37. #define MCA_NUM_REGS 4
  38. #define MCE_VALID 0x01
  39. #define MCA_VECTOR 18
  40. //
  41. // MSR register addresses for MCA
  42. //
  43. #define MCG_CAP 0x179
  44. #define MCG_STATUS 0x17a
  45. #define MCG_CTL 0x17b
  46. #define MCG_EAX 0x180
  47. #define MCG_EBX 0x181
  48. #define MCG_ECX 0x182
  49. #define MCG_EDX 0x183
  50. #define MCG_ESI 0x184
  51. #define MCG_EDI 0x185
  52. #define MCG_EBP 0x186
  53. #define MCG_ESP 0x187
  54. #define MCG_EFLAGS 0x188
  55. #define MCG_EIP 0x189
  56. #define MC0_CTL 0x400
  57. #define MC0_STATUS 0x401
  58. #define MC0_ADDR 0x402
  59. #define MC0_MISC 0x403
  60. #define PENTIUM_MC_ADDR 0x0
  61. #define PENTIUM_MC_TYPE 0x1
  62. //
  63. // Bit Masks for MCG_CAP
  64. //
  65. #define MCA_CNT_MASK 0xFF
  66. #define MCG_CTL_PRESENT 0x100
  67. #define MCG_EXT_PRESENT 0x200
  68. typedef struct _MCG_CAPABILITY {
  69. union {
  70. struct {
  71. ULONG McaCnt:8;
  72. ULONG McaCntlPresent:1;
  73. ULONG McaExtPresent:1;
  74. ULONG Reserved_1: 6;
  75. ULONG McaExtCnt: 8;
  76. ULONG Reserved_2: 8;
  77. ULONG Reserved_3;
  78. } hw;
  79. ULONGLONG QuadPart;
  80. } u;
  81. } MCG_CAPABILITY, *PMCG_CAPABILITY;
  82. //
  83. // V2 defines up through Eip
  84. //
  85. #define MCG_EFLAGS_OFFSET (MCG_EFLAGS-MCG_EAX+1)
  86. //
  87. // Writing all 1's to MCG_CTL register enables logging.
  88. //
  89. #define MCA_MCGCTL_ENABLE_LOGGING 0xffffffffffffffff
  90. //
  91. // Bit interpretation of MCG_STATUS register
  92. //
  93. #define MCG_MC_INPROGRESS 0x4
  94. #define MCG_EIP_VALID 0x2
  95. #define MCG_RESTART_EIP_VALID 0x1
  96. //
  97. // For the function that reads the error reporting bank log, the type of error we
  98. // are interested in
  99. //
  100. #define MCA_GET_ANY_ERROR 0x1
  101. #define MCA_GET_NONRESTARTABLE_ERROR 0x2
  102. //
  103. // Defines for the size of TSS and the initial stack to operate on
  104. //
  105. #define MINIMUM_TSS_SIZE 0x68
  106. //
  107. // Global Varibles
  108. //
  109. MCA_INFO HalpMcaInfo;
  110. BOOLEAN HalpMcaInterfaceLocked;
  111. extern KAFFINITY HalpActiveProcessors;
  112. #if !defined(_WIN64) || defined(PICACPI)
  113. extern UCHAR HalpClockMcaQueueDpc;
  114. #endif
  115. extern UCHAR MsgMCEPending[];
  116. extern WCHAR rgzSessionManager[];
  117. extern WCHAR rgzEnableMCE[];
  118. extern WCHAR rgzEnableMCA[];
  119. //
  120. // External prototypes
  121. //
  122. VOID
  123. HalpMcaCurrentProcessorSetTSS (
  124. IN PULONG pTSS
  125. );
  126. #if !defined(_AMD64_)
  127. VOID
  128. HalpSetCr4MCEBit (
  129. VOID
  130. );
  131. #endif // _AMD64_
  132. //
  133. // Internal prototypes
  134. //
  135. VOID
  136. HalpMcaInit (
  137. VOID
  138. );
  139. NTSTATUS
  140. HalpMcaReadProcessorException (
  141. IN OUT PMCA_EXCEPTION Exception,
  142. IN BOOLEAN NonRestartableOnly
  143. );
  144. VOID
  145. HalpMcaQueueDpc(
  146. VOID
  147. );
  148. VOID
  149. HalpMcaGetConfiguration (
  150. OUT PULONG MCEEnabled,
  151. OUT PULONG MCAEnabled
  152. );
  153. VOID
  154. HalpMcaLockInterface(
  155. VOID
  156. );
  157. VOID
  158. HalpMcaUnlockInterface(
  159. VOID
  160. );
  161. NTSTATUS
  162. HalpMcaReadRegisterInterface(
  163. IN UCHAR BankNumber,
  164. IN OUT PMCA_EXCEPTION Exception
  165. );
  166. #ifdef ALLOC_PRAGMA
  167. #pragma alloc_text(INIT, HalpMcaInit)
  168. #pragma alloc_text(PAGELK, HalpMcaCurrentProcessorSetConfig)
  169. #pragma alloc_text(INIT, HalpMcaGetConfiguration)
  170. #pragma alloc_text(PAGE, HalpGetMcaLog)
  171. #pragma alloc_text(PAGE, HalpMcaRegisterDriver)
  172. #pragma alloc_text(PAGE, HalpMcaLockInterface)
  173. #pragma alloc_text(PAGE, HalpMcaUnlockInterface)
  174. #endif
  175. //
  176. // Register names for registers starting at MCG_EAX
  177. //
  178. char *RegNames[] = {
  179. "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp", "eflags", "eip"
  180. };
  181. #define REGNAMECNT (sizeof(RegNames)/sizeof(RegNames[0]))
  182. VOID
  183. HalpMcaLockInterface(
  184. VOID
  185. )
  186. {
  187. ExAcquireFastMutex(&HalpMcaInfo.Mutex);
  188. #if DBG
  189. ASSERT(HalpMcaInterfaceLocked == FALSE);
  190. HalpMcaInterfaceLocked = TRUE;
  191. #endif
  192. }
  193. VOID
  194. HalpMcaUnlockInterface(
  195. VOID
  196. )
  197. {
  198. ExReleaseFastMutex(&HalpMcaInfo.Mutex);
  199. #if DBG
  200. ASSERT(HalpMcaInterfaceLocked == TRUE);
  201. HalpMcaInterfaceLocked = FALSE;
  202. #endif
  203. }
  204. //
  205. // All the initialization code for MCA goes here
  206. //
  207. VOID
  208. HalpMcaInit (
  209. VOID
  210. )
  211. /*++
  212. Routine Description:
  213. This routine is called to do all the initialization work
  214. Arguments:
  215. None
  216. Return Value:
  217. STATUS_SUCCESS if successful
  218. error status otherwise
  219. --*/
  220. {
  221. ULONGLONG MsrCapability;
  222. KIRQL OldIrql;
  223. KAFFINITY ActiveProcessors, CurrentAffinity;
  224. ULONGLONG MsrMceType;
  225. ULONG MCEEnabled;
  226. ULONG MCAEnabled;
  227. PULONG pTSS;
  228. //
  229. // This lock synchronises access to the log area when we call the
  230. // logger on multiple processors.
  231. //
  232. // Note: This must be initialized regardless of whether or not
  233. // this processor supports MCA.
  234. //
  235. ExInitializeFastMutex (&HalpMcaInfo.Mutex);
  236. //
  237. // If this processor does not support MCA, nothing more to do.
  238. //
  239. if ( (!(HalpFeatureBits & HAL_MCE_PRESENT)) &&
  240. (!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
  241. return; // nothing to do
  242. }
  243. HalpMcaGetConfiguration(&MCEEnabled, &MCAEnabled);
  244. if ( (HalpFeatureBits & HAL_MCE_PRESENT) &&
  245. (!(HalpFeatureBits & HAL_MCA_PRESENT)) ) {
  246. if (MCEEnabled == FALSE) {
  247. // User has not enabled MCE capability.
  248. HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
  249. return;
  250. }
  251. #if DBG
  252. DbgPrint("MCE feature is enabled via registry\n");
  253. #endif // DBG
  254. MsrMceType = RDMSR(PENTIUM_MC_TYPE);
  255. if (((PLARGE_INTEGER)(&MsrMceType))->LowPart & MCE_VALID) {
  256. //
  257. // On an AST PREMMIA MX machine we seem to have a Machine
  258. // Check Pending always.
  259. //
  260. HalDisplayString(MsgMCEPending);
  261. HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
  262. return;
  263. }
  264. }
  265. //
  266. // If MCA is available, find out the number of banks available and
  267. // also get the platform specific bank 0 configuration
  268. //
  269. if ( HalpFeatureBits & HAL_MCA_PRESENT ) {
  270. if (MCAEnabled == FALSE) {
  271. //
  272. // User has disabled MCA capability.
  273. //
  274. #if DBG
  275. DbgPrint("MCA feature is disabled via registry\n");
  276. #endif // DBG
  277. HalpFeatureBits &= ~(HAL_MCE_PRESENT | HAL_MCA_PRESENT);
  278. return;
  279. }
  280. MsrCapability = RDMSR(MCG_CAP);
  281. HalpMcaInfo.NumBanks = (UCHAR)(MsrCapability & MCA_CNT_MASK);
  282. //
  283. // Find out the Bank 0 configuration setup by BIOS. This will be used
  284. // as a mask when writing to Bank 0
  285. //
  286. HalpMcaInfo.Bank0Config = RDMSR(MC0_CTL);
  287. }
  288. ASSERT(HalpFeatureBits & HAL_MCE_PRESENT);
  289. //
  290. // Initialize on each processor
  291. //
  292. #if !defined(_AMD64_)
  293. ActiveProcessors = HalpActiveProcessors;
  294. for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
  295. if (ActiveProcessors & CurrentAffinity) {
  296. ActiveProcessors &= ~CurrentAffinity;
  297. KeSetSystemAffinityThread (CurrentAffinity);
  298. //
  299. // Initialize MCA support on this processor
  300. //
  301. //
  302. // Allocate memory for this processor's TSS and it's own
  303. // private stack
  304. //
  305. pTSS = (PULONG)ExAllocatePoolWithTag(NonPagedPool,
  306. MINIMUM_TSS_SIZE,
  307. HAL_POOL_TAG
  308. );
  309. if (!pTSS) {
  310. //
  311. // This allocation is critical.
  312. //
  313. KeBugCheckEx(HAL_MEMORY_ALLOCATION,
  314. MINIMUM_TSS_SIZE,
  315. 2,
  316. (ULONG_PTR)__FILE__,
  317. __LINE__
  318. );
  319. }
  320. RtlZeroMemory(pTSS, MINIMUM_TSS_SIZE);
  321. OldIrql = KfRaiseIrql(HIGH_LEVEL);
  322. HalpMcaCurrentProcessorSetTSS(pTSS);
  323. HalpMcaCurrentProcessorSetConfig();
  324. KeLowerIrql(OldIrql);
  325. }
  326. }
  327. #endif // _AMD64_
  328. //
  329. // Restore threads affinity
  330. //
  331. KeRevertToUserAffinityThread();
  332. }
  333. VOID
  334. HalpMcaCurrentProcessorSetConfig (
  335. VOID
  336. )
  337. /*++
  338. Routine Description:
  339. This routine sets/modifies the configuration of the machine check
  340. architecture on the current processor. Input is specification of
  341. the control register MCi_CTL for each bank of the MCA architecture.
  342. which controls the generation of machine check exceptions for errors
  343. logged to that bank.
  344. If MCA is not available on this processor, check if MCE is available.
  345. If so, enable MCE in CR4
  346. Arguments:
  347. Context: Array of values of MCi_CTL for each bank of MCA.
  348. If NULL, use MCA_DEFAULT_BANK_CONF values for each bank
  349. Return Value:
  350. None
  351. --*/
  352. {
  353. ULONGLONG MciCtl;
  354. ULONGLONG McgCap;
  355. ULONGLONG McgCtl;
  356. ULONG BankNum;
  357. if (HalpFeatureBits & HAL_MCA_PRESENT) {
  358. //
  359. // MCA is available. Initialize MCG_CTL register if present
  360. // Writing all 1's enable MCE or MCA Error Exceptions
  361. //
  362. McgCap = RDMSR(MCG_CAP);
  363. if (McgCap & MCG_CTL_PRESENT) {
  364. McgCtl = MCA_MCGCTL_ENABLE_LOGGING;
  365. WRMSR(MCG_CTL, McgCtl);
  366. }
  367. //
  368. // Enable all MCA errors
  369. //
  370. for ( BankNum = 0; BankNum < HalpMcaInfo.NumBanks; BankNum++ ) {
  371. //
  372. // Use MCA_DEFAULT_BANK_CONF for each bank
  373. //
  374. MciCtl = MCA_DEFAULT_BANK_CONF;
  375. //
  376. // If this is bank 0, use HalpMcaInfo.Bank0Config as a mask
  377. //
  378. if (BankNum == 0) {
  379. MciCtl &= HalpMcaInfo.Bank0Config;
  380. }
  381. WRMSR(MC0_CTL + (BankNum * MCA_NUM_REGS), MciCtl);
  382. }
  383. }
  384. //
  385. // Enable MCE bit in CR4
  386. //
  387. #if defined(_AMD64_)
  388. {
  389. ULONG64 cr4;
  390. cr4 = ReadCR4();
  391. cr4 |= CR4_MCE;
  392. WriteCR4(cr4);
  393. }
  394. #else
  395. HalpSetCr4MCEBit();
  396. #endif
  397. }
  398. NTSTATUS
  399. HalpMcaRegisterDriver(
  400. IN PMCA_DRIVER_INFO DriverInfo
  401. )
  402. /*++
  403. Routine Description:
  404. This routine is called by the driver (via HalSetSystemInformation)
  405. to register its presence. Only one driver can be registered at a time.
  406. Arguments:
  407. DriverInfo: Contains info about the callback routine and the DriverObject
  408. Return Value:
  409. Unless a MCA driver is already registered OR one of the two callback
  410. routines are NULL, this routine returns Success.
  411. --*/
  412. {
  413. KIRQL OldIrql;
  414. PVOID UnlockHandle;
  415. NTSTATUS Status;
  416. PAGED_CODE();
  417. Status = STATUS_UNSUCCESSFUL;
  418. if ((HalpFeatureBits & HAL_MCE_PRESENT) && DriverInfo->DpcCallback) {
  419. HalpMcaLockInterface();
  420. //
  421. // Register driver
  422. //
  423. if (!HalpMcaInfo.DriverInfo.DpcCallback) {
  424. // Initialize the DPC object
  425. KeInitializeDpc(
  426. &HalpMcaInfo.Dpc,
  427. DriverInfo->DpcCallback,
  428. DriverInfo->DeviceContext
  429. );
  430. // register driver
  431. HalpMcaInfo.DriverInfo.ExceptionCallback = DriverInfo->ExceptionCallback;
  432. HalpMcaInfo.DriverInfo.DpcCallback = DriverInfo->DpcCallback;
  433. HalpMcaInfo.DriverInfo.DeviceContext = DriverInfo->DeviceContext;
  434. Status = STATUS_SUCCESS;
  435. }
  436. HalpMcaUnlockInterface();
  437. } else if (!DriverInfo->DpcCallback) {
  438. HalpMcaLockInterface();
  439. // Only deregistering myself is permitted
  440. if (HalpMcaInfo.DriverInfo.DeviceContext == DriverInfo->DeviceContext) {
  441. HalpMcaInfo.DriverInfo.ExceptionCallback = NULL;
  442. HalpMcaInfo.DriverInfo.DpcCallback = NULL;
  443. HalpMcaInfo.DriverInfo.DeviceContext = NULL;
  444. Status = STATUS_SUCCESS;
  445. }
  446. HalpMcaUnlockInterface();
  447. }
  448. return Status;
  449. }
  450. #define MAX_MCA_NONFATAL_RETRIES 5
  451. #define MCA_NONFATAL_ERORRS_BEFORE_WBINVD 3
  452. NTSTATUS
  453. HalpGetMcaLog (
  454. IN OUT PMCA_EXCEPTION Exception,
  455. IN ULONG BufferSize,
  456. OUT PULONG Length
  457. )
  458. /*++
  459. Routine Description:
  460. This is the entry point for driver to read the bank logs
  461. Called by HaliQuerySystemInformation()
  462. Arguments:
  463. Exception: Buffer into which the error is reported
  464. BufferSize: Size of the passed buffer
  465. Length: of the result
  466. Return Value:
  467. Success or failure
  468. --*/
  469. {
  470. KAFFINITY ActiveProcessors, CurrentAffinity;
  471. NTSTATUS Status;
  472. ULONG p1, p2;
  473. ULONGLONG p3;
  474. static ULONG McaStatusCount = 0;
  475. static ULONG SavedBank = 0;
  476. static ULONGLONG SavedMcaStatus = 0;
  477. static KAFFINITY SavedAffinity = 0;
  478. PAGED_CODE();
  479. if (! (HalpFeatureBits & HAL_MCA_PRESENT)) {
  480. return(STATUS_NO_SUCH_DEVICE);
  481. }
  482. switch (BufferSize) {
  483. case MCA_EXCEPTION_V1_SIZE:
  484. Exception->VersionNumber = 1;
  485. break;
  486. case MCA_EXCEPTION_V2_SIZE:
  487. ASSERT(Exception->VersionNumber == 2);
  488. break;
  489. default:
  490. return(STATUS_INVALID_PARAMETER);
  491. }
  492. ActiveProcessors = HalpActiveProcessors;
  493. Status = STATUS_NOT_FOUND;
  494. HalpMcaLockInterface();
  495. *Length = 0;
  496. for (CurrentAffinity = 1; ActiveProcessors; CurrentAffinity <<= 1) {
  497. if (ActiveProcessors & CurrentAffinity) {
  498. ActiveProcessors &= ~CurrentAffinity;
  499. KeSetSystemAffinityThread (CurrentAffinity);
  500. //
  501. // Check this processor for an exception
  502. //
  503. Status = HalpMcaReadProcessorException (Exception, FALSE);
  504. //
  505. // Avoiding going into an infinite loop reporting a non-fatal
  506. // single bit MCA error. This can be the result of the same
  507. // error being generated repeatly by the hardware.
  508. //
  509. if (Status == STATUS_SUCCESS) {
  510. //
  511. // Check to see if the same processor is reporting the
  512. // same MCA status.
  513. //
  514. if ((CurrentAffinity == SavedAffinity) &&
  515. (SavedBank == Exception->u.Mca.BankNumber) &&
  516. (SavedMcaStatus == Exception->u.Mca.Status.QuadPart)) {
  517. //
  518. // Check to see if the same error is generated more than
  519. // n times. Currently n==5. If so, bugcheck the system.
  520. //
  521. if (McaStatusCount >= MAX_MCA_NONFATAL_RETRIES) {
  522. if (Exception->VersionNumber == 1) {
  523. //
  524. // Parameters for bugcheck
  525. //
  526. p1 = ((PLARGE_INTEGER)(&Exception->u.Mce.Type))->LowPart;
  527. p2 = 0;
  528. p3 = Exception->u.Mce.Address;
  529. } else {
  530. //
  531. // Parameters for bugcheck
  532. //
  533. p1 = Exception->u.Mca.BankNumber;
  534. p2 = Exception->u.Mca.Address.Address;
  535. p3 = Exception->u.Mca.Status.QuadPart;
  536. }
  537. //
  538. // We need a new bugcheck code for this case.
  539. //
  540. KeBugCheckEx (
  541. MACHINE_CHECK_EXCEPTION,
  542. p1,
  543. p2,
  544. ((PLARGE_INTEGER)(&p3))->HighPart,
  545. ((PLARGE_INTEGER)(&p3))->LowPart
  546. );
  547. } else {
  548. //
  549. // This error is seen more than 1 once. If it has
  550. // occurred more than
  551. // MCA_NONFATAL_ERORRS_BEFORE_WBINVD times, write
  552. // back and Invalid cache to see if the error can be
  553. // cleared.
  554. //
  555. McaStatusCount++;
  556. if (McaStatusCount >=
  557. MCA_NONFATAL_ERORRS_BEFORE_WBINVD) {
  558. #if defined(_AMD64_)
  559. WritebackInvalidate();
  560. #else
  561. _asm {
  562. wbinvd
  563. }
  564. #endif
  565. }
  566. }
  567. } else {
  568. //
  569. // First time we have seen this error, save the Status,
  570. // affinity and clear the count.
  571. //
  572. SavedMcaStatus = Exception->u.Mca.Status.QuadPart;
  573. SavedBank = Exception->u.Mca.BankNumber;
  574. McaStatusCount = 0;
  575. SavedAffinity = CurrentAffinity;
  576. }
  577. } else {
  578. //
  579. // Either we did not get an error or it will be fatal.
  580. // If we did not get an error and we are doing the processor
  581. // that reported the last error, clear things so we do not
  582. // match previous errors. Since each time we look for an
  583. // error we start over with the first processor we do not
  584. // have to worry about multiple processor having stuck
  585. // errors. We will only be able to see the first one.
  586. //
  587. if (SavedAffinity == CurrentAffinity) {
  588. SavedMcaStatus = 0;
  589. SavedBank = 0;
  590. McaStatusCount = 0;
  591. SavedAffinity = 0;
  592. }
  593. }
  594. //
  595. // If found, return current information
  596. //
  597. if (Status != STATUS_NOT_FOUND) {
  598. ASSERT (Status != STATUS_SEVERITY_ERROR);
  599. *Length = BufferSize;
  600. break;
  601. }
  602. }
  603. }
  604. //
  605. // Restore threads affinity, release mutex, and return
  606. //
  607. KeRevertToUserAffinityThread();
  608. HalpMcaUnlockInterface();
  609. return Status;
  610. }
  611. // Set the following to check async capability
  612. BOOLEAN NoMCABugCheck = FALSE;
  613. VOID
  614. HalpMcaExceptionHandler (
  615. VOID
  616. )
  617. /*++
  618. Routine Description:
  619. This is the MCA exception handler.
  620. Arguments:
  621. None
  622. Return Value:
  623. None
  624. --*/
  625. {
  626. NTSTATUS Status;
  627. MCA_EXCEPTION BankLog;
  628. ULONG p1;
  629. ULONGLONG McgStatus, p3;
  630. if (!(HalpFeatureBits & HAL_MCA_PRESENT) ) {
  631. //
  632. // If we have ONLY MCE (and not MCA), read the MC_ADDR and MC_TYPE
  633. // MSRs, print the values and bugcheck as the errors are not
  634. // restartable.
  635. //
  636. BankLog.VersionNumber = 1;
  637. BankLog.ExceptionType = HAL_MCE_RECORD;
  638. BankLog.u.Mce.Address = RDMSR(PENTIUM_MC_ADDR);
  639. BankLog.u.Mce.Type = RDMSR(PENTIUM_MC_TYPE);
  640. Status = STATUS_SEVERITY_ERROR;
  641. //
  642. // Parameters for bugcheck
  643. //
  644. p1 = ((PLARGE_INTEGER)(&BankLog.u.Mce.Type))->LowPart;
  645. p3 = BankLog.u.Mce.Address;
  646. } else {
  647. McgStatus = RDMSR(MCG_STATUS);
  648. ASSERT( (McgStatus & MCG_MC_INPROGRESS) != 0);
  649. BankLog.VersionNumber = 2;
  650. Status = HalpMcaReadProcessorException (&BankLog, TRUE);
  651. //
  652. // Clear MCIP bit in MCG_STATUS register
  653. //
  654. McgStatus = 0;
  655. WRMSR(MCG_STATUS, McgStatus);
  656. //
  657. // Parameters for bugcheck
  658. //
  659. p1 = BankLog.u.Mca.BankNumber;
  660. p3 = BankLog.u.Mca.Status.QuadPart;
  661. }
  662. if (Status == STATUS_SEVERITY_ERROR) {
  663. //
  664. // Call the exception callback of the driver so that
  665. // the error can be logged to NVRAM
  666. //
  667. if (HalpMcaInfo.DriverInfo.ExceptionCallback) {
  668. HalpMcaInfo.DriverInfo.ExceptionCallback (
  669. HalpMcaInfo.DriverInfo.DeviceContext,
  670. &BankLog
  671. );
  672. }
  673. if (!NoMCABugCheck) {
  674. //
  675. // Bugcheck
  676. //
  677. KeBugCheckEx(
  678. MACHINE_CHECK_EXCEPTION,
  679. p1,
  680. (ULONG_PTR) &BankLog,
  681. ((PLARGE_INTEGER)(&p3))->HighPart,
  682. ((PLARGE_INTEGER)(&p3))->LowPart
  683. );
  684. // NOT REACHED
  685. }
  686. }
  687. //
  688. // Must be restartable. Indicate to the timer tick routine that a
  689. // DPC needs queued for MCA driver.
  690. //
  691. if (HalpMcaInfo.DriverInfo.DpcCallback) {
  692. HalpClockMcaQueueDpc = 1;
  693. }
  694. }
  695. VOID
  696. HalpMcaQueueDpc(
  697. VOID
  698. )
  699. /*++
  700. Routine Description:
  701. Gets called from the timer tick to check if DPC
  702. needs to be queued
  703. --*/
  704. {
  705. KeInsertQueueDpc(
  706. &HalpMcaInfo.Dpc,
  707. NULL,
  708. NULL
  709. );
  710. }
  711. NTSTATUS
  712. HalpMcaReadRegisterInterface(
  713. IN UCHAR BankNumber,
  714. IN OUT PMCA_EXCEPTION Exception
  715. )
  716. /*++
  717. Routine Description:
  718. This routine reads the given MCA register number from the
  719. current processor and returns the result in the Exception
  720. structure.
  721. Arguments:
  722. BankNumber Number of MCA Bank to be examined.
  723. Exception Buffer into which the error is reported
  724. Return Value:
  725. STATUS_SUCCESS if an error was found and the data copied into
  726. the excption buffer.
  727. STATUS_UNSUCCESSFUL if the register contains no error information.
  728. STATUS_NOT_FOUND if the register number exceeds the maximum number
  729. of registers.
  730. STATUS_INVALID_PARAMETER if the Exception record is of an unknown type.
  731. --*/
  732. {
  733. ULONGLONG McgStatus;
  734. MCI_STATS istatus;
  735. NTSTATUS ReturnStatus;
  736. MCG_CAPABILITY cap;
  737. ULONG Reg;
  738. //
  739. // Are they asking for a valid register?
  740. //
  741. if (BankNumber >= HalpMcaInfo.NumBanks) {
  742. return STATUS_NOT_FOUND;
  743. }
  744. //
  745. // The exception buffer should tell us if it's version 1 or
  746. // 2. Anything else we don't know how to deal with.
  747. //
  748. if ((Exception->VersionNumber < 1) ||
  749. (Exception->VersionNumber > 2)) {
  750. return STATUS_INVALID_PARAMETER;
  751. }
  752. //
  753. // Read the global status register
  754. //
  755. McgStatus = RDMSR(MCG_STATUS);
  756. //
  757. // Read the Status MSR of the requested bank
  758. //
  759. istatus.QuadPart = RDMSR(MC0_STATUS + BankNumber * MCA_NUM_REGS);
  760. if (istatus.MciStats.Valid == 0) {
  761. //
  762. // No error in this bank.
  763. //
  764. return STATUS_UNSUCCESSFUL;
  765. }
  766. //
  767. // When MCIP bit is set, the execution can be restarted when
  768. // (MCi_STATUS.DAM == 0) && (MCG_STATUS.RIPV == 1)
  769. //
  770. // Note: STATUS_SEVERITY_ERROR is not a valid status choice.
  771. //
  772. ReturnStatus = STATUS_SUCCESS;
  773. if ((McgStatus & MCG_MC_INPROGRESS) &&
  774. (!(McgStatus & MCG_RESTART_EIP_VALID) ||
  775. istatus.MciStats.Damage)) {
  776. ReturnStatus = STATUS_SEVERITY_ERROR;
  777. }
  778. //
  779. // Complete extended exception record, if requested.
  780. //
  781. if (Exception->VersionNumber == 2) {
  782. cap.u.QuadPart = RDMSR(MCG_CAP);
  783. if (cap.u.hw.McaExtCnt > 0) {
  784. // Get Version 2 stuff from MSRs.
  785. Exception->ExtCnt = cap.u.hw.McaExtCnt;
  786. if (Exception->ExtCnt > MCA_EXTREG_V2MAX) {
  787. Exception->ExtCnt = MCA_EXTREG_V2MAX;
  788. }
  789. for (Reg = 0; Reg < Exception->ExtCnt; Reg++) {
  790. Exception->ExtReg[Reg] = RDMSR(MCG_EAX+Reg);
  791. }
  792. if (cap.u.hw.McaExtCnt >= MCG_EFLAGS_OFFSET) {
  793. if (RDMSR(MCG_EFLAGS) == 0) {
  794. // Let user know he got only Version 1 data.
  795. Exception->VersionNumber = 1;
  796. }
  797. }
  798. } else {
  799. // Let user know he got only Version 1 data.
  800. Exception->VersionNumber = 1;
  801. }
  802. }
  803. //
  804. // Complete exception record
  805. //
  806. Exception->ExceptionType = HAL_MCA_RECORD;
  807. Exception->TimeStamp.QuadPart = 0;
  808. Exception->u.Mca.Address.QuadPart = 0;
  809. Exception->u.Mca.Misc = 0;
  810. Exception->u.Mca.BankNumber = BankNumber;
  811. Exception->u.Mca.Status = istatus;
  812. Exception->ProcessorNumber = KeGetCurrentProcessorNumber();
  813. #if defined(_AMD64_)
  814. if (KeGetCurrentIrql() != CLOCK_LEVEL) {
  815. #else
  816. if (KeGetCurrentIrql() != CLOCK2_LEVEL) {
  817. #endif
  818. KeQuerySystemTime(&Exception->TimeStamp);
  819. }
  820. if (istatus.MciStats.AddressValid) {
  821. Exception->u.Mca.Address.QuadPart =
  822. RDMSR(MC0_ADDR + BankNumber * MCA_NUM_REGS);
  823. }
  824. //
  825. // Although MiscValid should never be set on P6 it
  826. // seems that sometimes it is. It is not implemented
  827. // on P6 and above so don't read it there.
  828. //
  829. if (istatus.MciStats.MiscValid &&
  830. (KeGetCurrentPrcb()->CpuType != 6)) {
  831. Exception->u.Mca.Misc =
  832. RDMSR(MC0_MISC + BankNumber * MCA_NUM_REGS);
  833. }
  834. //
  835. // Clear Machine Check in MCi_STATUS register
  836. //
  837. WRMSR(MC0_STATUS + Exception->u.Mca.BankNumber * MCA_NUM_REGS, 0);
  838. //
  839. // Clear Register state in MCG_EFLAGS
  840. //
  841. if (Exception->VersionNumber != 1) {
  842. WRMSR(MCG_EFLAGS, 0);
  843. }
  844. //
  845. // When the Valid bit of status register is cleared, hardware may write
  846. // a new buffered error report into the error reporting area. The
  847. // serializing instruction is required to permit the update to complete
  848. //
  849. HalpSerialize();
  850. return(ReturnStatus);
  851. }
  852. NTSTATUS
  853. HalpMcaReadProcessorException (
  854. IN OUT PMCA_EXCEPTION Exception,
  855. IN BOOLEAN NonRestartableOnly
  856. )
  857. /*++
  858. Routine Description:
  859. This routine logs the errors from the MCA banks on one processor.
  860. Necessary checks for the restartability are performed. The routine
  861. 1> Checks for restartability, and for each bank identifies valid bank
  862. entries and logs error.
  863. 2> If the error is not restartable provides additional information about
  864. bank and the MCA registers.
  865. 3> Resets the Status registers for each bank
  866. Arguments:
  867. Exception: Into which we log the error if found
  868. NonRestartableOnly: Get any error vs. look for error that is not-restartable
  869. Return Values:
  870. STATUS_SEVERITY_ERROR: Detected non-restartable error.
  871. STATUS_SUCCESS: Successfully logged bank values
  872. STATUS_NOT_FOUND: No error found on any bank
  873. --*/
  874. {
  875. UCHAR BankNumber;
  876. NTSTATUS ReturnStatus = STATUS_NOT_FOUND;
  877. //
  878. // scan banks on current processor and log contents of first valid bank
  879. // reporting error. Once we find a valid error, no need to read remaining
  880. // banks. It is the application responsibility to read more errors.
  881. //
  882. for (BankNumber = 0; BankNumber < HalpMcaInfo.NumBanks; BankNumber++) {
  883. ReturnStatus = HalpMcaReadRegisterInterface(BankNumber, Exception);
  884. if ((ReturnStatus == STATUS_UNSUCCESSFUL) ||
  885. ((ReturnStatus == STATUS_SUCCESS) &&
  886. (NonRestartableOnly == TRUE))) {
  887. //
  888. // No error in this bank or only looking for non-restartable
  889. // errors, skip this one.
  890. //
  891. ReturnStatus = STATUS_NOT_FOUND;
  892. continue;
  893. }
  894. //
  895. // We either found an uncorrected error OR found a corrected error
  896. // and we were asked for either corrected or uncorrected error
  897. // Return this error.
  898. //
  899. ASSERT((ReturnStatus == STATUS_SUCCESS) ||
  900. (ReturnStatus == STATUS_SEVERITY_ERROR));
  901. break;
  902. }
  903. return(ReturnStatus);
  904. }
  905. VOID
  906. HalpMcaGetConfiguration (
  907. OUT PULONG MCEEnabled,
  908. OUT PULONG MCAEnabled
  909. )
  910. /*++
  911. Routine Description:
  912. This routine stores the Machine Check configuration information.
  913. Arguments:
  914. MCEEnabled - Pointer to the MCEEnabled indicator.
  915. 0 = False, 1 = True (0 if value not present in Registry).
  916. MCAEnabled - Pointer to the MCAEnabled indicator.
  917. 0 = False, 1 = True (1 if value not present in Registry).
  918. Return Value:
  919. None.
  920. --*/
  921. {
  922. RTL_QUERY_REGISTRY_TABLE Parameters[3];
  923. ULONG DefaultDataMCE;
  924. ULONG DefaultDataMCA;
  925. RtlZeroMemory(Parameters, sizeof(Parameters));
  926. DefaultDataMCE = *MCEEnabled = FALSE;
  927. DefaultDataMCA = *MCAEnabled = TRUE;
  928. //
  929. // Gather all of the "user specified" information from
  930. // the registry.
  931. //
  932. Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  933. Parameters[0].Name = rgzEnableMCE;
  934. Parameters[0].EntryContext = MCEEnabled;
  935. Parameters[0].DefaultType = REG_DWORD;
  936. Parameters[0].DefaultData = &DefaultDataMCE;
  937. Parameters[0].DefaultLength = sizeof(ULONG);
  938. Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  939. Parameters[1].Name = rgzEnableMCA;
  940. Parameters[1].EntryContext = MCAEnabled;
  941. Parameters[1].DefaultType = REG_DWORD;
  942. Parameters[1].DefaultData = &DefaultDataMCA;
  943. Parameters[1].DefaultLength = sizeof(ULONG);
  944. RtlQueryRegistryValues(
  945. RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
  946. rgzSessionManager,
  947. Parameters,
  948. NULL,
  949. NULL
  950. );
  951. }
  952. VOID
  953. HalHandleMcheck (
  954. IN PKTRAP_FRAME TrapFrame,
  955. IN PKEXCEPTION_FRAME ExceptionFrame
  956. )
  957. {
  958. HalpMcaExceptionHandler();
  959. }