AcpiApei.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /** @file
  2. Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include <Uefi.h>
  6. #include <Library/FlashLib.h>
  7. #include <Library/NVParamLib.h>
  8. #include <NVParamDef.h>
  9. #include "AcpiApei.h"
  10. UINT8 AMPERE_GUID[16] = {0x8d, 0x89, 0xed, 0xe8, 0x16, 0xdf, 0xcc, 0x43, 0x8e, 0xcc, 0x54, 0xf0, 0x60, 0xef, 0x15, 0x7f};
  11. CHAR8 DEFAULT_BERT_REBOOT_MSG[BERT_MSG_SIZE] = "Unknown reboot reason";
  12. STATIC VOID
  13. AcpiApeiUninstallTable (
  14. UINT32 Signature
  15. )
  16. {
  17. EFI_STATUS Status;
  18. EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
  19. EFI_ACPI_SDT_PROTOCOL *AcpiTableSdtProtocol;
  20. EFI_ACPI_SDT_HEADER *Table;
  21. UINTN TableKey;
  22. UINTN TableIndex;
  23. /*
  24. * Get access to ACPI tables
  25. */
  26. Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTableProtocol);
  27. if (EFI_ERROR (Status)) {
  28. DEBUG ((DEBUG_ERROR, "%a:%d: Unable to locate ACPI table protocol\n", __FUNCTION__, __LINE__));
  29. return;
  30. }
  31. Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiTableSdtProtocol);
  32. if (EFI_ERROR (Status)) {
  33. DEBUG ((DEBUG_ERROR, "%a:%d: Unable to locate ACPI table support protocol\n", __FUNCTION__, __LINE__));
  34. return;
  35. }
  36. /*
  37. * Search for ACPI Table Signature
  38. */
  39. TableIndex = 0;
  40. Status = AcpiLocateTableBySignature (
  41. AcpiTableSdtProtocol,
  42. Signature,
  43. &TableIndex,
  44. (EFI_ACPI_DESCRIPTION_HEADER **)&Table,
  45. &TableKey
  46. );
  47. if (EFI_ERROR (Status)) {
  48. DEBUG ((DEBUG_ERROR, "%a:%d Unable to get ACPI table\n", __FUNCTION__, __LINE__));
  49. return;
  50. }
  51. /*
  52. * Uninstall ACPI Table
  53. */
  54. Status = AcpiTableProtocol->UninstallAcpiTable (AcpiTableProtocol, TableKey);
  55. if (EFI_ERROR (Status)) {
  56. DEBUG ((DEBUG_ERROR, "%a:%d: Unable to uninstall table\n", __FUNCTION__, __LINE__));
  57. }
  58. }
  59. VOID
  60. AdjustBERTRegionLen (
  61. UINT32 Len
  62. )
  63. {
  64. EFI_STATUS Status;
  65. EFI_ACPI_SDT_PROTOCOL *AcpiTableSdtProtocol;
  66. UINTN TableKey;
  67. UINTN TableIndex;
  68. EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_HEADER *Table;
  69. Status = gBS->LocateProtocol (
  70. &gEfiAcpiSdtProtocolGuid,
  71. NULL,
  72. (VOID **)&AcpiTableSdtProtocol
  73. );
  74. if (EFI_ERROR (Status)) {
  75. DEBUG ((DEBUG_ERROR, "APEI: Unable to locate ACPI table support protocol\n"));
  76. return;
  77. }
  78. /*
  79. * Search for ACPI Table Signature
  80. */
  81. TableIndex = 0;
  82. Status = AcpiLocateTableBySignature (
  83. AcpiTableSdtProtocol,
  84. EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_SIGNATURE,
  85. &TableIndex,
  86. (EFI_ACPI_DESCRIPTION_HEADER **)&Table,
  87. &TableKey
  88. );
  89. if (EFI_ERROR (Status)) {
  90. DEBUG ((DEBUG_ERROR, "%a:%d Unable to get ACPI BERT table\n", __FUNCTION__, __LINE__));
  91. return;
  92. }
  93. /*
  94. * Adjust Boot Error Region Length
  95. */
  96. Table->BootErrorRegionLength = Len;
  97. AcpiUpdateChecksum ((UINT8 *)Table, Table->Header.Length);
  98. }
  99. /*
  100. * Retrieve Bert data from SPI NOR
  101. */
  102. VOID
  103. PullBertSpinorData (
  104. APEI_CRASH_DUMP_DATA *BertErrorData
  105. )
  106. {
  107. UINTN Length;
  108. Length = sizeof (*BertErrorData);
  109. FlashReadCommand (
  110. BERT_FLASH_OFFSET,
  111. BertErrorData,
  112. Length
  113. );
  114. }
  115. /*
  116. * wrap raw bert error data
  117. *
  118. * @param IN BertErrorData Bert Error record to be wrapped
  119. * @param OUT WrappedError Generic error data for OS to consume.
  120. */
  121. VOID
  122. WrapBertErrorData (
  123. APEI_CRASH_DUMP_BERT_ERROR *WrappedError
  124. )
  125. {
  126. UINT32 CrashSize;
  127. UINT8 CrashType;
  128. UINT8 CrashSubType;
  129. CrashSize = PLAT_CRASH_ITERATOR_SIZE *
  130. GetNumberOfSupportedSockets () *
  131. GetMaximumNumberOfCores ();
  132. CrashSize += 2 * (SMPRO_CRASH_SIZE + PMPRO_CRASH_SIZE + RASIP_CRASH_SIZE);
  133. CrashSize += sizeof (WrappedError->Bed.Vendor) + sizeof (WrappedError->Bed.BertRev);
  134. CrashType = WrappedError->Bed.Vendor.Type & RAS_TYPE_ERROR_MASK;
  135. CrashSubType = WrappedError->Bed.Vendor.SubType;
  136. WrappedError->Ges.BlockStatus.ErrorDataEntryCount = 1;
  137. WrappedError->Ges.BlockStatus.UncorrectableErrorValid = 1;
  138. WrappedError->Ged.ErrorSeverity = BERT_DEFAULT_ERROR_SEVERITY;
  139. WrappedError->Ged.Revision = GENERIC_ERROR_DATA_REVISION;
  140. if ((CrashType == RAS_TYPE_BERT && (CrashSubType == 0 || CrashSubType == BERT_UEFI_FAILURE))
  141. || (CrashType == RAS_TYPE_2P)) {
  142. WrappedError->Ged.ErrorDataLength = sizeof (WrappedError->Bed.Vendor) +
  143. sizeof (WrappedError->Bed.BertRev);
  144. WrappedError->Ges.DataLength = sizeof (WrappedError->Bed.Vendor) +
  145. sizeof (WrappedError->Bed.BertRev) +
  146. sizeof (WrappedError->Ged);
  147. AdjustBERTRegionLen (
  148. sizeof (WrappedError->Bed.Vendor) +
  149. sizeof (WrappedError->Bed.BertRev) +
  150. sizeof (WrappedError->Ged) +
  151. sizeof (WrappedError->Ges)
  152. );
  153. } else {
  154. WrappedError->Ged.ErrorDataLength = CrashSize;
  155. WrappedError->Ges.DataLength = CrashSize + sizeof (WrappedError->Ged);
  156. AdjustBERTRegionLen (
  157. CrashSize +
  158. sizeof (WrappedError->Ged) +
  159. sizeof (WrappedError->Ges)
  160. );
  161. }
  162. CopyMem (
  163. WrappedError->Ged.SectionType,
  164. AMPERE_GUID,
  165. sizeof (AMPERE_GUID)
  166. );
  167. }
  168. /*
  169. * create default bert error
  170. * Msg: Unknown reboot reason
  171. */
  172. VOID
  173. CreateDefaultBertData (
  174. APEI_BERT_ERROR_DATA *Data
  175. )
  176. {
  177. Data->Type = RAS_TYPE_BERT_PAYLOAD3;
  178. AsciiStrCpyS (
  179. Data->Msg,
  180. BERT_MSG_SIZE,
  181. DEFAULT_BERT_REBOOT_MSG
  182. );
  183. }
  184. /*
  185. * Ensures BertErrorData In SPINOR matches
  186. * the record produced by CreateDefaultBertData.
  187. * @param Bed Crash dump Data
  188. */
  189. VOID
  190. WriteSpinorDefaultBertTable (
  191. APEI_CRASH_DUMP_DATA *Bed
  192. )
  193. {
  194. UINT8 BertRev;
  195. UINTN Length;
  196. UINT64 Offset;
  197. UINT32 MsgDiff;
  198. APEI_BERT_ERROR_DATA DefaultData = {0};
  199. CreateDefaultBertData (&DefaultData);
  200. if ((Bed->Vendor.Type != DefaultData.Type)) {
  201. Offset = BERT_FLASH_OFFSET +
  202. OFFSET_OF (APEI_CRASH_DUMP_DATA, Vendor) +
  203. OFFSET_OF (APEI_BERT_ERROR_DATA, Type);
  204. Length = sizeof (DefaultData.Type);
  205. FlashEraseCommand (Offset, Length);
  206. FlashWriteCommand (Offset, &(DefaultData.Type), Length);
  207. }
  208. if ((Bed->Vendor.SubType != DefaultData.SubType)) {
  209. Offset = BERT_FLASH_OFFSET +
  210. OFFSET_OF (APEI_CRASH_DUMP_DATA, Vendor) +
  211. OFFSET_OF (APEI_BERT_ERROR_DATA, SubType);
  212. Length = sizeof (DefaultData.SubType);
  213. FlashEraseCommand (Offset, Length);
  214. FlashWriteCommand (Offset, &(DefaultData.SubType), Length);
  215. }
  216. if ((Bed->Vendor.Instance != DefaultData.Instance)) {
  217. Offset = BERT_FLASH_OFFSET +
  218. OFFSET_OF (APEI_CRASH_DUMP_DATA, Vendor) +
  219. OFFSET_OF (APEI_BERT_ERROR_DATA, Instance);
  220. Length = sizeof (DefaultData.Instance);
  221. FlashEraseCommand (Offset, Length);
  222. FlashWriteCommand (Offset, &(DefaultData.Instance), Length);
  223. }
  224. MsgDiff = AsciiStrnCmp (Bed->Vendor.Msg, DefaultData.Msg, BERT_MSG_SIZE);
  225. if (MsgDiff != 0) {
  226. Offset = BERT_FLASH_OFFSET +
  227. OFFSET_OF (APEI_CRASH_DUMP_DATA, Vendor) +
  228. OFFSET_OF (APEI_BERT_ERROR_DATA, Msg);
  229. Length = sizeof (DefaultData.Msg);
  230. FlashEraseCommand (Offset, Length);
  231. FlashWriteCommand (Offset, &(DefaultData.Msg), Length);
  232. }
  233. if (Bed->BertRev != CURRENT_BERT_VERSION) {
  234. Offset = BERT_FLASH_OFFSET + OFFSET_OF (APEI_CRASH_DUMP_DATA, BertRev);
  235. Length = sizeof (Bed->BertRev);
  236. BertRev = CURRENT_BERT_VERSION;
  237. FlashEraseCommand (Offset, Length);
  238. FlashWriteCommand (Offset, &BertRev, Length);
  239. }
  240. }
  241. /*
  242. * Checks Status of NV_SI_RAS_BERT_ENABLED
  243. * Returns TRUE if enabled and FALSE if disabled
  244. */
  245. BOOLEAN
  246. IsBertEnabled (
  247. VOID
  248. )
  249. {
  250. EFI_STATUS Status;
  251. UINT32 Value;
  252. Status = NVParamGet (
  253. NV_SI_RAS_BERT_ENABLED,
  254. NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
  255. &Value
  256. );
  257. if (EFI_ERROR (Status)) {
  258. // BERT is enabled by default
  259. return TRUE;
  260. }
  261. return (Value != 0) ? TRUE : FALSE;
  262. }
  263. /*
  264. * Write bert table to DDR
  265. */
  266. VOID
  267. WriteDDRBertTable (
  268. APEI_CRASH_DUMP_BERT_ERROR *Data
  269. )
  270. {
  271. VOID *Blk = (VOID *)BERT_DDR_OFFSET;
  272. /*
  273. * writing sizeof data to ddr produces alignment error
  274. * this is a temporary workaround
  275. */
  276. CopyMem (Blk, Data, BERT_DDR_LENGTH);
  277. }
  278. /*
  279. * Update Bert Table
  280. */
  281. EFI_STATUS
  282. AcpiPopulateBert (
  283. VOID
  284. )
  285. {
  286. APEI_CRASH_DUMP_BERT_ERROR *DDRError;
  287. DDRError =
  288. (APEI_CRASH_DUMP_BERT_ERROR *)
  289. AllocateZeroPool (sizeof (APEI_CRASH_DUMP_BERT_ERROR));
  290. if (DDRError == NULL) {
  291. return EFI_OUT_OF_RESOURCES;
  292. }
  293. if (IsBertEnabled ()) {
  294. PullBertSpinorData (&(DDRError->Bed));
  295. if ((DDRError->Bed.BertRev == CURRENT_BERT_VERSION)) {
  296. WrapBertErrorData (DDRError);
  297. WriteDDRBertTable (DDRError);
  298. }
  299. WriteSpinorDefaultBertTable (&(DDRError->Bed));
  300. }
  301. FreePool (DDRError);
  302. return EFI_SUCCESS;
  303. }
  304. /*
  305. * Checks Status of NV_SI_RAS_SDEI_ENABLED
  306. * Returns TRUE if enabled and FALSE if disabled or error occurred
  307. */
  308. BOOLEAN
  309. IsSdeiEnabled (
  310. VOID
  311. )
  312. {
  313. EFI_STATUS Status;
  314. UINT32 Value;
  315. Status = NVParamGet (
  316. NV_SI_RAS_SDEI_ENABLED,
  317. NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
  318. &Value
  319. );
  320. if (EFI_ERROR (Status)) {
  321. // SDEI is disabled by default
  322. return FALSE;
  323. }
  324. return (Value != 0) ? TRUE : FALSE;
  325. }
  326. STATIC
  327. VOID
  328. AcpiApeiHestUpdateTable1P (
  329. VOID
  330. )
  331. {
  332. EFI_STATUS Status;
  333. EFI_ACPI_SDT_PROTOCOL *AcpiTableSdtProtocol;
  334. EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER *HestTablePointer;
  335. UINTN TableKey;
  336. UINTN TableIndex;
  337. Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&AcpiTableSdtProtocol);
  338. if (EFI_ERROR (Status)) {
  339. DEBUG ((DEBUG_ERROR, "APEI: Unable to locate ACPI table support protocol\n"));
  340. return;
  341. }
  342. /*
  343. * Search for ACPI Table Signature
  344. */
  345. TableIndex = 0;
  346. Status = AcpiLocateTableBySignature (
  347. AcpiTableSdtProtocol,
  348. EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE,
  349. &TableIndex,
  350. (EFI_ACPI_DESCRIPTION_HEADER **)&HestTablePointer,
  351. &TableKey
  352. );
  353. if (EFI_ERROR (Status)) {
  354. DEBUG ((DEBUG_ERROR, "%a:%d Unable to get ACPI HEST table\n", __FUNCTION__, __LINE__));
  355. return;
  356. }
  357. HestTablePointer->ErrorSourceCount -= HEST_NUM_ENTRIES_PER_SOC;
  358. HestTablePointer->Header.Length -=
  359. (HEST_NUM_ENTRIES_PER_SOC *
  360. sizeof (EFI_ACPI_6_3_GENERIC_HARDWARE_ERROR_SOURCE_VERSION_2_STRUCTURE));
  361. AcpiUpdateChecksum ((UINT8 *)HestTablePointer, HestTablePointer->Header.Length);
  362. }
  363. /*
  364. * Update APEI
  365. *
  366. */
  367. EFI_STATUS
  368. EFIAPI
  369. AcpiApeiUpdate (
  370. VOID
  371. )
  372. {
  373. EFI_STATUS Status;
  374. ACPI_CONFIG_VARSTORE_DATA AcpiConfigData;
  375. UINTN BufferSize;
  376. BufferSize = sizeof (ACPI_CONFIG_VARSTORE_DATA);
  377. Status = gRT->GetVariable (
  378. L"AcpiConfigNVData",
  379. &gAcpiConfigFormSetGuid,
  380. NULL,
  381. &BufferSize,
  382. &AcpiConfigData
  383. );
  384. if (!EFI_ERROR (Status) && (AcpiConfigData.EnableApeiSupport == 0)) {
  385. AcpiApeiUninstallTable (EFI_ACPI_6_3_BOOT_ERROR_RECORD_TABLE_SIGNATURE);
  386. AcpiApeiUninstallTable (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE);
  387. AcpiApeiUninstallTable (EFI_ACPI_6_3_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE);
  388. AcpiApeiUninstallTable (EFI_ACPI_6_3_ERROR_INJECTION_TABLE_SIGNATURE);
  389. } else {
  390. if (!IsSlaveSocketActive ()) {
  391. AcpiApeiHestUpdateTable1P ();
  392. }
  393. }
  394. if (!IsSdeiEnabled ()) {
  395. AcpiApeiUninstallTable (EFI_ACPI_6_3_SOFTWARE_DELEGATED_EXCEPTIONS_INTERFACE_TABLE_SIGNATURE);
  396. }
  397. return EFI_SUCCESS;
  398. }