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.

1994 lines
53 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 and APs, 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. rv = HalpGetStateInfoSize( CMC_EVENT );
  437. if ( !SAL_SUCCESSFUL( rv ) ) {
  438. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CMC failed...\n" ));
  439. return FALSE;
  440. }
  441. HalpCmcInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1];
  442. HalpCmcInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN;
  443. HalpCmcInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount;
  444. HalpCmcInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount;
  445. HalpCmcInfo.Stats.PollingInterval = HAL_CMC_INTERRUPTS_BASED;
  446. rv = HalpGetStateInfoSize( CPE_EVENT );
  447. if ( !SAL_SUCCESSFUL( rv ) ) {
  448. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_GET_STATE_INFO_SIZE.CPE failed...\n" ));
  449. return FALSE;
  450. }
  451. HalpCpeInfo.Stats.MaxLogSize = (ULONG)rv.ReturnValues[1];
  452. HalpCpeInfo.KernelToken = (PVOID)(ULONG_PTR)HALP_KERNEL_TOKEN;
  453. HalpCpeInfo.KernelLogs.MaxCount = HalpMceLogsMaxCount;
  454. HalpCpeInfo.DriverLogs.MaxCount = HalpMceLogsMaxCount;
  455. //
  456. // Register OsMcaDispatch (OS_MCA) physical address with SAL
  457. //
  458. gp_reg = GetGp();
  459. rv = HalpSalSetVectors(0, MchkEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsMcaDispatch1)->fPtr)), gp_reg,0);
  460. if ( !SAL_SUCCESSFUL(rv) ) {
  461. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.MCA vector failed...\n" ));
  462. return FALSE;
  463. }
  464. //
  465. // Register OsInitDispatch physical address with SAL
  466. //
  467. rv = HalpSalSetVectors(0, InitEvent, MmGetPhysicalAddress((fptr)(((PLabel*)HalpOsInitDispatch)->fPtr)), gp_reg,0);
  468. if ( !SAL_SUCCESSFUL(rv) ) {
  469. HalDebugPrint(( HAL_ERROR, "HAL!HalpInitializeOSMCA: SAL_SET_VECTOR.INIT vector failed...\n" ));
  470. return FALSE;
  471. }
  472. return TRUE;
  473. } // HalpInitializeOSMCA()
  474. //EndProc//////////////////////////////////////////////////////////////////////
  475. VOID
  476. HalpMcaBugCheck(
  477. ULONG McaBugCheckType,
  478. PMCA_EXCEPTION McaLog,
  479. ULONGLONG McaAllocatedLogSize,
  480. ULONGLONG SalStatus
  481. )
  482. //++
  483. // Name: HalpMcaBugCheck()
  484. //
  485. // Routine Description:
  486. //
  487. // This function is called to bugcheck the system in a case of a fatal MCA
  488. // or fatal FW interface errors. The OS must guarantee as much as possible
  489. // error containment in this path.
  490. // With the current implementation, this function should be only called from
  491. // the OS_MCA path. For other MCA specific wrappers of KeBugCheckEx, one should
  492. // HalpMcaKeBugCheckEx().
  493. //
  494. // Arguments On Entry:
  495. // ULONG McaBugCheckType
  496. // PMCA_EXCEPTION McaLog
  497. // ULONGLONG McaAllocatedLogSize
  498. // ULONGLONG SalStatus
  499. //
  500. // Return:
  501. // None.
  502. //
  503. // Implementation notes:
  504. // This code CANNOT [as default rules - at least entry and through fatal MCAs handling]
  505. // - make any system call
  506. // - attempt to acquire any spinlock used by any code outside the MCA handler
  507. // - change the interrupt state.
  508. // Passing data to non-MCA code must be done using manual semaphore instructions.
  509. // This code should minimize the path and the global or memory allocated data accesses.
  510. // This code should only access MCA-namespace structures.
  511. // This code is called under the MP protection of HalpMcaSpinLock and with the flag
  512. // HalpOsMcaInProgress set.
  513. //
  514. //--
  515. {
  516. if ( HalpOsMcaInProgress ) {
  517. //
  518. // Enable InbvDisplayString calls to make it through to bootvid driver.
  519. //
  520. if ( InbvIsBootDriverInstalled() ) {
  521. InbvAcquireDisplayOwnership();
  522. InbvResetDisplay();
  523. InbvSolidColorFill(0,0,639,479,4); // make the screen blue
  524. InbvSetTextColor(15);
  525. InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL);
  526. InbvEnableDisplayString(TRUE); // enable display string
  527. InbvSetScrollRegion(0,0,639,479); // set to use entire screen
  528. }
  529. HalDisplayString (MSG_MCA_HARDWARE_ERROR);
  530. HalDisplayString (MSG_HARDWARE_ERROR2);
  531. //
  532. // Thierry 09/2000:
  533. //
  534. // - if desired, process the MCA log HERE...
  535. //
  536. // and use HalDisplayString() to dump info for the field or hardware vendor.
  537. // The processing could be based on processor or platform independent record definitions.
  538. //
  539. HalDisplayString( MSG_HALT );
  540. if ( HalpMcaInfo.NoBugCheck == 0 ) {
  541. KeBugCheckEx( MACHINE_CHECK_EXCEPTION, (ULONG_PTR)McaBugCheckType,
  542. (ULONG_PTR)McaLog,
  543. (ULONG_PTR)McaAllocatedLogSize,
  544. (ULONG_PTR)SalStatus );
  545. }
  546. }
  547. if ( ((*KdDebuggerNotPresent) == FALSE) && ((*KdDebuggerEnabled) != FALSE) ) {
  548. KeEnterKernelDebugger();
  549. }
  550. while( TRUE ) {
  551. //
  552. ; // Simply sit here so the MCA HARDWARE ERROR screen does not get corrupted...
  553. //
  554. }
  555. // noreturn
  556. } // HalpMcaBugCheck()
  557. ERROR_SEVERITY
  558. HalpMcaProcessLog(
  559. PMCA_EXCEPTION McaLog
  560. )
  561. //++
  562. // Name: HalpMcaProcessLog()
  563. //
  564. // Routine Description:
  565. //
  566. // This function is called to process the MCA event log in the OS_MCA path.
  567. //
  568. // Arguments On Entry:
  569. // PMCA_EXCEPTION McaLog - Pointer to the MCA event log.
  570. //
  571. // Return:
  572. // ERROR_SEVERITY
  573. //
  574. // Implementation notes:
  575. // This code CANNOT [as default rules]
  576. // - make any system call
  577. // - attempt to acquire any spinlock used by any code outside the MCA handler
  578. // - change the interrupt state.
  579. // Passing data to non-MCA code must be done using manual semaphore instructions.
  580. // This code should minimize the path and the global or memory allocated data accesses.
  581. // This code should only access MCA-namespace structures.
  582. // This code is called under the MP protection of HalpMcaSpinLock and with the flag
  583. // HalpOsMcaInProgress set.
  584. //
  585. //--
  586. {
  587. ERROR_SEVERITY mcaSeverity;
  588. mcaSeverity = McaLog->ErrorSeverity;
  589. switch( mcaSeverity ) {
  590. case ErrorFatal:
  591. break;
  592. case ErrorRecoverable:
  593. //
  594. // Thierry - FIXFIX 08/2000:
  595. //
  596. ///////////////////////////////////////////////////////////////
  597. //
  598. // Call to kernel supported recovery will be here....
  599. //
  600. ///////////////////////////////////////////////////////////////
  601. //
  602. // However, for now we do not recover so flag it as ErrorFatal.
  603. mcaSeverity = ErrorFatal;
  604. break;
  605. case ErrorCorrected:
  606. default:
  607. //
  608. // These ERRROR_SEVERITY values have no HAL MCA specific handling.
  609. // As specified by the SAL Specs July 2000, we should not get these values in this path.
  610. //
  611. break;
  612. }
  613. //
  614. // If OEM driver has registered an exception callback for MCA event,
  615. // call it here and save returned error severity value.
  616. //
  617. if ( HalpMcaInfo.DriverInfo.ExceptionCallback ) {
  618. mcaSeverity = HalpMcaInfo.DriverInfo.ExceptionCallback(
  619. HalpMcaInfo.DriverInfo.DeviceContext,
  620. McaLog );
  621. }
  622. //
  623. // Save corrected log for future kernel notification.
  624. //
  625. if ( (HalpMcaInfo.KernelDelivery) && (mcaSeverity == ErrorCorrected) ) {
  626. InterlockedIncrement( &HalpMcaInfo.Stats.McaCorrectedCount );
  627. #if 0
  628. //
  629. // Thierry - 09/16/2000: ToBeDone.
  630. // Saving the corrected MCA log records requires careful rendez-vous configuration
  631. // handling, possible OS_MCA monarch selection, MCA logs (pre-)allocations and
  632. // special locking in case a consumer accesses the logs queue on another processor.
  633. //
  634. // The kernel-WMI and/or OEM MCA driver notification is done in HalpMcaHandler().
  635. //
  636. if ( !HalpSaveCorrectedMcaLog( McaLog ) ) {
  637. InterlockedIncrement( &HalpMcaInfo.CorrectedLogsLost );
  638. }
  639. #endif // 0
  640. //
  641. // The kernel-WMI and/or OEM MCA driver notification for corrected MCA event
  642. // is done in HalpMcaHandler().
  643. //
  644. }
  645. //
  646. // Thierry 10/17/2000 BUGBUG
  647. //
  648. // The FW does not save the MCA log in NVRAM and we have no official date from Intel
  649. // when the SAL will be doing it.
  650. // So for now, return as ErrorFatal and let dump the log through the debugger.
  651. //
  652. // Before Sal Rev <ToBeDetermined>, the error logs were completely erroneous...
  653. //
  654. if ( HalpSalPalData.SalRevision.Revision < HALP_SAL_REVISION_MAX ) {
  655. return( ErrorFatal );
  656. }
  657. else {
  658. return( mcaSeverity );
  659. }
  660. } // HalpMcaProcessLog()
  661. SAL_PAL_RETURN_VALUES
  662. HalpMcaHandler(
  663. ULONG64 RendezvousState,
  664. PPAL_MINI_SAVE_AREA Pmsa
  665. )
  666. //++
  667. // Name: HalpMcaHandler()
  668. //
  669. // Routine Description:
  670. //
  671. // This is the OsMca handler for firmware uncorrected errors
  672. // It is our option to run this in physical or virtual mode.
  673. //
  674. // Arguments On Entry:
  675. // None.
  676. //
  677. // Conditions On Entry: 09/2000 implementation.
  678. // - PSR state: at least,
  679. // PSR.dt = 1, PSR.it = 1, PSR.rt = 1 - virtual mode.
  680. // PSR.ic = 1, PSR.i = 0 - Interruption resources collection enabled,
  681. // Interrupts off.
  682. // PSR.mc = 1 - MCA masked for this processor.
  683. // - SalToOsHndOff initialized.
  684. // - s0 = MinStatePtr.
  685. // - s1 = IA64 PAL Processor State Parameter.
  686. // - s2 = PALE_CHECK return address.
  687. // - Processor registers state saved in myStateDump[] by osmcaProcStateDump().
  688. // - myStackFrame[0] = ar.rsc
  689. // - myStackFrame[1] = ar.pfs
  690. // - myStackFrame[2] = ar.ifs
  691. // - myStackFrame[3] = ar.bspstore
  692. // - myStackFrame[4] = ar.rnat
  693. // - myStackFrame[5] = ar.bsp - ar.bspstore
  694. // - ar.bspstore = myBspStore
  695. // - sp = &mySp[sizeof(mySp[])]
  696. //
  697. // Return:
  698. // rtn0=Success/Failure (0/!0)
  699. // rtn1=Alternate MinState Pointer if any else NULL
  700. //
  701. // Implementation notes:
  702. // This code CANNOT [as default rules - at least entry and through fatal MCAs handling]
  703. // - make any system call
  704. // - attempt to acquire any spinlock used by any code outside the MCA handler
  705. // - change the interrupt state.
  706. // Passing data to non-MCA code must be done using manual semaphore instructions.
  707. // This code should minimize the path and the global or memory allocated data accesses.
  708. // This code should only access MCA-namespace structures and should not access globals
  709. // until it is safe.
  710. //
  711. //--
  712. {
  713. SAL_PAL_RETURN_VALUES rv;
  714. LONGLONG salStatus;
  715. BOOLEAN mcWakeUp;
  716. PMCA_EXCEPTION mcaLog;
  717. ULONGLONG mcaAllocatedLogSize;
  718. PSAL_EVENT_RESOURCES mcaResources;
  719. KIRQL oldIrql;
  720. volatile KPCR * const pcr = KeGetPcr();
  721. //
  722. // Acquire MCA spinlock protecting OS_MCA resources.
  723. //
  724. // Thierry 10/06/2000: FIXFIX.
  725. // we will move this MP synchronization in HalpOsMcaDispatch after current discussions
  726. // with Intel about MP MCA handling are completed.
  727. // Expecting responses from Intel about these.
  728. //
  729. KeRaiseIrql(HIGH_LEVEL, &oldIrql);
  730. HalpAcquireMcaSpinLock( &HalpMcaSpinLock );
  731. HalpOsMcaInProgress++;
  732. //
  733. // Save OsToSal minimum state
  734. //
  735. mcaResources = pcr->OsMcaResourcePtr;
  736. mcaResources->OsToSalHandOff.SalReturnAddress = mcaResources->SalToOsHandOff.SalReturnAddress;
  737. mcaResources->OsToSalHandOff.SalGlobalPointer = mcaResources->SalToOsHandOff.SalGlobalPointer;
  738. //
  739. // update local variables with pre-initialized MCA log data.
  740. //
  741. mcaLog = (PMCA_EXCEPTION)(mcaResources->EventPool);
  742. mcaAllocatedLogSize = mcaResources->EventPoolSize;
  743. if ( !mcaLog || !mcaAllocatedLogSize ) {
  744. //
  745. // The following code should never happen or the implementation of the HAL MCA logs
  746. // pre-allocation failed miserably. This would be a development error.
  747. //
  748. HalpMcaBugCheck( (ULONG_PTR)HAL_BUGCHECK_MCA_ASSERT, mcaLog,
  749. mcaAllocatedLogSize,
  750. (ULONGLONG)0 );
  751. }
  752. //
  753. // Get the MCA logs
  754. //
  755. salStatus = (LONGLONG)0;
  756. while( salStatus >= 0 ) {
  757. ERROR_SEVERITY errorSeverity;
  758. rv = HalpGetStateInfo( MCA_EVENT, mcaLog );
  759. salStatus = rv.ReturnValues[0];
  760. switch( salStatus ) {
  761. case SAL_STATUS_SUCCESS:
  762. errorSeverity = HalpMcaProcessLog( mcaLog );
  763. if ( errorSeverity == ErrorFatal ) {
  764. //
  765. // We are now going down with a MACHINE_CHECK_EXCEPTION.
  766. // No return...
  767. //
  768. HalpMcaBugCheck( HAL_BUGCHECK_MCA_FATAL, mcaLog,
  769. mcaAllocatedLogSize,
  770. 0 );
  771. }
  772. rv = HalpClearStateInfo( MCA_EVENT );
  773. if ( !SAL_SUCCESSFUL(rv) ) {
  774. //
  775. // Current consideration for this implementation - 08/2000:
  776. // if clearing the event fails, we assume that FW has a real problem;
  777. // continuing will be dangerous. We bugcheck.
  778. //
  779. HalpMcaBugCheck( HAL_BUGCHECK_MCA_CLEAR_STATEINFO, mcaLog,
  780. mcaAllocatedLogSize,
  781. rv.ReturnValues[0] );
  782. }
  783. // SAL_STATUS_SUCCESS, SAL_STATUS_SUCCESS_MORE_RECORDS ... and
  784. // ErrorSeverity != ErrorFatal.
  785. //
  786. // Call the registered kernel handler.
  787. //
  788. // Thierry 08/2000 - FIXFIX:
  789. // The errorSeverity check is under comments. It should not be commented for the
  790. // final version. However, we wanted to have kernel notification if we are getting
  791. // log error severity != ErrorFatal or != ErrorRecoverable.
  792. if ( /* (errorSeverity == ErrorCorrected) && */
  793. ( HalpMcaInfo.KernelDelivery || HalpMcaInfo.DriverInfo.DpcCallback ) ) {
  794. InterlockedExchange( &HalpMcaInfo.DpcNotification, 1 );
  795. }
  796. break;
  797. case SAL_STATUS_NO_INFORMATION_AVAILABLE:
  798. //
  799. // The salStatus value will break the salStatus loop.
  800. //
  801. rv.ReturnValues[0] = SAL_STATUS_SUCCESS;
  802. break;
  803. case SAL_STATUS_SUCCESS_WITH_OVERFLOW:
  804. case SAL_STATUS_INVALID_ARGUMENT:
  805. case SAL_STATUS_ERROR:
  806. case SAL_STATUS_VA_NOT_REGISTERED:
  807. default: // Thierry 08/00: WARNING - SAL July 2000 - v2.90.
  808. // default includes possible unknown positive salStatus values.
  809. HalpMcaBugCheck( HAL_BUGCHECK_MCA_GET_STATEINFO, mcaLog,
  810. mcaAllocatedLogSize,
  811. salStatus );
  812. break;
  813. }
  814. }
  815. //
  816. // Currently 08/2000, we do not support the modification of the minstate.
  817. //
  818. mcaResources->OsToSalHandOff.MinStateSavePtr = mcaResources->SalToOsHandOff.MinStateSavePtr;
  819. mcaResources->OsToSalHandOff.Result = rv.ReturnValues[0];
  820. //
  821. // If error was corrected and MCA non-monarch processors are in rendez vous,
  822. // we will have to wake them up.
  823. //
  824. mcWakeUp = ( (rv.ReturnValues[0] == SAL_STATUS_SUCCESS) &&
  825. HalpSalRendezVousSucceeded( mcaResources->SalToOsHandOff ) );
  826. //
  827. // Release MCA spinlock protecting OS_MCA resources.
  828. //
  829. HalpOsMcaInProgress = 0;
  830. HalpReleaseMcaSpinLock( &HalpMcaSpinLock );
  831. //
  832. // If required, let's wake MCA non-monarch processors up.
  833. //
  834. if ( mcWakeUp ) {
  835. HalpMcWakeUp();
  836. }
  837. return( rv );
  838. } // HalpMcaHandler()
  839. //++
  840. // Name: HalpGetErrLogSize()
  841. //
  842. // Routine Description:
  843. //
  844. // This is a wrapper that will call SAL_GET_STATE_INFO_SIZE
  845. //
  846. // Arguments On Entry:
  847. // arg0 = Reserved
  848. // arg1 = Event Type (MCA,INIT,CMC,CPE)
  849. //
  850. // Returns
  851. // rtn0=Success/Failure (0/!0)
  852. // rtn1=Size
  853. //--
  854. SAL_PAL_RETURN_VALUES
  855. HalpGetErrLogSize( ULONGLONG Res,
  856. ULONGLONG eType
  857. )
  858. {
  859. SAL_PAL_RETURN_VALUES rv = {0};
  860. HalpSalCall(SAL_GET_STATE_INFO_SIZE, eType, 0,0,0,0,0,0, &rv);
  861. return(rv);
  862. }
  863. //EndProc//////////////////////////////////////////////////////////////////////
  864. //++
  865. // Name: HalpGetErrLog()
  866. //
  867. // Routine Description:
  868. //
  869. // This is a wrapper that will call SAL_GET_STATE_INFO
  870. //
  871. // Arguments On Entry:
  872. // arg0 = Reserved
  873. // arg1 = Event Type (MCA,INIT,CMC)
  874. // arg3 = pBuffer
  875. //
  876. // Success/Failure (0/!0)
  877. //--
  878. SAL_PAL_RETURN_VALUES
  879. HalpGetErrLog( ULONGLONG Res,
  880. ULONGLONG eType,
  881. ULONGLONG* pBuff
  882. )
  883. {
  884. SAL_PAL_RETURN_VALUES rv={0};
  885. HalpSalCall(SAL_GET_STATE_INFO, eType, 0, (ULONGLONG)pBuff, 0,0,0,0, &rv);
  886. //
  887. // Regardless of the call success or failure, fix the record to store
  888. // the processor number the SAL_PROC was executed on.
  889. // This feature is requested by WMI.
  890. //
  891. HalpSetFwMceLogProcessorNumber( (PERROR_RECORD_HEADER)pBuff );
  892. return(rv);
  893. }
  894. //EndProc//////////////////////////////////////////////////////////////////////
  895. //++
  896. // Name: HalpClrErrLog()
  897. //
  898. // Routine Description:
  899. //
  900. // This is a wrapper that will call SAL_CLEAR_STATE_INFO
  901. //
  902. // Arguments On Entry:
  903. // arg0 = Reserved
  904. // arg1 = Event Type (MCA,INIT,CMC,CPE)
  905. //
  906. // Success/Failure (0/!0)
  907. //--
  908. SAL_PAL_RETURN_VALUES
  909. HalpClrErrLog( ULONGLONG Res,
  910. ULONGLONG eType
  911. )
  912. {
  913. SAL_PAL_RETURN_VALUES rv={0};
  914. HalpSalCall( SAL_CLEAR_STATE_INFO, eType, 0,0,0,0,0,0, &rv );
  915. return(rv);
  916. }
  917. //EndProc//////////////////////////////////////////////////////////////////////
  918. //++
  919. // Name: HalpSalSetParams()
  920. //
  921. // Routine Description:
  922. //
  923. // This is a wrapper that will call SAL_MC_SET_PARAMS
  924. //
  925. // Arguments On Entry:
  926. // arg0 = Reserved
  927. // arg1 = Parameter Type (rendz. or wakeup)
  928. // arg2 = Event Type (interrupt/semaphore)
  929. // arg3 = Interrupt Vector or Memory Address
  930. // arg4 = Timeout value for rendezvous
  931. //
  932. // Success/Failure (0/!0)
  933. //--
  934. SAL_PAL_RETURN_VALUES
  935. HalpSalSetParams(ULONGLONG Res,
  936. ULONGLONG pType,
  937. ULONGLONG eType,
  938. ULONGLONG VecAdd,
  939. ULONGLONG tValue)
  940. {
  941. SAL_PAL_RETURN_VALUES rv={0};
  942. HalpSalCall(SAL_MC_SET_PARAMS, pType, eType, VecAdd,tValue,0,0,0,&rv);
  943. return(rv);
  944. }
  945. //EndProc//////////////////////////////////////////////////////////////////////
  946. //++
  947. // Name: HalpSalSetVectors()
  948. //
  949. // Routine Description:
  950. //
  951. // This is a wrapper that will call SAL_SET_VECTORS
  952. //
  953. // Arguments On Entry:
  954. // arg0 = Reserved
  955. // arg1 = Event Type (MCA, INIT..)
  956. // arg2 = Physical Address of handler
  957. // arg3 = gp
  958. // arg4 = length of event handler in bytes
  959. //
  960. // Success/Failure (0/!0)
  961. //--
  962. SAL_PAL_RETURN_VALUES
  963. HalpSalSetVectors( ULONGLONG Res,
  964. ULONGLONG eType,
  965. PHYSICAL_ADDRESS Addr,
  966. ULONGLONG gpValue,
  967. ULONGLONG szHndlr)
  968. {
  969. SAL_PAL_RETURN_VALUES rv={0};
  970. if ( eType == InitEvent ) {
  971. //
  972. // Thierry 08/2000:
  973. // Current implementation assumes that OS decides the monarch inside OS_INIT.
  974. // This implies handler_2, gp_2, length_2 are identical to handler_1, gp_1, length_1.
  975. //
  976. HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue, szHndlr,
  977. (ULONGLONG)Addr.QuadPart, gpValue, szHndlr, &rv);
  978. }
  979. else {
  980. HalpSalCall(SAL_SET_VECTORS, eType, (ULONGLONG)Addr.QuadPart, gpValue,szHndlr,0,0,0,&rv);
  981. }
  982. return(rv);
  983. }
  984. //EndProc//////////////////////////////////////////////////////////////////////
  985. //++
  986. // Name: HalpSalRendz()
  987. //
  988. // Routine Description:
  989. //
  990. // This is a wrapper that will call SAL_MC_RENDEZ
  991. //
  992. // Arguments On Entry:
  993. // arg0 = Reserved
  994. //
  995. // Success/Failure (0/!0)
  996. //--
  997. SAL_PAL_RETURN_VALUES
  998. HalpSalRendz(void)
  999. {
  1000. SAL_PAL_RETURN_VALUES rv={0};
  1001. HalpSalCall(SAL_MC_RENDEZ, 0, 0, 0,0,0,0,0,&rv);
  1002. return(rv);
  1003. }
  1004. VOID
  1005. HalpMcWakeUp(
  1006. VOID
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. This function does IPI to wakeup the MC non-monarch processors.
  1011. Arguments:
  1012. None.
  1013. Return Value:
  1014. None.
  1015. Remarks:
  1016. This function is assumed to be executed on the MC monarch processor.
  1017. --*/
  1018. {
  1019. USHORT LogicalCpu;
  1020. USHORT ProcessorID;
  1021. USHORT monarchID;
  1022. //
  1023. // Scan the processor set and request an interprocessor interrupt on
  1024. // each of the specified targets.
  1025. //
  1026. monarchID = (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX];
  1027. for (LogicalCpu = 0; LogicalCpu < HalpMpInfo.ProcessorCount; LogicalCpu++) {
  1028. //
  1029. // Only IPI processors that are started.
  1030. //
  1031. if (HalpActiveProcessors & (1 << HalpProcessorInfo[LogicalCpu].NtProcessorNumber)) {
  1032. ProcessorID = HalpProcessorInfo[LogicalCpu].LocalApicID;
  1033. //
  1034. // Request interprocessor interrupt on target physicalCpu.
  1035. //
  1036. if ( ProcessorID != monarchID ) {
  1037. HalpSendIPI(ProcessorID, MC_WKUP_VECTOR);
  1038. }
  1039. }
  1040. }
  1041. } // HalpMcWakeUp()
  1042. VOID
  1043. HalpCMCEnable(
  1044. VOID
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This routine sets the processor CMCV register with CMCI_VECTOR.
  1049. Arguments:
  1050. None.
  1051. Return Value:
  1052. None.
  1053. --*/
  1054. {
  1055. if ( HalpFeatureBits & HAL_CMC_PRESENT ) {
  1056. HalpWriteCMCVector( CMCI_VECTOR );
  1057. }
  1058. return;
  1059. } // HalpCMCEnable()
  1060. VOID
  1061. HalpCMCDisable(
  1062. VOID
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This routine resets the processor CMCV register.
  1067. Arguments:
  1068. None
  1069. Return Value:
  1070. None
  1071. --*/
  1072. {
  1073. HalpWriteCMCVector( 0x10000ui64 );
  1074. return;
  1075. } // HalpCMCDisable()
  1076. ULONG_PTR
  1077. HalpSetCMCVector(
  1078. IN ULONG_PTR CmcVector
  1079. )
  1080. /*++
  1081. Routine Description:
  1082. This routine sets the processor CMCV register with specified vector.
  1083. This function is the broadcast function for HalpCMCDisableForAllProcessors().
  1084. Arguments:
  1085. CmcVector: CMC Vector value.
  1086. Value:
  1087. STATUS_SUCCESS
  1088. --*/
  1089. {
  1090. HalpWriteCMCVector( (ULONG64)CmcVector );
  1091. return((ULONG_PTR)(ULONG)(STATUS_SUCCESS));
  1092. } // HalpSetCmcVector()
  1093. VOID
  1094. HalpCMCDisableForAllProcessors(
  1095. VOID
  1096. )
  1097. /*++
  1098. Routine Description:
  1099. This routine disables processor CMC on every processor in the host configuration
  1100. by executing HalpSetCmcVector( 0ui64 ) on every processor in a synchronous manner.
  1101. Arguments:
  1102. None.
  1103. Value:
  1104. None.
  1105. --*/
  1106. {
  1107. //
  1108. // Can not do an IPI if the processors are above IPI level such
  1109. // as we are in the kernel debugger.
  1110. //
  1111. if (KeGetCurrentIrql() < IPI_LEVEL) {
  1112. (VOID)KiIpiGenericCall( HalpSetCMCVector, (ULONG_PTR)0x10000ui64 );
  1113. } else {
  1114. HalpSetCMCVector(0x10000ui64);
  1115. }
  1116. return;
  1117. } // HalpCMCDisableForAllProcessors()
  1118. VOID
  1119. HalpCMCIHandler (
  1120. IN PKINTERRUPT_ROUTINE Interrupt,
  1121. IN PKTRAP_FRAME TrapFrame
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. Processor Interrupt routine for CMC interrupts.
  1126. Arguments:
  1127. TrapFrame - Captured trap frame address.
  1128. Return Parameters:
  1129. None.
  1130. Notes:
  1131. Thierry 08/2000:
  1132. This function does not do much, it flags the PCR InOsCmc field
  1133. and calls the second-level handler: HalpCmcHandler().
  1134. However, this was implmented this way so this function abstracts the
  1135. standard interrupts resources from the purely CMC processing in HalpCmcHandler().
  1136. --*/
  1137. {
  1138. volatile KPCR * const pcr = KeGetPcr();
  1139. pcr->InOsCmc = TRUE;
  1140. HalpCmcHandler();
  1141. pcr->InOsCmc = FALSE;
  1142. return;
  1143. } // HalpCMCIHandler()
  1144. VOID
  1145. HalpCmcProcessLog(
  1146. PCMC_EXCEPTION CmcLog
  1147. )
  1148. /*++
  1149. Routine Description:
  1150. This function does a simple processing check a IA64 CMC log.
  1151. Arguments:
  1152. CmcLog - Provides CMC log address
  1153. Return Parameters:
  1154. None.
  1155. Notes:
  1156. Currently simply checking and outputing log contents for checked hal only.
  1157. --*/
  1158. {
  1159. #if DBG
  1160. //
  1161. // Simple log processing for first debugging...
  1162. //
  1163. GUID processorDeviceGuid = ERROR_PROCESSOR_GUID;
  1164. BOOLEAN processorDeviceFound;
  1165. PERROR_RECORD_HEADER header = (PERROR_RECORD_HEADER)CmcLog;
  1166. PERROR_SECTION_HEADER section, sectionMax;
  1167. if ( header->ErrorSeverity != ErrorCorrected ) {
  1168. HalDebugPrint(( HAL_ERROR,
  1169. "HAL!HalpCmcProcessLog: CMC record with severity [%d] != corrected!!!\n",
  1170. header->ErrorSeverity ));
  1171. }
  1172. //
  1173. // SAL spec BUGBUG 08/2000: we should have put the length of the header in the definition.
  1174. // Same for section header.
  1175. //
  1176. processorDeviceFound = FALSE;
  1177. section = (PERROR_SECTION_HEADER)((ULONG_PTR)header + sizeof(*header));
  1178. sectionMax = (PERROR_SECTION_HEADER)((ULONG_PTR)header + header->Length);
  1179. while( section < sectionMax ) {
  1180. if ( IsEqualGUID( &section->Guid, &processorDeviceGuid ) ) {
  1181. PERROR_PROCESSOR processorRecord = (PERROR_PROCESSOR)section;
  1182. processorDeviceFound = TRUE;
  1183. //
  1184. // Minimum processing here. This will enhance with testing and most common
  1185. // occurences.
  1186. //
  1187. if ( processorRecord->Valid.StateParameter ) {
  1188. ULONGLONG stateParameter = processorRecord->StateParameter.StateParameter;
  1189. //
  1190. // At any time more than one error could be valid
  1191. //
  1192. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_SHIFT) &
  1193. ERROR_PROCESSOR_STATE_PARAMETER_CACHE_CHECK_MASK) {
  1194. //
  1195. // cache error
  1196. //
  1197. HalDebugPrint(( HAL_INFO,
  1198. "HAL!HalpCmcProcessLog: Corrected Processor CACHE Machine Check error\n" ));
  1199. }
  1200. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_SHIFT) &
  1201. ERROR_PROCESSOR_STATE_PARAMETER_TLB_CHECK_MASK) {
  1202. //
  1203. // tlb error
  1204. //
  1205. HalDebugPrint(( HAL_INFO,
  1206. "HAL!HalpCmcProcessLog: Corrected Processor TLB Machine Check error\n" ));
  1207. }
  1208. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_SHIFT) &
  1209. ERROR_PROCESSOR_STATE_PARAMETER_BUS_CHECK_MASK) {
  1210. //
  1211. // bus error
  1212. //
  1213. HalDebugPrint(( HAL_INFO,
  1214. "HAL!HalpCmcProcessLog: Corrected Processor BUS Machine Check error\n" ));
  1215. }
  1216. if((stateParameter >> ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_SHIFT) &
  1217. ERROR_PROCESSOR_STATE_PARAMETER_UNKNOWN_CHECK_MASK) {
  1218. //
  1219. // unknown error
  1220. //
  1221. HalDebugPrint(( HAL_INFO,
  1222. "HAL!HalpCmcProcessLog: Corrected Processor UNKNOWN Machine Check error\n" ));
  1223. }
  1224. }
  1225. }
  1226. }
  1227. if ( !processorDeviceFound ) {
  1228. HalDebugPrint(( HAL_ERROR,
  1229. "HAL!HalpCmcProcessLog: CMC log without processor device record!!!\n"));
  1230. }
  1231. #endif // DBG
  1232. return;
  1233. } // HalpCmcProcessLog()
  1234. //++
  1235. // Name: HalpCmcHandler()
  1236. //
  1237. // Routine Description:
  1238. //
  1239. // This is the second level CMC Interrupt Handler for FW corrected errors.
  1240. //
  1241. // Arguments On Entry:
  1242. // None.
  1243. //
  1244. // Return.
  1245. // None.
  1246. //
  1247. // Notes:
  1248. // This function calls the kernel notification and inserts the OEM CMC driver dpc if
  1249. // registered.
  1250. // Accessing the CMC logs at this level could be inacceptable because of the possible
  1251. // large size of the logs and the time required to collect them.
  1252. // The collection of the logs is delayed until the work item calls
  1253. // HalQuerySystemInformation.HalCmcLogInformation.
  1254. //--
  1255. VOID
  1256. HalpCmcHandler(
  1257. VOID
  1258. )
  1259. {
  1260. //
  1261. // Internal housekeeping.
  1262. //
  1263. InterlockedIncrement( &HalpCmcInfo.Stats.CmcInterruptCount );
  1264. //
  1265. // Notify the kernel if registered.
  1266. //
  1267. if ( HalpCmcInfo.KernelDelivery ) {
  1268. if ( !HalpCmcInfo.KernelDelivery( HalpCmcInfo.KernelToken, NULL ) ) {
  1269. InterlockedIncrement( &HalpCmcInfo.Stats.KernelDeliveryFails );
  1270. }
  1271. }
  1272. //
  1273. // Notify the OEM CMC driver if registered.
  1274. //
  1275. if ( HalpCmcInfo.DriverInfo.DpcCallback ) {
  1276. if ( !KeInsertQueueDpc( &HalpCmcInfo.DriverDpc, NULL, NULL ) ) {
  1277. InterlockedIncrement( &HalpCmcInfo.Stats.DriverDpcQueueFails );
  1278. }
  1279. }
  1280. return;
  1281. } // HalpCmcHandler()
  1282. //EndProc//////////////////////////////////////////////////////////////////////
  1283. //++
  1284. // Name: HalpCpeHandler()
  1285. //
  1286. // Routine Description:
  1287. //
  1288. // This is the second level CPE Interrupt Handler for Platform corrected errors.
  1289. //
  1290. // Arguments On Entry:
  1291. // None.
  1292. //
  1293. // Return.
  1294. // None.
  1295. //
  1296. // Notes:
  1297. // This function calls the kernel notification and inserts the OEM CPE driver dpc if
  1298. // registered.
  1299. // Accessing the CPE logs at this level could be inacceptable because of the possible
  1300. // large size of the logs and the time required to collect them.
  1301. // The collection of the logs is delayed until the work item calls
  1302. // HalQuerySystemInformation.HalCpeLogInformation.
  1303. //--
  1304. VOID
  1305. HalpCpeHandler(
  1306. VOID
  1307. )
  1308. {
  1309. //
  1310. // Internal housekeeping.
  1311. //
  1312. InterlockedIncrement( &HalpCpeInfo.Stats.CpeInterruptCount );
  1313. //
  1314. // Notify the kernel if registered.
  1315. //
  1316. if ( HalpCpeInfo.KernelDelivery ) {
  1317. if ( !HalpCpeInfo.KernelDelivery( HalpCpeInfo.KernelToken, NULL ) ) {
  1318. InterlockedIncrement( &HalpCpeInfo.Stats.KernelDeliveryFails );
  1319. }
  1320. }
  1321. //
  1322. // Notify the OEM CPE driver if registered.
  1323. //
  1324. if ( HalpCpeInfo.DriverInfo.DpcCallback ) {
  1325. if ( !KeInsertQueueDpc( &HalpCpeInfo.DriverDpc, NULL, NULL ) ) {
  1326. InterlockedIncrement( &HalpCpeInfo.Stats.DriverDpcQueueFails );
  1327. }
  1328. }
  1329. return;
  1330. } // HalpCpeHandler()
  1331. //EndProc//////////////////////////////////////////////////////////////////////
  1332. VOID
  1333. HalpMcRzHandler (
  1334. IN PKINTERRUPT_ROUTINE Interrupt,
  1335. IN PKTRAP_FRAME TrapFrame
  1336. )
  1337. /*++
  1338. Routine Description:
  1339. Arguements:
  1340. Return Parameters:
  1341. --*/
  1342. {
  1343. SAL_PAL_RETURN_VALUES rv={0};
  1344. HalpDisableInterrupts();
  1345. rv=HalpSalRendz();
  1346. HalpEnableInterrupts();
  1347. // do any Isr clean up and re-enable the interrupts & MC's
  1348. return;
  1349. }
  1350. //EndProc//////////////////////////////////////////////////////////////////////
  1351. VOID
  1352. HalpMcWkupHandler (
  1353. IN PKINTERRUPT_ROUTINE Interrupt,
  1354. IN PKTRAP_FRAME TrapFrame
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. Arguements:
  1359. Return Parameters:
  1360. --*/
  1361. {
  1362. return;
  1363. }
  1364. //EndProc//////////////////////////////////////////////////////////////////////
  1365. VOID
  1366. HalpCPEIHandler (
  1367. IN PKINTERRUPT_ROUTINE Interrupt,
  1368. IN PKTRAP_FRAME TrapFrame
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. Processor Interrupt routine for CPE interrupts.
  1373. Arguments:
  1374. TrapFrame - Captured trap frame address.
  1375. Return Parameters:
  1376. None.
  1377. Notes:
  1378. Thierry 08/2000:
  1379. This function does not do much, it flags the PCR InOsCpe field
  1380. and calls the second-level handler: HalpCpeHandler().
  1381. However, this was implmented this way so this function abstracts the
  1382. standard interrupts resources from the purely CPE processing in HalpCpeHandler().
  1383. --*/
  1384. {
  1385. volatile KPCR * const pcr = KeGetPcr();
  1386. pcr->InOsCpe = TRUE;
  1387. HalpCpeHandler();
  1388. pcr->InOsCpe = FALSE;
  1389. return;
  1390. } // HalpCPEIHandler()
  1391. VOID
  1392. HalpCPEEnable (
  1393. VOID
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. This routine sets the default HAL CPE handling regardless of the user specified
  1398. registry setting. It enables the supported Platform Interrupt sources and
  1399. exposes the initial interrupt/polling based mode used for CPE.
  1400. The user specified registry setting is handled via HalpMcaInit() at the end of
  1401. phase 1.
  1402. Arguments:
  1403. None.
  1404. Return Parameters:
  1405. None.
  1406. Implementation Notes:
  1407. The following implementation assumes that this code is executed on BSP.
  1408. --*/
  1409. {
  1410. ULONG i;
  1411. if ( HalpFeatureBits & HAL_CPE_PRESENT ) {
  1412. ULONG maxCPE = HalpMaxCPEImplemented;
  1413. if ( maxCPE ) {
  1414. //
  1415. // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags,
  1416. // HalpCPEIoSapicVector.
  1417. //
  1418. for (i=0 ; i != maxCPE; i++ ) {
  1419. HalpEnableRedirEntry( HalpCPEIntIn[i] );
  1420. }
  1421. //
  1422. // Initialize the remaining fields of HAL private CPE info structure.
  1423. //
  1424. HalpCpeInfo.Stats.PollingInterval = HAL_CPE_INTERRUPTS_BASED;
  1425. }
  1426. else {
  1427. //
  1428. // We will implement Polling model.
  1429. //
  1430. //
  1431. // Thierry 03/11/2001: WARNING WARNING
  1432. // Do not enable xxhal.c HAL_CPE_PRESENT if HalpMaxCPEImplemented == 0.
  1433. // We bugcheck with the current BigSur SAL/FW (<= build 99) at SAL_GET_STATE_INFO calls,
  1434. // the FW assuming that we are calling the SAL MC related functions in physical mode.
  1435. // With the Lion SAL/FW (<= build 75), we bugcheck after getting MCA logs at boot time,
  1436. // the FW having some virtualization issues.
  1437. // Intel is committed to provide working FWs soon (< 2 weeks...).
  1438. //
  1439. HalpCpeInfo.Stats.PollingInterval = HALP_CPE_DEFAULT_POLLING_INTERVAL;
  1440. }
  1441. }
  1442. else {
  1443. HalpCpeInfo.Stats.PollingInterval = HAL_CPE_DISABLED;
  1444. }
  1445. return;
  1446. } // HalpCPEEnable()
  1447. VOID
  1448. HalpCPEDisable (
  1449. VOID
  1450. )
  1451. /*++
  1452. Routine Description:
  1453. This routine disables the SAPIC Platform Interrupt Sources.
  1454. Note that if HalpMaxCPEImplemented is 0, the function does nothing.
  1455. Arguments:
  1456. None.
  1457. Return Parameters:
  1458. None.
  1459. --*/
  1460. {
  1461. //
  1462. // Pick up the information from HalpCPEIntIn, HalpCPEDestination, HalpCPEVectorFlags,
  1463. // HalpCPEIoSapicVector
  1464. int i;
  1465. for (i=0;i != HalpMaxCPEImplemented;i++) {
  1466. HalpDisableRedirEntry(HalpCPEIntIn[i]);
  1467. }
  1468. return;
  1469. } // HalpCPEDisable()
  1470. VOID
  1471. HalpMCADisable(
  1472. VOID
  1473. )
  1474. {
  1475. PHYSICAL_ADDRESS NULL_PHYSICAL_ADDRESS = {0};
  1476. SAL_PAL_RETURN_VALUES rv = {0};
  1477. char Lid;
  1478. ULONGLONG gp_reg = GetGp();
  1479. // Disable CMCs
  1480. HalpCMCDisableForAllProcessors();
  1481. // Disable CPE Interrupts
  1482. HalpCPEDisable();
  1483. //DeRegister Rendez. Paramters with SAL
  1484. #define NULL_VECTOR 0xF
  1485. rv = HalpSalSetParams(0,RendzType, IntrVecType, NULL_VECTOR, HalpMcRendezTimeOut );
  1486. // Deregister WakeUp parameters with SAL
  1487. rv=HalpSalSetParams(0, WakeUpType, IntrVecType, NULL_VECTOR,0);
  1488. // Deregister OsMcaDispatch (OS_MCA) physical address with SAL
  1489. rv=HalpSalSetVectors(0, MchkEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0);
  1490. // Deregister OsInitDispatch physical address with SAL
  1491. rv=HalpSalSetVectors(0, InitEvent, NULL_PHYSICAL_ADDRESS, gp_reg,0);
  1492. return;
  1493. } // HalpMCADisable()
  1494. NTSTATUS
  1495. HalpGetMceInformation(
  1496. PHAL_ERROR_INFO ErrorInfo,
  1497. PULONG ErrorInfoLength
  1498. )
  1499. /*++
  1500. Routine Description:
  1501. This routine is called by HaliQuerySystemInformation for the HalErrorInformation class.
  1502. Arguments:
  1503. ErrorInfo : pointer to HAL_ERROR_INFO structure.
  1504. ErrorInfoLength : size of the valid memory structure pointed by ErrorInfo.
  1505. Return Value:
  1506. STATUS_SUCCESS if successful
  1507. error status otherwise
  1508. --*/
  1509. {
  1510. NTSTATUS status;
  1511. ULONG cpePollingInterval;
  1512. PAGED_CODE();
  1513. ASSERT( ErrorInfo );
  1514. ASSERT( ErrorInfoLength );
  1515. //
  1516. // Backward compatibility only.
  1517. //
  1518. if ( !ErrorInfo->Version || ( ErrorInfo->Version > HAL_ERROR_INFO_VERSION ) ) {
  1519. return( STATUS_REVISION_MISMATCH );
  1520. }
  1521. //
  1522. // Zero Reserved field.
  1523. //
  1524. ErrorInfo->Reserved = 0;
  1525. //
  1526. // Collect MCA info under protection if required.
  1527. //
  1528. ErrorInfo->McaMaxSize = HalpMcaInfo.Stats.MaxLogSize;
  1529. ErrorInfo->McaPreviousEventsCount = HalpMcaInfo.Stats.McaPreviousCount;
  1530. ErrorInfo->McaCorrectedEventsCount = HalpMcaInfo.Stats.McaCorrectedCount; // approximation.
  1531. ErrorInfo->McaKernelDeliveryFails = HalpMcaInfo.Stats.KernelDeliveryFails; // approximation.
  1532. ErrorInfo->McaDriverDpcQueueFails = HalpMcaInfo.Stats.DriverDpcQueueFails; // approximation.
  1533. ErrorInfo->McaReserved = 0;
  1534. //
  1535. // Collect CMC info under protection if required.
  1536. //
  1537. ErrorInfo->CmcMaxSize = HalpCmcInfo.Stats.MaxLogSize;
  1538. ErrorInfo->CmcPollingInterval = HalpCmcInfo.Stats.PollingInterval;
  1539. ErrorInfo->CmcInterruptsCount = HalpCmcInfo.Stats.CmcInterruptCount; // approximation.
  1540. ErrorInfo->CmcKernelDeliveryFails = HalpCmcInfo.Stats.KernelDeliveryFails; // approximation.
  1541. ErrorInfo->CmcDriverDpcQueueFails = HalpCmcInfo.Stats.DriverDpcQueueFails; // approximation.
  1542. HalpAcquireCmcMutex();
  1543. ErrorInfo->CmcGetStateFails = HalpCmcInfo.Stats.GetStateFails;
  1544. ErrorInfo->CmcClearStateFails = HalpCmcInfo.Stats.ClearStateFails;
  1545. ErrorInfo->CmcLogId = HalpCmcInfo.Stats.LogId;
  1546. HalpReleaseCmcMutex();
  1547. ErrorInfo->CmcReserved = 0;
  1548. //
  1549. // Collect CPE info under protection if required.
  1550. //
  1551. ErrorInfo->CpeMaxSize = HalpCpeInfo.Stats.MaxLogSize;
  1552. ErrorInfo->CpePollingInterval = HalpCpeInfo.Stats.PollingInterval;
  1553. ErrorInfo->CpeInterruptsCount = HalpCpeInfo.Stats.CpeInterruptCount; // approximation.
  1554. ErrorInfo->CpeKernelDeliveryFails = HalpCpeInfo.Stats.KernelDeliveryFails; // approximation.
  1555. ErrorInfo->CpeDriverDpcQueueFails = HalpCpeInfo.Stats.DriverDpcQueueFails; // approximation.
  1556. HalpAcquireCpeMutex();
  1557. ErrorInfo->CpeGetStateFails = HalpCpeInfo.Stats.GetStateFails;
  1558. ErrorInfo->CpeClearStateFails = HalpCpeInfo.Stats.ClearStateFails;
  1559. ErrorInfo->CpeLogId = HalpCpeInfo.Stats.LogId;
  1560. HalpReleaseCpeMutex();
  1561. // CpeInterruptSources: Number of SAPIC Platform Interrup Sources supported by HAL.
  1562. ErrorInfo->CpeInterruptSources = HalpMaxCPEImplemented;
  1563. //
  1564. // Update KernelTokens
  1565. //
  1566. ErrorInfo->McaKernelToken = (ULONGLONG) HalpMcaInfo.KernelToken;
  1567. ErrorInfo->CmcKernelToken = (ULONGLONG) HalpCmcInfo.KernelToken;
  1568. ErrorInfo->CpeKernelToken = (ULONGLONG) HalpCpeInfo.KernelToken;
  1569. ErrorInfo->KernelReserved[3] = (ULONGLONG) 0;
  1570. *ErrorInfoLength = sizeof(*ErrorInfo);
  1571. return( STATUS_SUCCESS );
  1572. } // HalpGetMceInformation()