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.

2190 lines
62 KiB

  1. //** Copyright (C) 1996-2000 Intel Corporation. All rights reserved.
  2. //**
  3. //** The information and source code contained herein is the exclusive
  4. //** property of Intel Corporation and may not be disclosed, examined
  5. //** or reproduced in whole or in part without explicit written authorization
  6. //** from the company.
  7. //**
  8. //###########################################################################
  9. //-----------------------------------------------------------------------------
  10. // Version control information follows.
  11. //
  12. //
  13. // 10 Jun 1999 Bugcheck Bernard Lint
  14. // M. Jayakumar ([email protected])
  15. // Thierry Fevrier
  16. ///////////////////////////////////////////////////////////////////////////////
  17. //
  18. // Module Name: OSMCA.C - Merced OS Machine Check Handler
  19. //
  20. // Description:
  21. // This module has OS Machine Check Handler Reference Code.
  22. //
  23. // Contents: HalpOsMcaInit()
  24. // HalpCmcHandler()
  25. // HalpMcaHandler()
  26. // HalpMcRzHandlr()
  27. // HalpMcWkupHandlr()
  28. // HalpProcMcaHndlr()
  29. // HalpPlatMcaHndlr()
  30. //
  31. //
  32. // Target Platform: Merced
  33. //
  34. // Reuse: None
  35. //
  36. ////////////////////////////////////////////////////////////////////////////M//
  37. #include "halp.h"
  38. #include "nthal.h"
  39. #include "arc.h"
  40. #include "i64fw.h"
  41. #include "check.h"
  42. #include "iosapic.h"
  43. #include "inbv.h"
  44. #include "osmca.h"
  45. // pmdata.c: CPE definitions.
  46. extern ULONG HalpMaxCPEImplemented;
  47. extern ULONG HalpCPEIntIn[];
  48. // i64fw.c: HAL Private Data structure for SAL/PAL
  49. extern HALP_SAL_PAL_DATA HalpSalPalData;
  50. // i64fwasm.s: low-level protection data structures
  51. extern KSPIN_LOCK HalpMcaSpinLock;
  52. extern KSPIN_LOCK HalpCmcSpinLock;
  53. extern KSPIN_LOCK HalpCpeSpinLock;
  54. //
  55. // IA64 MCE Info structures to keep track of MCE features
  56. // available on installed hardware.
  57. //
  58. HALP_MCA_INFO HalpMcaInfo;
  59. HALP_CMC_INFO HalpCmcInfo;
  60. HALP_CPE_INFO HalpCpeInfo;
  61. KERNEL_MCE_DELIVERY HalpMceKernelDelivery;
  62. volatile ULONG HalpOsMcaInProgress = 0;
  63. //
  64. // SAL_MC_SET_PARAMS.time_out
  65. //
  66. ULONGLONG HalpMcRendezTimeOut = HALP_DEFAULT_MC_RENDEZ_TIMEOUT;
  67. //
  68. // HalpProcessorMcaRecords:
  69. //
  70. // Number of MCA records pre-allocated per processor.
  71. //
  72. ULONGLONG HalpProcessorMcaRecords = HALP_DEFAULT_PROCESSOR_MCA_RECORDS;
  73. //
  74. // HalpProcessorInitRecords:
  75. //
  76. // Number of INIT records pre-allocated per processor.
  77. //
  78. ULONGLONG HalpProcessorInitRecords = HALP_DEFAULT_PROCESSOR_INIT_RECORDS;
  79. //
  80. // HalpMceLogsMaxCount:
  81. //
  82. // Maximum number of saved logs.
  83. //
  84. ULONG HalpMceLogsMaxCount = HALP_MCELOGS_MAXCOUNT;
  85. //
  86. // HAL Private Error Device GUIDs:
  87. // [useful for kdexts]
  88. //
  89. ERROR_DEVICE_GUID HalpErrorProcessorGuid = ERROR_PROCESSOR_GUID;
  90. ERROR_DEVICE_GUID HalpErrorMemoryGuid = ERROR_MEMORY_GUID;
  91. ERROR_DEVICE_GUID HalpErrorPciBusGuid = ERROR_PCI_BUS_GUID;
  92. ERROR_DEVICE_GUID HalpErrorPciComponentGuid = ERROR_PCI_COMPONENT_GUID;
  93. ERROR_DEVICE_GUID HalpErrorSystemEventLogGuid = ERROR_SYSTEM_EVENT_LOG_GUID;
  94. ERROR_DEVICE_GUID HalpErrorSmbiosGuid = ERROR_SMBIOS_GUID;
  95. ERROR_DEVICE_GUID HalpErrorPlatformSpecificGuid = ERROR_PLATFORM_SPECIFIC_GUID;
  96. ERROR_DEVICE_GUID HalpErrorPlatformBusGuid = ERROR_PLATFORM_BUS_GUID;
  97. ERROR_DEVICE_GUID HalpErrorPlatformHostControllerGuid = ERROR_PLATFORM_HOST_CONTROLLER_GUID;
  98. //
  99. // HAL Private Error Definitions:
  100. // [useful for kdexts]
  101. // Actually in this case, the typed pointers allow also the inclusion of the symbols definitions
  102. // without the data structures sizes.
  103. //
  104. PERROR_MODINFO HalpPErrorModInfo;
  105. PERROR_PROCESSOR_CPUID_INFO HalpPErrorProcessorCpuIdInfo;
  106. PERROR_PROCESSOR HalpPErrorProcessor;
  107. PERROR_PROCESSOR_STATIC_INFO HalpPErrorProcessorStaticInfo;
  108. PERROR_MEMORY HalpPErrorMemory;
  109. PERROR_PCI_BUS HalpPErrorPciBus;
  110. PERROR_PCI_COMPONENT HalpPErrorPciComponent;
  111. PERROR_SYSTEM_EVENT_LOG HalpPErrorSystemEventLog;
  112. PERROR_SMBIOS HalpPErrorSmbios;
  113. PERROR_PLATFORM_SPECIFIC HalpPErrorPlatformSpecific;
  114. PERROR_PLATFORM_BUS HalpPErrorPlatformBus;
  115. PERROR_PLATFORM_HOST_CONTROLLER HalpPErrorPlatformHostController;
  116. //
  117. // MCA/CMC/CPE state catchers
  118. //
  119. ERROR_SEVERITY
  120. HalpMcaProcessLog(
  121. PMCA_EXCEPTION McaLog
  122. );
  123. BOOLEAN
  124. HalpPreAllocateMceTypeRecords(
  125. ULONG EventType,
  126. ULONG Number
  127. );
  128. VOID
  129. HalpMcaBugCheck(
  130. ULONG McaBugCheckType,
  131. PMCA_EXCEPTION McaLog,
  132. ULONGLONG McaAllocatedLogSize,
  133. ULONGLONG Arg4
  134. );
  135. #ifdef ALLOC_PRAGMA
  136. #pragma alloc_text(INIT, HalpInitializeOSMCA)
  137. #pragma alloc_text(INIT, HalpAllocateMceStacks)
  138. #pragma alloc_text(INIT, HalpPreAllocateMceRecords)
  139. #pragma alloc_text(INIT, HalpPreAllocateMceTypeRecords)
  140. #pragma alloc_text(PAGELK, HalpMcaHandler)
  141. #pragma alloc_text(PAGELK, HalpMcaProcessLog)
  142. #pragma alloc_text(PAGELK, HalpMcaBugCheck)
  143. #pragma alloc_text(PAGELK, HalpGetErrLog)
  144. #pragma alloc_text(PAGELK, HalpClrErrLog)
  145. #pragma alloc_text(PAGE, HalpGetMceInformation)
  146. #endif // ALLOC_PRAGMA
  147. BOOLEAN
  148. HalpSaveEventLog(
  149. PSINGLE_LIST_ENTRY HeadList,
  150. PERROR_RECORD_HEADER RecordHeader,
  151. ULONG Tag,
  152. POOL_TYPE PoolType,
  153. PKSPIN_LOCK SpinLock
  154. )
  155. {
  156. PSINGLE_LIST_ENTRY entry, previousEntry;
  157. SIZE_T logSize;
  158. PERROR_RECORD_HEADER savedLog;
  159. KIRQL oldIrql;
  160. //
  161. // Allocate and Initialize the new entry
  162. //
  163. logSize = RecordHeader->Length;
  164. if ( !logSize ) {
  165. HalDebugPrint(( HAL_ERROR, "HAL!HalpSaveEventLog: record length is zeroed.\n" ));
  166. return FALSE;
  167. }
  168. entry = (PSINGLE_LIST_ENTRY)ExAllocatePoolWithTag( PoolType, sizeof(*entry) + logSize, Tag );
  169. if ( entry == NULL ) {
  170. HalDebugPrint(( HAL_ERROR, "HAL!HalpSaveEventLog: Event log allocation failed.\n" ));
  171. return FALSE;
  172. }
  173. entry->Next = NULL;
  174. savedLog = (PERROR_RECORD_HEADER)((ULONG_PTR)entry + sizeof(*entry));
  175. RtlCopyMemory( savedLog, RecordHeader, logSize );
  176. //
  177. // Insert the new entry with protection.
  178. //
  179. KeRaiseIrql( HIGH_LEVEL, &oldIrql );
  180. KiAcquireSpinLock( SpinLock );
  181. previousEntry = HeadList;
  182. while( previousEntry->Next != NULL ) {
  183. previousEntry = previousEntry->Next;
  184. }
  185. previousEntry->Next = entry;
  186. KiReleaseSpinLock( SpinLock );
  187. KeLowerIrql( oldIrql );
  188. return TRUE;
  189. } // HalpSaveEventLog()
  190. #define HalpSaveCorrectedMcaLog( _McaLog ) \
  191. HalpSaveEventLog( &HalpMcaInfo.CorrectedLogs, (PERROR_RECORD_HEADER)(_McaLog), 'CacM', NonPagedPool, &HalpMcaSpinLock )
  192. NTSTATUS
  193. HalpCheckForMcaLogs(
  194. VOID
  195. )
  196. /*++
  197. Routine Description:
  198. This routine checks the FW early during boot if a MCA event log is present.
  199. The log is considered as "previous".
  200. This routine is called at phase 1 on BSP only, from HalpPreAllocateMceRecords().
  201. it is executed on the standard kernel stacks.
  202. Arguments:
  203. None
  204. Return Value:
  205. STATUS_NO_MEMORY if mca log allocation failed.
  206. STATUS_SUCCESS otherwise, regardless of FW interfaces failures.
  207. --*/
  208. {
  209. NTSTATUS status;
  210. PERROR_RECORD_HEADER log;
  211. log = ExAllocatePoolWithTag( NonPagedPool, HalpMcaInfo.Stats.MaxLogSize, 'PacM' );
  212. if ( !log ) {
  213. return( STATUS_NO_MEMORY );
  214. }
  215. status = HalpGetFwMceLog( MCA_EVENT, log, &HalpMcaInfo.Stats, HALP_FWMCE_DONOT_CLEAR_LOG );
  216. if ( status != STATUS_NOT_FOUND ) {
  217. //
  218. // Successful log collection or invalid record or unsuccessful FW Interface calls
  219. // are considered as a trigger for the MCA log consumers to collect them from the FW.
  220. //
  221. InterlockedIncrement( &HalpMcaInfo.Stats.McaPreviousCount );
  222. }
  223. ExFreePoolWithTag( log, 'PacM' );
  224. return( STATUS_SUCCESS );
  225. } // HalpCheckForMcaLogs()
  226. BOOLEAN
  227. HalpPreAllocateMceTypeRecords(
  228. ULONG EventType,
  229. ULONG Number
  230. )
  231. {
  232. SAL_PAL_RETURN_VALUES rv = {0};
  233. ULONGLONG defaultEventRecords;
  234. PVOID log;
  235. SIZE_T logSize;
  236. PHYSICAL_ADDRESS physicalAddr;
  237. if ( (EventType != MCA_EVENT) && (EventType != INIT_EVENT) ) {
  238. ASSERTMSG( "HAL!HalpPreAllocateMceTypeRecords: unknown event type!\n", FALSE );
  239. return FALSE;
  240. }
  241. //
  242. // On BSP only, call SAL to get maximum size of EventType record
  243. //
  244. if ( Number == 0 ) {
  245. rv = HalpGetStateInfoSize( EventType );
  246. if ( !SAL_SUCCESSFUL(rv) ) {
  247. HalDebugPrint(( HAL_ERROR, "HAL!HalpPreAllocateMceTypeRecords: SAL_GET_STATE_INFO_SIZE failed...\n" ));
  248. return FALSE;
  249. }
  250. logSize = rv.ReturnValues[1];
  251. }
  252. if ( EventType == MCA_EVENT ) {
  253. if ( Number == 0 ) {
  254. // Update HalpMcaInfo, without protection. This is not required.
  255. HalpMcaInfo.Stats.MaxLogSize = (ULONG)logSize;
  256. }
  257. else {
  258. logSize = (SIZE_T)HalpMcaInfo.Stats.MaxLogSize;
  259. }
  260. defaultEventRecords = HalpProcessorMcaRecords;
  261. }
  262. else {
  263. ASSERTMSG( "HAL!HalpPreAllocateMceTypeRecords: invalid event type!\n", EventType == INIT_EVENT );
  264. if ( Number == 0 ) {
  265. // Update HalpInitInfo, without protection. This is not required.
  266. HalpInitInfo.MaxLogSize = (ULONG)logSize;
  267. }
  268. else {
  269. logSize = (SIZE_T)HalpInitInfo.MaxLogSize;
  270. }
  271. defaultEventRecords = HalpProcessorInitRecords;
  272. }
  273. // Determine size of allocation
  274. logSize = ROUND_TO_PAGES( (logSize * defaultEventRecords) );
  275. //
  276. // Allocate Event Records buffer
  277. //
  278. physicalAddr.QuadPart = 0xffffffffffffffffI64;
  279. log = MmAllocateContiguousMemory( logSize, physicalAddr );
  280. if ( log == NULL ) {
  281. HalDebugPrint(( HAL_ERROR, "HAL!HalpPreAllocateMceTypeRecords: SAL %s Event Records allocation failed (0x%Ix)...\n",
  282. ( EventType == MCA_EVENT ) ? "MCA" : "INIT",
  283. logSize ));
  284. return FALSE;
  285. }
  286. //
  287. // Update KPCR entry.
  288. //
  289. {
  290. volatile KPCR * const pcr = KeGetPcr();
  291. PSAL_EVENT_RESOURCES eventResources;
  292. if ( EventType == MCA_EVENT ) {
  293. eventResources = pcr->OsMcaResourcePtr;
  294. }
  295. eventResources->EventPool = log;
  296. eventResources->EventPoolSize = (ULONG) logSize;
  297. }
  298. return TRUE;
  299. } // HalpPreAllocateMceTypeRecords()
  300. BOOLEAN
  301. HalpPreAllocateMceRecords(
  302. IN ULONG Number
  303. )
  304. {
  305. NTSTATUS status;
  306. //
  307. // Pre-Allocate MCA records
  308. //
  309. if ( !HalpPreAllocateMceTypeRecords( MCA_EVENT , Number ) ) {
  310. return FALSE;
  311. }
  312. //
  313. // Check for MCA logs.
  314. // These might be logs related to previous boot sessions.
  315. //
  316. status = HalpCheckForMcaLogs();
  317. if ( !NT_SUCCESS( status ) ) {
  318. return FALSE;
  319. }
  320. return TRUE;
  321. } // HalpPreAllocateMceRecords()
  322. BOOLEAN
  323. HalpAllocateMceStacks(
  324. IN ULONG Number
  325. )
  326. {
  327. PHYSICAL_ADDRESS physicalAddr;
  328. PVOID mem;
  329. PVOID mcaStateDump, mcaBackStore, mcaStack;
  330. ULONGLONG mcaStateDumpPhysical;
  331. ULONGLONG mcaBackStoreLimit, mcaStackLimit;
  332. ULONG length;
  333. //
  334. // Allocate MCA/INIT stacks
  335. //
  336. length = HALP_MCA_STATEDUMP_SIZE + HALP_MCA_BACKSTORE_SIZE + HALP_MCA_STACK_SIZE;
  337. physicalAddr.QuadPart = 0xffffffffffffffffI64;
  338. mem = MmAllocateContiguousMemory( length, physicalAddr );
  339. if ( mem == NULL ) {
  340. HalDebugPrint(( HAL_ERROR, "HAL!HalpAllocateMceStacks: MCA State Dump allocation failed (0x%Ix)...\n",
  341. length ));
  342. return FALSE;
  343. }
  344. //
  345. // The layout in memory by increasing addresses is:
  346. //
  347. // Bottom of stack
  348. // .
  349. // .
  350. // .
  351. // Initial Stack
  352. // State Dump Area
  353. // .
  354. // .
  355. // Initial BSP
  356. // .
  357. // .
  358. // .
  359. // BSP Limit
  360. //
  361. mcaStack = mem;
  362. mcaStackLimit = (ULONGLONG)mem + HALP_MCA_STACK_SIZE;
  363. mem = (PCHAR) mem + HALP_MCA_STACK_SIZE;
  364. mcaStateDump = mem;
  365. mcaStateDumpPhysical = MmGetPhysicalAddress(mem).QuadPart;
  366. mem = (PCHAR) mem + HALP_MCA_STATEDUMP_SIZE;
  367. mcaBackStore = mem;
  368. mcaBackStoreLimit = (ULONGLONG)mem + (ULONGLONG)(ULONG)HALP_MCA_BACKSTORE_SIZE;
  369. //
  370. // Update PCR MCA, INIT stacks
  371. //
  372. {
  373. volatile KPCR * const pcr = KeGetPcr();
  374. PSAL_EVENT_RESOURCES eventResources;
  375. eventResources = pcr->OsMcaResourcePtr;
  376. eventResources->StateDump = mcaStateDump;
  377. eventResources->StateDumpPhysical = mcaStateDumpPhysical;
  378. eventResources->BackStore = mcaBackStore;
  379. eventResources->BackStoreLimit = mcaBackStoreLimit;
  380. eventResources->Stack = (PCHAR) mcaStackLimit;
  381. eventResources->StackLimit = (ULONGLONG) mcaStack;
  382. }
  383. return TRUE;
  384. } // HalpPreAllocateMceRecords()
  385. //++
  386. // Name: HalpInitializeOSMCA()
  387. //
  388. // Routine Description:
  389. //
  390. // This routine registers MCA init's
  391. //
  392. // Arguments On Entry:
  393. // arg0 = Function ID
  394. //
  395. // Success/Failure (0/!0)
  396. //--
  397. BOOLEAN
  398. HalpInitializeOSMCA(
  399. IN ULONG Number
  400. )
  401. {
  402. SAL_PAL_RETURN_VALUES rv = {0};
  403. ULONGLONG gp_reg;
  404. //
  405. // Register SAL_MC_RendezVous parameters with SAL
  406. //
  407. rv = HalpSalSetParams(0, RendzType, IntrVecType, MC_RZ_VECTOR, HalpMcRendezTimeOut);
  408. if ( !SAL_SUCCESSFUL(rv) ) {
  409. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_MC_SET_PARAMS.rendezvous vector failed...\n" ));
  410. return FALSE;
  411. }
  412. //
  413. // Register WakeUp parameters with SAL
  414. //
  415. rv = HalpSalSetParams(0, WakeUpType, IntrVecType, MC_WKUP_VECTOR,0);
  416. if ( !SAL_SUCCESSFUL(rv) ) {
  417. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_MC_SET_PARAMS.wakeup vector failed...\n" ));
  418. return FALSE;
  419. }
  420. //
  421. // Allocate MCA, INIT stacks
  422. //
  423. if ( !HalpAllocateMceStacks( Number ) ) {
  424. return FALSE;
  425. }
  426. //
  427. // Pre-Allocate desired number of MCA,INIT records
  428. //
  429. HalpMcaInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN;
  430. if ( !HalpPreAllocateMceRecords( Number ) ) {
  431. return FALSE;
  432. }
  433. //
  434. // Initialize HAL private CMC, CPE structures.
  435. //
  436. if ( HalpFeatureBits & HAL_CMC_PRESENT ) {
  437. rv = HalpGetStateInfoSize( CMC_EVENT );
  438. if ( SAL_SUCCESSFUL( rv ) ) {
  439. if ( rv.ReturnValues[1] >= sizeof( ERROR_RECORD_HEADER ) ) {
  440. HalpCmcInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1];
  441. HalpCmcInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN;
  442. HalpCmcInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount;
  443. HalpCmcInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount;
  444. HalpCmcInfo.Stats.PollingInterval = HAL_CMC_INTERRUPTS_BASED;
  445. HalpCmcInfo.ThresholdCounter = 0;
  446. } else {
  447. HalDebugPrint(( HAL_ERROR,
  448. "HAL!HalpGetFeatureBits: Invalid max CMC log size from SAL\n" ));
  449. HalpFeatureBits &= ~HAL_CMC_PRESENT;
  450. }
  451. } else {
  452. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CMC failed...\n" ));
  453. HalpFeatureBits &= ~HAL_CMC_PRESENT;
  454. }
  455. }
  456. if ( HalpFeatureBits & HAL_CPE_PRESENT ) {
  457. rv = HalpGetStateInfoSize( CPE_EVENT );
  458. if ( SAL_SUCCESSFUL( rv ) ) {
  459. if ( rv.ReturnValues[1] >= sizeof( ERROR_RECORD_HEADER ) ) {
  460. HalpCpeInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1];
  461. HalpCpeInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN;
  462. HalpCpeInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount;
  463. HalpCpeInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount;
  464. HalpCpeInfo.ThresholdCounter = 0;
  465. } else {
  466. HalDebugPrint(( HAL_ERROR,
  467. "HAL!HalpGetFeatureBits: Invalid max CPE log size from SAL\n" ));
  468. HalpFeatureBits &= ~HAL_CPE_PRESENT;
  469. }
  470. } else {
  471. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CPE failed...\n" ));
  472. HalpFeatureBits &= ~HAL_CPE_PRESENT;
  473. }
  474. }
  475. //
  476. // Register OsMcaDispatch (OS_MCA) physical address with SAL
  477. //
  478. gp_reg = GetGp();
  479. rv = HalpSalSetVectors(0, MchkEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsMcaDispatch1)->fPtr)), gp_reg,0);
  480. if ( !SAL_SUCCESSFUL(rv) ) {
  481. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.MCA vector failed...\n" ));
  482. return FALSE;
  483. }
  484. //
  485. // Register OsInitDispatch physical address with SAL
  486. //
  487. rv = HalpSalSetVectors(0, InitEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsInitDispatch)->fPtr)), gp_reg,0);
  488. if ( !SAL_SUCCESSFUL(rv) ) {
  489. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.INIT vector failed...\n" ));
  490. return FALSE;
  491. }
  492. return TRUE;
  493. } // HalpInitializeOSMCA()
  494. //EndProc//////////////////////////////////////////////////////////////////////
  495. VOID
  496. HalpMcaBugCheck(
  497. ULONG McaBugCheckType,
  498. PMCA_EXCEPTION McaLog,
  499. ULONGLONG McaAllocatedLogSize,
  500. ULONGLONG SalStatus
  501. )
  502. //++
  503. // Name: HalpMcaBugCheck()
  504. //
  505. // Routine Description:
  506. //
  507. // This function is called to bugcheck the system in a case of a fatal MCA
  508. // or fatal FW interface errors. The OS must guarantee as much as possible
  509. // error containment in this path.
  510. // With the current implementation, this function should be only called from
  511. // the OS_MCA path. For other MCA specific wrappers of KeBugCheckEx, one should
  512. // HalpMcaKeBugCheckEx().
  513. //
  514. // Arguments On Entry:
  515. // ULONG McaBugCheckType
  516. // PMCA_EXCEPTION McaLog
  517. // ULONGLONG McaAllocatedLogSize
  518. // ULONGLONG SalStatus
  519. //
  520. // Return:
  521. // None.
  522. //
  523. // Implementation notes:
  524. // This code CANNOT [as default rules - at least entry and through fatal MCAs handling]
  525. // - make any system call
  526. // - attempt to acquire any spinlock used by any code outside the MCA handler
  527. // - change the interrupt state.
  528. // Passing data to non-MCA code must be done using manual semaphore instructions.
  529. // This code should minimize the path and the global or memory allocated data accesses.
  530. // This code should only access MCA-namespace structures.
  531. // This code is called under the MP protection of HalpMcaSpinLock and with the flag
  532. // HalpOsMcaInProgress set.
  533. //
  534. //--
  535. {
  536. if ( HalpOsMcaInProgress ) {
  537. //
  538. // Enable InbvDisplayString calls to make it through to bootvid driver.
  539. //
  540. if ( InbvIsBootDriverInstalled() ) {
  541. InbvAcquireDisplayOwnership();
  542. InbvResetDisplay();
  543. InbvSolidColorFill(0,0,639,479,4); // make the screen blue
  544. InbvSetTextColor(15);
  545. InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
  546. InbvEnableDisplayString(TRUE); // enable display string
  547. InbvSetScrollRegion(0,0,639,479); // set to use entire screen
  548. }
  549. HalDisplayString (MSG_MCA_HARDWARE_ERROR);
  550. HalDisplayString (MSG_HARDWARE_ERROR2);
  551. //
  552. // Thierry 09/2000:
  553. //
  554. // - if desired, process the MCA log HERE...
  555. //
  556. // and use HalDisplayString() to dump info for the field or hardware vendor.
  557. // The processing could be based on processor or platform independent record definitions.
  558. //
  559. HalDisplayString( MSG_HALT );
  560. if ( HalpMcaInfo.NoBugCheck == 0 ) {
  561. KeBugCheckEx( MACHINE_CHECK_EXCEPTION, (ULONG_PTR)McaBugCheckType,
  562. (ULONG_PTR)McaLog,
  563. (ULONG_PTR)McaAllocatedLogSize,
  564. (ULONG_PTR)SalStatus );
  565. }
  566. }
  567. if ( ((*KdDebuggerNotPresent) == FALSE) && ((*KdDebuggerEnabled) != FALSE) ) {
  568. KeEnterKernelDebugger();
  569. }
  570. while( TRUE ) {
  571. //
  572. ; // Simply sit here so the MCA HARDWARE ERROR screen does not get corrupted...
  573. //
  574. }
  575. // noreturn
  576. } // HalpMcaBugCheck()
  577. ERROR_SEVERITY
  578. HalpMcaProcessLog(
  579. PMCA_EXCEPTION McaLog
  580. )
  581. //++
  582. // Name: HalpMcaProcessLog()
  583. //
  584. // Routine Description:
  585. //
  586. // This function is called to process the MCA event log in the OS_MCA path.
  587. //
  588. // Arguments On Entry:
  589. // PMCA_EXCEPTION McaLog - Pointer to the MCA event log.
  590. //
  591. // Return:
  592. // ERROR_SEVERITY
  593. //
  594. // Implementation notes:
  595. // This code CANNOT [as default rules]
  596. // - make any system call
  597. // - attempt to acquire any spinlock used by any code outside the MCA handler
  598. // - change the interrupt state.
  599. // Passing data to non-MCA code must be done using manual semaphore instructions.
  600. // This code should minimize the path and the global or memory allocated data accesses.
  601. // This code should only access MCA-namespace structures.
  602. // This code is called under the MP protection of HalpMcaSpinLock and with the flag
  603. // HalpOsMcaInProgress set.
  604. //
  605. //--
  606. {
  607. ERROR_SEVERITY mcaSeverity;
  608. mcaSeverity = McaLog->ErrorSeverity;
  609. switch( mcaSeverity ) {
  610. case ErrorFatal:
  611. break;
  612. case ErrorRecoverable:
  613. //
  614. // Thierry - FIXFIX 08/2000:
  615. //
  616. ///////////////////////////////////////////////////////////////
  617. //
  618. // Call to kernel supported recovery will be here....
  619. //
  620. ///////////////////////////////////////////////////////////////
  621. //
  622. // However, for now we do not recover so flag it as ErrorFatal.
  623. mcaSeverity = ErrorFatal;
  624. break;
  625. case ErrorCorrected:
  626. default:
  627. //
  628. // These ERRROR_SEVERITY values have no HAL MCA specific handling.
  629. // As specified by the SAL Specs July 2000, we should not get these values in this path.
  630. //
  631. break;
  632. }
  633. //
  634. // If OEM driver has registered an exception callback for MCA event,
  635. // call it here and save returned error severity value.
  636. //
  637. if ( HalpMcaInfo.DriverInfo.ExceptionCallback ) {
  638. mcaSeverity = HalpMcaInfo.DriverInfo.ExceptionCallback(
  639. HalpMcaInfo.DriverInfo.DeviceContext,
  640. McaLog );
  641. }
  642. //
  643. // Save corrected log for future kernel notification.
  644. //
  645. if ( (HalpMcaInfo.KernelDelivery) && (mcaSeverity == ErrorCorrected) ) {
  646. InterlockedIncrement( &HalpMcaInfo.Stats.McaCorrectedCount );
  647. #if 0
  648. //
  649. // Thierry - 09/16/2000: ToBeDone.
  650. // Saving the corrected MCA log records requires careful rendez-vous configuration
  651. // handling, possible OS_MCA monarch selection, MCA logs (pre-)allocations and
  652. // special locking in case a consumer accesses the logs queue on another processor.
  653. //
  654. // The kernel-WMI and/or OEM MCA driver notification is done in HalpMcaHandler().
  655. //
  656. if ( !HalpSaveCorrectedMcaLog( McaLog ) ) {
  657. InterlockedIncrement( &HalpMcaInfo.CorrectedLogsLost );
  658. }
  659. #endif // 0
  660. //
  661. // The kernel-WMI and/or OEM MCA driver notification for corrected MCA event
  662. // is done in HalpMcaHandler().
  663. //
  664. }
  665. //
  666. // Thierry 10/17/2000 BUGBUG
  667. //
  668. // The FW does not save the MCA log in NVRAM and we have no official date from Intel
  669. // when the SAL will be doing it.
  670. // So for now, return as ErrorFatal and let dump the log through the debugger.
  671. //
  672. // Before Sal Rev <ToBeDetermined>, the error logs were completely erroneous...
  673. //
  674. if ( HalpSalPalData.SalRevision.Revision < HALP_SAL_REVISION_MAX ) {
  675. return( ErrorFatal );
  676. }
  677. else {
  678. return( mcaSeverity );
  679. }
  680. } // HalpMcaProcessLog()
  681. SAL_PAL_RETURN_VALUES
  682. HalpMcaHandler(
  683. ULONG64 RendezvousState,
  684. PPAL_MINI_SAVE_AREA Pmsa
  685. )
  686. //++
  687. // Name: HalpMcaHandler()
  688. //
  689. // Routine Description:
  690. //
  691. // This is the OsMca handler for firmware uncorrected errors
  692. // It is our option to run this in physical or virtual mode.
  693. //
  694. // Arguments On Entry:
  695. // None.
  696. //
  697. // Conditions On Entry: 09/2000 implementation.
  698. // - PSR state: at least,
  699. // PSR.dt = 1, PSR.it = 1, PSR.rt = 1 - virtual mode.
  700. // PSR.ic = 1, PSR.i = 0 - Interruption resources collection enabled,
  701. // Interrupts off.
  702. // PSR.mc = 1 - MCA masked for this processor.
  703. // - SalToOsHndOff initialized.
  704. // - s0 = MinStatePtr.
  705. // - s1 = IA64 PAL Processor State Parameter.
  706. // - s2 = PALE_CHECK return address.
  707. // - Processor registers state saved in myStateDump[] by osmcaProcStateDump().
  708. // - myStackFrame[0] = ar.rsc
  709. // - myStackFrame[1] = ar.pfs
  710. // - myStackFrame[2] = ar.ifs
  711. // - myStackFrame[3] = ar.bspstore
  712. // - myStackFrame[4] = ar.rnat
  713. // - myStackFrame[5] = ar.bsp - ar.bspstore
  714. // - ar.bspstore = myBspStore
  715. // - sp = &mySp[sizeof(mySp[])]
  716. //
  717. // Return:
  718. // rtn0=Success/Failure (0/!0)
  719. // rtn1=Alternate MinState Pointer if any else NULL
  720. //
  721. // Implementation notes:
  722. // This code CANNOT [as default rules - at least entry and through fatal MCAs handling]
  723. // - make any system call
  724. // - attempt to acquire any spinlock used by any code outside the MCA handler
  725. // - change the interrupt state.
  726. // Passing data to non-MCA code must be done using manual semaphore instructions.
  727. // This code should minimize the path and the global or memory allocated data accesses.
  728. // This code should only access MCA-namespace structures and should not access globals
  729. // until it is safe.
  730. //
  731. //--
  732. {
  733. SAL_PAL_RETURN_VALUES rv;
  734. LONGLONG salStatus;
  735. BOOLEAN mcWakeUp;
  736. PMCA_EXCEPTION mcaLog;
  737. ULONGLONG mcaAllocatedLogSize;
  738. PSAL_EVENT_RESOURCES mcaResources;
  739. KIRQL oldIrql;
  740. BOOLEAN raisedIrql;
  741. volatile KPCR * const pcr = KeGetPcr();
  742. //
  743. // Acquire MCA spinlock protecting OS_MCA resources.
  744. //
  745. // Thierry 10/06/2000: FIXFIX.
  746. // we will move this MP synchronization in HalpOsMcaDispatch after current discussions
  747. // with Intel about MP MCA handling are completed.
  748. // Expecting responses from Intel about these.
  749. //
  750. //
  751. // If we are running below MCA_LEVEL then we need to raise irql to
  752. // MCA_LEVEL.
  753. //
  754. if (KeGetCurrentIrql() < MCA_LEVEL)
  755. {
  756. KeRaiseIrql(MCA_LEVEL, &oldIrql);
  757. raisedIrql = TRUE;
  758. } else {
  759. raisedIrql = FALSE;
  760. }
  761. //
  762. // Enable interrupts while we spin on the MCA spinlock. This will allow the
  763. // monarch processor to IPI us if it needs to.
  764. //
  765. HalpEnableInterrupts();
  766. HalpAcquireMcaSpinLock( &HalpMcaSpinLock );
  767. HalpDisableInterrupts();
  768. HalpOsMcaInProgress++;
  769. //
  770. // Save OsToSal minimum state
  771. //
  772. mcaResources = pcr->OsMcaResourcePtr;
  773. mcaResources->OsToSalHandOff.SalReturnAddress = mcaResources->SalToOsHandOff.SalReturnAddress;
  774. mcaResources->OsToSalHandOff.SalGlobalPointer = mcaResources->SalToOsHandOff.SalGlobalPointer;
  775. //
  776. // update local variables with pre-initialized MCA log data.
  777. //
  778. mcaLog = (PMCA_EXCEPTION)(mcaResources->EventPool);
  779. mcaAllocatedLogSize = mcaResources->EventPoolSize;
  780. if ( !mcaLog || !mcaAllocatedLogSize ) {
  781. //
  782. // The following code should never happen or the implementation of the HAL MCA logs
  783. // pre-allocation failed miserably. This would be a development error.
  784. //
  785. HalpMcaBugCheck( (ULONG_PTR)HAL_BUGCHECK_MCA_ASSERT, mcaLog,
  786. mcaAllocatedLogSize,
  787. (ULONGLONG)0 );
  788. }
  789. //
  790. // Get the MCA logs
  791. //
  792. salStatus = (LONGLONG)0;
  793. while( salStatus >= 0 ) {
  794. ERROR_SEVERITY errorSeverity;
  795. rv = HalpGetStateInfo( MCA_EVENT, mcaLog );
  796. salStatus = rv.ReturnValues[0];
  797. switch( salStatus ) {
  798. case SAL_STATUS_SUCCESS:
  799. errorSeverity = HalpMcaProcessLog( mcaLog );
  800. if ( errorSeverity == ErrorFatal ) {
  801. //
  802. // We are now going down with a MACHINE_CHECK_EXCEPTION.
  803. // No return...
  804. //
  805. HalpMcaBugCheck( HAL_BUGCHECK_MCA_FATAL, mcaLog,
  806. mcaAllocatedLogSize,
  807. 0 );
  808. } else {
  809. //
  810. // Ideally we would have recovered the error at this point.
  811. // However we don't currently handle MCA error recovery
  812. // yet. Once we do then this "else clause" should be
  813. // deleted.
  814. //
  815. HalpMcaBugCheck( HAL_BUGCHECK_MCA_NONFATAL, mcaLog,
  816. mcaAllocatedLogSize,
  817. 0 );
  818. }
  819. rv = HalpClearStateInfo( MCA_EVENT );
  820. if ( !SAL_SUCCESSFUL(rv) ) {
  821. //
  822. // Current consideration for this implementation - 08/2000:
  823. // if clearing the event fails, we assume that FW has a real problem;
  824. // continuing will be dangerous. We bugcheck.
  825. //
  826. HalpMcaBugCheck( HAL_BUGCHECK_MCA_CLEAR_STATEINFO, mcaLog,
  827. mcaAllocatedLogSize,
  828. rv.ReturnValues[0] );
  829. }
  830. // SAL_STATUS_SUCCESS, SAL_STATUS_SUCCESS_MORE_RECORDS ... and
  831. // ErrorSeverity != ErrorFatal.
  832. //
  833. // Call the registered kernel handler.
  834. //
  835. // Thierry 08/2000 - FIXFIX:
  836. // The errorSeverity check is under comments. It should not be commented for the
  837. // final version. However, we wanted to have kernel notification if we are getting
  838. // log error severity != ErrorFatal or != ErrorRecoverable.
  839. if ( /* (errorSeverity == ErrorCorrected) && */
  840. ( HalpMcaInfo.KernelDelivery || HalpMcaInfo.DriverInfo.DpcCallback ) ) {
  841. InterlockedExchange( &HalpMcaInfo.DpcNotification, 1 );
  842. }
  843. break;
  844. case SAL_STATUS_NO_INFORMATION_AVAILABLE:
  845. //
  846. // The salStatus value will break the salStatus loop.
  847. //
  848. rv.ReturnValues[0] = SAL_STATUS_SUCCESS;
  849. break;
  850. case SAL_STATUS_SUCCESS_WITH_OVERFLOW:
  851. case SAL_STATUS_INVALID_ARGUMENT:
  852. case SAL_STATUS_ERROR:
  853. case SAL_STATUS_VA_NOT_REGISTERED:
  854. default: // Thierry 08/00: WARNING - SAL July 2000 - v2.90.
  855. // default includes possible unknown positive salStatus values.
  856. HalpMcaBugCheck( HAL_BUGCHECK_MCA_GET_STATEINFO, mcaLog,
  857. mcaAllocatedLogSize,
  858. salStatus );
  859. break;
  860. }
  861. }
  862. //
  863. // If we get here then one of two things have happened. Either the SAL
  864. // didn't return any records or we got a recoverable error, handled it, and
  865. // the HAL_BUGCHECK_MCA_NONFATAL bugcheck above in the SAL_STATUS_SUCCESS
  866. // case above has been removed.
  867. //
  868. // Once we add code to recover from MCAs and support returning to the SAL we
  869. // need to change this bugcheck so it is only called if we received no error
  870. // records in response to SAL_GET_STATEINFO.
  871. //
  872. HalpMcaBugCheck( HAL_BUGCHECK_MCA_NONFATAL, 0, 0, 0 );
  873. //
  874. // Currently 08/2000, we do not support the modification of the minstate.
  875. //
  876. mcaResources->OsToSalHandOff.MinStateSavePtr = mcaResources->SalToOsHandOff.MinStateSavePtr;
  877. mcaResources->OsToSalHandOff.Result = rv.ReturnValues[0];
  878. //
  879. // If error was corrected and MCA non-monarch processors are in rendez vous,
  880. // we will have to wake them up.
  881. //
  882. mcWakeUp = ( (rv.ReturnValues[0] == SAL_STATUS_SUCCESS) &&
  883. HalpSalRendezVousSucceeded( mcaResources->SalToOsHandOff ) );
  884. //
  885. // Release MCA spinlock protecting OS_MCA resources.
  886. //
  887. HalpOsMcaInProgress = 0;
  888. HalpReleaseMcaSpinLock( &HalpMcaSpinLock );
  889. if (raisedIrql)
  890. {
  891. KeLowerIrql(oldIrql);
  892. }
  893. //
  894. // If required, let's wake MCA non-monarch processors up.
  895. //
  896. if ( mcWakeUp ) {
  897. HalpMcWakeUp();
  898. }
  899. return( rv );
  900. } // HalpMcaHandler()
  901. //++
  902. // Name: HalpGetErrLogSize()
  903. //
  904. // Routine Description:
  905. //
  906. // This is a wrapper that will call SAL_GET_STATE_INFO_SIZE
  907. //
  908. // Arguments On Entry:
  909. // arg0 = Reserved
  910. // arg1 = Event Type (MCA,INIT,CMC,CPE)
  911. //
  912. // Returns
  913. // rtn0=Success/Failure (0/!0)
  914. // rtn1=Size
  915. //--
  916. SAL_PAL_RETURN_VALUES
  917. HalpGetErrLogSize( ULONGLONG Res,
  918. ULONGLONG eType
  919. )
  920. {
  921. SAL_PAL_RETURN_VALUES rv = {0};
  922. HalpSalCall(SAL_GET_STATE_INFO_SIZE, eType, 0,0,0,0,0,0, &rv);
  923. return(rv);
  924. }
  925. //EndProc//////////////////////////////////////////////////////////////////////
  926. //++
  927. // Name: HalpGetErrLog()
  928. //
  929. // Routine Description:
  930. //
  931. // This is a wrapper that will call SAL_GET_STATE_INFO
  932. //
  933. // Arguments On Entry:
  934. // arg0 = Reserved
  935. // arg1 = Event Type (MCA,INIT,CMC)
  936. // arg3 = pBuffer
  937. //
  938. // Success/Failure (0/!0)
  939. //--
  940. SAL_PAL_RETURN_VALUES
  941. HalpGetErrLog( ULONGLONG Res,
  942. ULONGLONG eType,
  943. ULONGLONG* pBuff
  944. )
  945. {
  946. SAL_PAL_RETURN_VALUES rv={0};
  947. HalpSalCall(SAL_GET_STATE_INFO, eType, 0, (ULONGLONG)pBuff, 0,0,0,0, &rv);
  948. //
  949. // Regardless of the call success or failure, fix the record to store
  950. // the processor number the SAL_PROC was executed on.
  951. // This feature is requested by WMI.
  952. //
  953. HalpSetFwMceLogProcessorNumber( (PERROR_RECORD_HEADER)pBuff );
  954. return(rv);
  955. }
  956. //EndProc//////////////////////////////////////////////////////////////////////
  957. //++
  958. // Name: HalpClrErrLog()
  959. //
  960. // Routine Description:
  961. //
  962. // This is a wrapper that will call SAL_CLEAR_STATE_INFO
  963. //
  964. // Arguments On Entry:
  965. // arg0 = Reserved
  966. // arg1 = Event Type (MCA,INIT,CMC,CPE)
  967. //
  968. // Success/Failure (0/!0)
  969. //--
  970. SAL_PAL_RETURN_VALUES
  971. HalpClrErrLog( ULONGLONG Res,
  972. ULONGLONG eType
  973. )
  974. {
  975. SAL_PAL_RETURN_VALUES rv={0};
  976. HalpSalCall( SAL_CLEAR_STATE_INFO, eType, 0,0,0,0,0,0, &rv );
  977. return(rv);
  978. }
  979. //EndProc//////////////////////////////////////////////////////////////////////
  980. //++
  981. // Name: HalpSalSetParams()
  982. //
  983. // Routine Description:
  984. //
  985. // This is a wrapper that will call SAL_MC_SET_PARAMS
  986. //
  987. // Arguments On Entry:
  988. // arg0 = Reserved
  989. // arg1 = Parameter Type (rendz. or wakeup)
  990. // arg2 = Event Type (interrupt/semaphore)
  991. // arg3 = Interrupt Vector or Memory Address
  992. // arg4 = Timeout value for rendezvous
  993. //
  994. // Success/Failure (0/!0)
  995. //--
  996. SAL_PAL_RETURN_VALUES
  997. HalpSalSetParams(ULONGLONG Res,
  998. ULONGLONG pType,
  999. ULONGLONG eType,
  1000. ULONGLONG VecAdd,
  1001. ULONGLONG tValue)
  1002. {
  1003. SAL_PAL_RETURN_VALUES rv={0};
  1004. HalpSalCall(SAL_MC_SET_PARAMS, pType, eType, VecAdd,tValue,0,0,0,&rv);
  1005. return(rv);
  1006. }
  1007. //EndProc//////////////////////////////////////////////////////////////////////
  1008. //++
  1009. // Name: HalpSalSetVectors()
  1010. //
  1011. // Routine Description:
  1012. //
  1013. // This is a wrapper that will call SAL_SET_VECTORS
  1014. //
  1015. // Arguments On Entry:
  1016. // arg0 = Reserved
  1017. // arg1 = Event Type (MCA, INIT..)
  1018. // arg2 = Physical Address of handler
  1019. // arg3 = gp
  1020. // arg4 = length of event handler in bytes
  1021. //
  1022. // Success/Failure (0/!0)
  1023. //--
  1024. SAL_PAL_RETURN_VALUES
  1025. HalpSalSetVectors( ULONGLONG Res,
  1026. ULONGLONG eType,
  1027. PHYSICAL_ADDRESS Addr,
  1028. ULONGLONG gpValue,
  1029. ULONGLONG szHndlr)
  1030. {
  1031. SAL_PAL_RETURN_VALUES rv={0};
  1032. if ( eType == InitEvent ) {
  1033. //
  1034. // Thierry 08/2000:
  1035. // Current implementation assumes that OS decides the monarch inside OS_INIT.
  1036. // This implies handler_2, gp_2, length_2 are identical to handler_1, gp_1, length_1.
  1037. //
  1038. HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue, szHndlr,
  1039. (ULONGLONG)Addr.QuadPart, gpValue, szHndlr, &rv);
  1040. }
  1041. else {
  1042. HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue,szHndlr,0,0,0,&rv);
  1043. }
  1044. return(rv);
  1045. }
  1046. //EndProc//////////////////////////////////////////////////////////////////////
  1047. //++
  1048. // Name: HalpSalRendz()
  1049. //
  1050. // Routine Description:
  1051. //
  1052. // This is a wrapper that will call SAL_MC_RENDEZ
  1053. //
  1054. // Arguments On Entry:
  1055. // arg0 = Reserved
  1056. //
  1057. // Success/Failure (0/!0)
  1058. //--
  1059. SAL_PAL_RETURN_VALUES
  1060. HalpSalRendz(void)
  1061. {
  1062. SAL_PAL_RETURN_VALUES rv={0};
  1063. HalpSalCall(SAL_MC_RENDEZ, 0, 0, 0,0,0,0,0,&rv);
  1064. return(rv);
  1065. }
  1066. VOID
  1067. HalpMcWakeUp(
  1068. VOID
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This function does IPI to wakeup the MC non-monarch processors.
  1073. Arguments:
  1074. None.
  1075. Return Value:
  1076. None.
  1077. Remarks:
  1078. This function is assumed to be executed on the MC monarch processor.
  1079. --*/
  1080. {
  1081. USHORT LogicalCpu;
  1082. USHORT ProcessorID;
  1083. USHORT monarchID;
  1084. //
  1085. // Scan the processor set and request an interprocessor interrupt on
  1086. // each of the specified targets.
  1087. //
  1088. monarchID = (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX];
  1089. for (LogicalCpu = 0; LogicalCpu < HalpMpInfo.ProcessorCount; LogicalCpu++) {
  1090. //
  1091. // Only IPI processors that are started.
  1092. //
  1093. if (HalpActiveProcessors & (1 << HalpProcessorInfo[LogicalCpu].NtProcessorNumber)) {
  1094. ProcessorID = HalpProcessorInfo[LogicalCpu].LocalApicID;
  1095. //
  1096. // Request interprocessor interrupt on target physicalCpu.
  1097. //
  1098. if ( ProcessorID != monarchID ) {
  1099. HalpSendIPI(ProcessorID, MC_WKUP_VECTOR);
  1100. }
  1101. }
  1102. }
  1103. } // HalpMcWakeUp()
  1104. VOID
  1105. HalpCMCEnable(
  1106. VOID
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. This routine sets the processor CMCV register with CMCI_VECTOR.
  1111. Arguments:
  1112. None.
  1113. Return Value:
  1114. None.
  1115. --*/
  1116. {
  1117. if ( HalpFeatureBits & HAL_CMC_PRESENT ) {
  1118. HalpWriteCMCVector( CMCI_VECTOR );
  1119. }
  1120. return;
  1121. } // HalpCMCEnable()
  1122. VOID
  1123. HalpCMCDisable(
  1124. VOID
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine resets the processor CMCV register.
  1129. Arguments:
  1130. None
  1131. Return Value:
  1132. None
  1133. --*/
  1134. {
  1135. HalpWriteCMCVector( 0x10000ui64 );
  1136. return;
  1137. } // HalpCMCDisable()
  1138. NTSTATUS
  1139. HalpGenerateCMCInterrupt(
  1140. VOID
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This routine is used for testing CMC processing. It is called indirectly
  1145. using HalSetSystemInformation.HalGenerateCmcInterrupt. The expectation is
  1146. that the caller has done whatever processing to simulate the error that the
  1147. SAL expects prior to calling this function.
  1148. Arguments:
  1149. CmcVector: CMC Vector value.
  1150. Value:
  1151. STATUS_SUCCESS
  1152. --*/
  1153. {
  1154. if (HalpFeatureBits & HAL_CMC_PRESENT) {
  1155. HalpSendIPI( (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX],
  1156. CMCI_VECTOR | DELIVER_FIXED);
  1157. return STATUS_SUCCESS;
  1158. }
  1159. return STATUS_NOT_SUPPORTED;
  1160. }
  1161. ULONG_PTR
  1162. HalpSetCMCVector(
  1163. IN ULONG_PTR CmcVector
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. This routine sets the processor CMCV register with specified vector.
  1168. This function is the broadcast function for HalpCMCDisableForAllProcessors().
  1169. Arguments:
  1170. CmcVector: CMC Vector value.
  1171. Value:
  1172. STATUS_SUCCESS
  1173. --*/
  1174. {
  1175. HalpWriteCMCVector( (ULONG64)CmcVector );
  1176. return((ULONG_PTR)(ULONG)(STATUS_SUCCESS));
  1177. } // HalpSetCmcVector()
  1178. VOID
  1179. HalpCMCDisableForAllProcessors(
  1180. VOID
  1181. )
  1182. /*++
  1183. Routine Description:
  1184. This routine disables processor CMC on every processor in the host configuration
  1185. by executing HalpSetCmcVector( 0ui64 ) on every processor in a synchronous manner.
  1186. Arguments:
  1187. None.
  1188. Value:
  1189. None.
  1190. --*/
  1191. {
  1192. //
  1193. // Can not do an IPI if the processors are above IPI level such
  1194. // as we are in the kernel debugger.
  1195. //
  1196. if (KeGetCurrentIrql() < IPI_LEVEL) {
  1197. (VOID)KiIpiGenericCall( HalpSetCMCVector, (ULONG_PTR)0x10000ui64 );
  1198. } else {
  1199. HalpSetCMCVector(0x10000ui64);
  1200. }
  1201. return;
  1202. } // HalpCMCDisableForAllProcessors()
  1203. VOID
  1204. HalpCMCIHandler (
  1205. IN PKINTERRUPT_ROUTINE Interrupt,
  1206. IN PKTRAP_FRAME TrapFrame
  1207. )
  1208. /*++
  1209. Routine Description:
  1210. Processor Interrupt routine for CMC interrupts.
  1211. Arguments:
  1212. TrapFrame - Captured trap frame address.
  1213. Return Parameters:
  1214. None.
  1215. Notes:
  1216. Thierry 08/2000:
  1217. This function does not do much, it flags the PCR InOsCmc field
  1218. and calls the second-level handler: HalpCmcHandler().
  1219. However, this was implmented this way so this function abstracts the
  1220. standard interrupts resources from the purely CMC processing in HalpCmcHandler().
  1221. --*/
  1222. {
  1223. volatile KPCR * const pcr = KeGetPcr();
  1224. pcr->InOsCmc = TRUE;
  1225. HalpCmcHandler();
  1226. pcr->InOsCmc = FALSE;
  1227. return;
  1228. } // HalpCMCIHandler()
  1229. VOID
  1230. HalpCmcProcessLog(
  1231. PCMC_EXCEPTION CmcLog
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. This function does a simple processing check a IA64 CMC log.
  1236. Arguments:
  1237. CmcLog - Provides CMC log address
  1238. Return Parameters:
  1239. None.
  1240. Notes:
  1241. Currently simply checking and outputing log contents for checked hal only.
  1242. --*/
  1243. {
  1244. #if DBG
  1245. //
  1246. // Simple log processing for first debugging...
  1247. //
  1248. GUID processorDeviceGuid = ERROR_PROCESSOR_GUID;
  1249. BOOLEAN processorDeviceFound;
  1250. PERROR_RECORD_HEADER header = (PERROR_RECORD_HEADER)CmcLog;
  1251. PERROR_SECTION_HEADER section, sectionMax;
  1252. if ( header->ErrorSeverity != ErrorCorrected ) {
  1253. HalDebugPrint(( HAL_ERROR,
  1254. "HAL!HalpCmcProcessLog: CMC record with severity [%d] != corrected!!!\n",
  1255. header->ErrorSeverity ));
  1256. }
  1257. //
  1258. // SAL spec BUGBUG 08/2000: we should have put the length of the header in the definition.
  1259. // Same for section header.
  1260. //
  1261. processorDeviceFound = FALSE;
  1262. section = (PERROR_SECTION_HEADER)((ULONG_PTR)header + sizeof(*header));
  1263. sectionMax = (PERROR_SECTION_HEADER)((ULONG_PTR)header + header->Length);
  1264. while( section < sectionMax ) {
  1265. if ( IsEqualGUID( &section->Guid, &processorDeviceGuid ) ) {
  1266. PERROR_PROCESSOR processorRecord = (PERROR_PROCESSOR)section;
  1267. processorDeviceFound = TRUE;
  1268. //
  1269. // Minimum processing here. This will enhance with testing and most common
  1270. // occurences.
  1271. //
  1272. if ( processorRecord->Valid.StateParameter ) {
  1273. ULONGLONG stateParameter = processorRecord->StateParameter.StateParameter;
  1274. //
  1275. // At any time more than one error could be valid
  1276. //
  1277. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_SHIFT) &
  1278. ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_MASK) {
  1279. //
  1280. // cache error
  1281. //
  1282. HalDebugPrint(( HAL_INFO,
  1283. "HAL!HalpCmcProcessLog: Corrected Processor CACHE Machine Check error\n" ));
  1284. }
  1285. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_SHIFT) &
  1286. ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_MASK) {
  1287. //
  1288. // tlb error
  1289. //
  1290. HalDebugPrint(( HAL_INFO,
  1291. "HAL!HalpCmcProcessLog: Corrected Processor TLB Machine Check error\n" ));
  1292. }
  1293. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_SHIFT) &
  1294. ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_MASK) {
  1295. //
  1296. // bus error
  1297. //
  1298. HalDebugPrint(( HAL_INFO,
  1299. "HAL!HalpCmcProcessLog: Corrected Processor BUS Machine Check error\n" ));
  1300. }
  1301. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_SHIFT) &
  1302. ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_MASK) {
  1303. //
  1304. // unknown error
  1305. //
  1306. HalDebugPrint(( HAL_INFO,
  1307. "HAL!HalpCmcProcessLog: Corrected Processor UNKNOWN Machine Check error\n" ));
  1308. }
  1309. }
  1310. }
  1311. }
  1312. if ( !processorDeviceFound ) {
  1313. HalDebugPrint(( HAL_ERROR,
  1314. "HAL!HalpCmcProcessLog: CMC log without processor device record!!!\n"));
  1315. }
  1316. #endif // DBG
  1317. return;
  1318. } // HalpCmcProcessLog()
  1319. //++
  1320. // Name: HalpCmcHandler()
  1321. //
  1322. // Routine Description:
  1323. //
  1324. // This is the second level CMC Interrupt Handler for FW corrected errors.
  1325. //
  1326. // Arguments On Entry:
  1327. // None.
  1328. //
  1329. // Return.
  1330. // None.
  1331. //
  1332. // Notes:
  1333. // This function calls the kernel notification and inserts the OEM CMC driver dpc if
  1334. // registered.
  1335. // Accessing the CMC logs at this level could be inacceptable because of the possible
  1336. // large size of the logs and the time required to collect them.
  1337. // The collection of the logs is delayed until the work item calls
  1338. // HalQuerySystemInformation.HalCmcLogInformation.
  1339. //--
  1340. VOID
  1341. HalpCmcHandler(
  1342. VOID
  1343. )
  1344. {
  1345. LARGE_INTEGER CurrentTime;
  1346. //
  1347. // Internal housekeeping.
  1348. //
  1349. InterlockedIncrement( &HalpCmcInfo.Stats.CmcInterruptCount );
  1350. //
  1351. // Notify the kernel if registered.
  1352. //
  1353. if ( HalpCmcInfo.KernelDelivery ) {
  1354. if ( !HalpCmcInfo.KernelDelivery( HalpCmcInfo.KernelToken, CmcAvailable, NULL ) ) {
  1355. InterlockedIncrement( &HalpCmcInfo.Stats.KernelDeliveryFails );
  1356. }
  1357. }
  1358. //
  1359. // Notify the OEM CMC driver if registered.
  1360. //
  1361. if ( HalpCmcInfo.DriverInfo.DpcCallback ) {
  1362. if ( !KeInsertQueueDpc( &HalpCmcInfo.DriverDpc, NULL, NULL ) ) {
  1363. InterlockedIncrement( &HalpCmcInfo.Stats.DriverDpcQueueFails );
  1364. }
  1365. }
  1366. //
  1367. // Now check if we are receiving CMC more frequently than our
  1368. // threshold and if so call kernel to switch to polled mode
  1369. //
  1370. if (HalpCmcInfo.ThresholdMaximum != 0)
  1371. {
  1372. CurrentTime = KeQueryPerformanceCounter(NULL);
  1373. KiAcquireSpinLock(&HalpCmcSpinLock);
  1374. if (HalpCmcInfo.Stats.PollingInterval == HAL_CMC_INTERRUPTS_BASED)
  1375. {
  1376. if ( (CurrentTime.QuadPart - HalpCmcInfo.LastTime.QuadPart) < HalpCmcInfo.ThresholdTime.QuadPart)
  1377. {
  1378. if (++HalpCmcInfo.ThresholdCounter > HalpCmcInfo.ThresholdMaximum)
  1379. {
  1380. //
  1381. // We have crossed the threshold so we need to
  1382. // downgrade to polling mode. We switch down to polling
  1383. // every 60 seconds as per the Intel Itanium Error
  1384. // Handling guide
  1385. //
  1386. HalpCmcInfo.Stats.PollingInterval = HALP_CMC_DEFAULT_POLLING_INTERVAL;
  1387. KiReleaseSpinLock(&HalpCmcSpinLock);
  1388. HalpCMCDisableForAllProcessors();
  1389. if (HalpCmcInfo.KernelDelivery != NULL) {
  1390. HalpCmcInfo.KernelDelivery( HalpCmcInfo.KernelToken,
  1391. CmcSwitchToPolledMode,
  1392. (PVOID)UlongToPtr(HalpCmcInfo.Stats.PollingInterval) );
  1393. }
  1394. } else {
  1395. KiReleaseSpinLock(&HalpCmcSpinLock);
  1396. }
  1397. } else {
  1398. HalpCmcInfo.LastTime = CurrentTime;
  1399. HalpCmcInfo.ThresholdCounter = 0;
  1400. KiReleaseSpinLock(&HalpCmcSpinLock);
  1401. }
  1402. } else {
  1403. KiReleaseSpinLock(&HalpCmcSpinLock);
  1404. }
  1405. }
  1406. } // HalpCmcHandler()
  1407. //EndProc//////////////////////////////////////////////////////////////////////
  1408. //++
  1409. // Name: HalpCpeHandler()
  1410. //
  1411. // Routine Description:
  1412. //
  1413. // This is the second level CPE Interrupt Handler for Platform corrected errors.
  1414. //
  1415. // Arguments On Entry:
  1416. // None.
  1417. //
  1418. // Return.
  1419. // None.
  1420. //
  1421. // Notes:
  1422. // This function calls the kernel notification and inserts the OEM CPE driver dpc if
  1423. // registered.
  1424. // Accessing the CPE logs at this level could be inacceptable because of the possible
  1425. // large size of the logs and the time required to collect them.
  1426. // The collection of the logs is delayed until the work item calls
  1427. // HalQuerySystemInformation.HalCpeLogInformation.
  1428. //--
  1429. VOID
  1430. HalpCpeHandler(
  1431. VOID
  1432. )
  1433. {
  1434. LARGE_INTEGER CurrentTime;
  1435. KIRQL Irql;
  1436. //
  1437. // Internal housekeeping.
  1438. //
  1439. InterlockedIncrement( &HalpCpeInfo.Stats.CpeInterruptCount );
  1440. //
  1441. // Disable further CPE interrupts. We have to do this now because WMI
  1442. // doesn't call SAL_GET_STATE_INFO until much later and the SAL routine
  1443. // is what actually resets the LEVEL triggered interrupt source.
  1444. //
  1445. // We will reenable interrupts on the way back out of the HalpClrErrLog
  1446. // call.
  1447. //
  1448. HalpCPEDisable();
  1449. //
  1450. // Notify the kernel if registered.
  1451. //
  1452. if ( HalpCpeInfo.KernelDelivery ) {
  1453. if ( !HalpCpeInfo.KernelDelivery( HalpCpeInfo.KernelToken, CpeAvailable, NULL ) ) {
  1454. InterlockedIncrement( &HalpCpeInfo.Stats.KernelDeliveryFails );
  1455. }
  1456. }
  1457. //
  1458. // Notify the OEM CPE driver if registered.
  1459. //
  1460. if ( HalpCpeInfo.DriverInfo.DpcCallback ) {
  1461. if ( !KeInsertQueueDpc( &HalpCpeInfo.DriverDpc, NULL, NULL ) ) {
  1462. InterlockedIncrement( &HalpCpeInfo.Stats.DriverDpcQueueFails );
  1463. }
  1464. }
  1465. //
  1466. // Now check if we are receiving Cpe more frequently than our
  1467. // threshold and if so call kernel to switch to polled mode
  1468. //
  1469. if (HalpCpeInfo.ThresholdMaximum != 0)
  1470. {
  1471. CurrentTime = KeQueryPerformanceCounter(NULL);
  1472. KiAcquireSpinLock(&HalpCpeSpinLock);
  1473. if (HalpCpeInfo.Stats.PollingInterval == HAL_CPE_INTERRUPTS_BASED)
  1474. {
  1475. if ( (CurrentTime.QuadPart - HalpCpeInfo.LastTime.QuadPart) < HalpCpeInfo.ThresholdTime.QuadPart)
  1476. {
  1477. if (++HalpCpeInfo.ThresholdCounter > HalpCpeInfo.ThresholdMaximum)
  1478. {
  1479. //
  1480. // We have crossed the threshold so we need to
  1481. // downgrade to polling mode. We switch down to polling
  1482. // every 60 seconds as per the Intel Itanium Error
  1483. // Handling guide
  1484. //
  1485. HalpCpeInfo.Stats.PollingInterval = HALP_CPE_DEFAULT_POLLING_INTERVAL;
  1486. KiReleaseSpinLock(&HalpCpeSpinLock);
  1487. if (HalpCpeInfo.KernelDelivery != NULL) {
  1488. HalpCpeInfo.KernelDelivery( HalpCpeInfo.KernelToken,
  1489. CpeSwitchToPolledMode,
  1490. (PVOID)UlongToPtr(HalpCpeInfo.Stats.PollingInterval) );
  1491. }
  1492. } else {
  1493. KiReleaseSpinLock(&HalpCpeSpinLock);
  1494. }
  1495. } else {
  1496. HalpCpeInfo.LastTime = CurrentTime;
  1497. HalpCpeInfo.ThresholdCounter = 0;
  1498. KiReleaseSpinLock(&HalpCpeSpinLock);
  1499. }
  1500. } else {
  1501. KiReleaseSpinLock(&HalpCpeSpinLock);
  1502. }
  1503. }
  1504. } // HalpCpeHandler()
  1505. //EndProc//////////////////////////////////////////////////////////////////////
  1506. VOID
  1507. HalpMcRzHandler (
  1508. IN PKINTERRUPT_ROUTINE Interrupt,
  1509. IN PKTRAP_FRAME TrapFrame
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. Arguements:
  1514. Return Parameters:
  1515. --*/
  1516. {
  1517. SAL_PAL_RETURN_VALUES rv={0};
  1518. HalpDisableInterrupts();
  1519. rv=HalpSalRendz();
  1520. HalpEnableInterrupts();
  1521. // do any Isr clean up and re-enable the interrupts & MC's
  1522. return;
  1523. }
  1524. //EndProc//////////////////////////////////////////////////////////////////////
  1525. VOID
  1526. HalpMcWkupHandler (
  1527. IN PKINTERRUPT_ROUTINE Interrupt,
  1528. IN PKTRAP_FRAME TrapFrame
  1529. )
  1530. /*++
  1531. Routine Description:
  1532. Arguements:
  1533. Return Parameters:
  1534. --*/
  1535. {
  1536. return;
  1537. }
  1538. //EndProc//////////////////////////////////////////////////////////////////////
  1539. VOID
  1540. HalpCPEIHandler (
  1541. IN PKINTERRUPT_ROUTINE Interrupt,
  1542. IN PKTRAP_FRAME TrapFrame
  1543. )
  1544. /*++
  1545. Routine Description:
  1546. Processor Interrupt routine for CPE interrupts.
  1547. Arguments:
  1548. TrapFrame - Captured trap frame address.
  1549. Return Parameters:
  1550. None.
  1551. Notes:
  1552. Thierry 08/2000:
  1553. This function does not do much, it flags the PCR InOsCpe field
  1554. and calls the second-level handler: HalpCpeHandler().
  1555. However, this was implmented this way so this function abstracts the
  1556. standard interrupts resources from the purely CPE processing in HalpCpeHandler().
  1557. --*/
  1558. {
  1559. volatile KPCR * const pcr = KeGetPcr();
  1560. pcr->InOsCpe = TRUE;
  1561. HalpCpeHandler();
  1562. pcr->InOsCpe = FALSE;
  1563. return;
  1564. } // HalpCPEIHandler()
  1565. VOID
  1566. HalpCPEEnable (
  1567. VOID
  1568. )
  1569. /*++
  1570. Routine Description:
  1571. This routine sets the default HAL CPE handling regardless of the user specified
  1572. registry setting. It enables the supported Platform Interrupt sources and
  1573. exposes the initial interrupt/polling based mode used for CPE.
  1574. The user specified registry setting is handled via HalpMcaInit() at the end of
  1575. phase 1.
  1576. Arguments:
  1577. None.
  1578. Return Parameters:
  1579. None.
  1580. Implementation Notes:
  1581. The following implementation assumes that this code is executed on BSP.
  1582. --*/
  1583. {
  1584. ULONG i;
  1585. if ( HalpFeatureBits & HAL_CPE_PRESENT ) {
  1586. ULONG maxCPE = HalpMaxCPEImplemented;
  1587. if ( maxCPE ) {
  1588. //
  1589. // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags,
  1590. // HalpCPEIoSapicVector.
  1591. //
  1592. for (i=0 ; i != maxCPE; i++ ) {
  1593. HalpEnableRedirEntry( HalpCPEIntIn[i] );
  1594. }
  1595. //
  1596. // Initialize the remaining fields of HAL private CPE info structure.
  1597. //
  1598. HalpCpeInfo.Stats.PollingInterval = HAL_CPE_INTERRUPTS_BASED;
  1599. }
  1600. else {
  1601. //
  1602. // We will implement Polling model.
  1603. //
  1604. HalpCpeInfo.Stats.PollingInterval = HALP_CPE_DEFAULT_POLLING_INTERVAL;
  1605. }
  1606. }
  1607. else {
  1608. HalpCpeInfo.Stats.PollingInterval = HAL_CPE_DISABLED;
  1609. }
  1610. } // HalpCPEEnable()
  1611. VOID
  1612. HalpCPEDisable (
  1613. VOID
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. This routine disables the SAPIC Platform Interrupt Sources.
  1618. Note that if HalpMaxCPEImplemented is 0, the function does nothing.
  1619. Arguments:
  1620. None.
  1621. Return Parameters:
  1622. None.
  1623. --*/
  1624. {
  1625. //
  1626. // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags,
  1627. // HalpCPEIoSapicVector
  1628. ULONG i;
  1629. for (i=0; i < HalpMaxCPEImplemented; i++) {
  1630. HalpDisableRedirEntry(HalpCPEIntIn[i]);
  1631. }
  1632. } // HalpCPEDisable()
  1633. VOID
  1634. HalpMCADisable(
  1635. VOID
  1636. )
  1637. {
  1638. PHYSICAL_ADDRESS NULL_PHYSICAL_ADDRESS = {0};
  1639. SAL_PAL_RETURN_VALUES rv = {0};
  1640. char Lid;
  1641. ULONGLONG gp_reg = GetGp();
  1642. // Disable CMCs
  1643. HalpCMCDisableForAllProcessors();
  1644. // Disable CPE Interrupts
  1645. HalpCPEDisable();
  1646. //DeRegister Rendez. Paramters with SAL
  1647. #define NULL_VECTOR 0xF
  1648. rv = HalpSalSetParams(0,RendzType, IntrVecType, NULL_VECTOR, HalpMcRendezTimeOut );
  1649. // Deregister WakeUp parameters with SAL
  1650. rv=HalpSalSetParams(0, WakeUpType, IntrVecType, NULL_VECTOR,0);
  1651. // Deregister OsMcaDispatch (OS_MCA) physical address with SAL
  1652. rv=HalpSalSetVectors(0, MchkEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0);
  1653. // Deregister OsInitDispatch physical address with SAL
  1654. rv=HalpSalSetVectors(0, InitEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0);
  1655. } // HalpMCADisable()
  1656. NTSTATUS
  1657. HalpGetMceInformation(
  1658. PHAL_ERROR_INFO ErrorInfo,
  1659. PULONG ErrorInfoLength
  1660. )
  1661. /*++
  1662. Routine Description:
  1663. This routine is called by HaliQuerySystemInformation for the HalErrorInformation class.
  1664. Arguments:
  1665. ErrorInfo : pointer to HAL_ERROR_INFO structure.
  1666. ErrorInfoLength : size of the valid memory structure pointed by ErrorInfo.
  1667. Return Value:
  1668. STATUS_SUCCESS if successful
  1669. error status otherwise
  1670. --*/
  1671. {
  1672. NTSTATUS status;
  1673. ULONG cpePollingInterval;
  1674. PAGED_CODE();
  1675. ASSERT( ErrorInfo );
  1676. ASSERT( ErrorInfoLength );
  1677. //
  1678. // Backward compatibility only.
  1679. //
  1680. if ( !ErrorInfo->Version || ( ErrorInfo->Version > HAL_ERROR_INFO_VERSION ) ) {
  1681. return( STATUS_REVISION_MISMATCH );
  1682. }
  1683. //
  1684. // Zero Reserved field.
  1685. //
  1686. ErrorInfo->Reserved = 0;
  1687. //
  1688. // Collect MCA info under protection if required.
  1689. //
  1690. ErrorInfo->McaMaxSize = HalpMcaInfo.Stats.MaxLogSize;
  1691. ErrorInfo->McaPreviousEventsCount = HalpMcaInfo.Stats.McaPreviousCount;
  1692. ErrorInfo->McaCorrectedEventsCount = HalpMcaInfo.Stats.McaCorrectedCount; // approximation.
  1693. ErrorInfo->McaKernelDeliveryFails = HalpMcaInfo.Stats.KernelDeliveryFails; // approximation.
  1694. ErrorInfo->McaDriverDpcQueueFails = HalpMcaInfo.Stats.DriverDpcQueueFails; // approximation.
  1695. ErrorInfo->McaReserved = 0;
  1696. //
  1697. // Collect CMC info under protection if required.
  1698. //
  1699. ErrorInfo->CmcMaxSize = HalpCmcInfo.Stats.MaxLogSize;
  1700. ErrorInfo->CmcPollingInterval = HalpCmcInfo.Stats.PollingInterval;
  1701. ErrorInfo->CmcInterruptsCount = HalpCmcInfo.Stats.CmcInterruptCount; // approximation.
  1702. ErrorInfo->CmcKernelDeliveryFails = HalpCmcInfo.Stats.KernelDeliveryFails; // approximation.
  1703. ErrorInfo->CmcDriverDpcQueueFails = HalpCmcInfo.Stats.DriverDpcQueueFails; // approximation.
  1704. HalpAcquireCmcMutex();
  1705. ErrorInfo->CmcGetStateFails = HalpCmcInfo.Stats.GetStateFails;
  1706. ErrorInfo->CmcClearStateFails = HalpCmcInfo.Stats.ClearStateFails;
  1707. ErrorInfo->CmcLogId = HalpCmcInfo.Stats.LogId;
  1708. HalpReleaseCmcMutex();
  1709. ErrorInfo->CmcReserved = 0;
  1710. //
  1711. // Collect CPE info under protection if required.
  1712. //
  1713. ErrorInfo->CpeMaxSize = HalpCpeInfo.Stats.MaxLogSize;
  1714. ErrorInfo->CpePollingInterval = HalpCpeInfo.Stats.PollingInterval;
  1715. ErrorInfo->CpeInterruptsCount = HalpCpeInfo.Stats.CpeInterruptCount; // approximation.
  1716. ErrorInfo->CpeKernelDeliveryFails = HalpCpeInfo.Stats.KernelDeliveryFails; // approximation.
  1717. ErrorInfo->CpeDriverDpcQueueFails = HalpCpeInfo.Stats.DriverDpcQueueFails; // approximation.
  1718. HalpAcquireCpeMutex();
  1719. ErrorInfo->CpeGetStateFails = HalpCpeInfo.Stats.GetStateFails;
  1720. ErrorInfo->CpeClearStateFails = HalpCpeInfo.Stats.ClearStateFails;
  1721. ErrorInfo->CpeLogId = HalpCpeInfo.Stats.LogId;
  1722. HalpReleaseCpeMutex();
  1723. // CpeInterruptSources: Number of SAPIC Platform Interrup Sources supported by HAL.
  1724. ErrorInfo->CpeInterruptSources = HalpMaxCPEImplemented;
  1725. //
  1726. // Update KernelTokens
  1727. //
  1728. ErrorInfo->McaKernelToken = (ULONGLONG) HalpMcaInfo.KernelToken;
  1729. ErrorInfo->CmcKernelToken = (ULONGLONG) HalpCmcInfo.KernelToken;
  1730. ErrorInfo->CpeKernelToken = (ULONGLONG) HalpCpeInfo.KernelToken;
  1731. ErrorInfo->KernelReserved[3] = (ULONGLONG) 0;
  1732. *ErrorInfoLength = sizeof(*ErrorInfo);
  1733. return( STATUS_SUCCESS );
  1734. } // HalpGetMceInformation()