AcpiPlatformLibBdat.c 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574
  1. /** @file
  2. ACPI Platform Driver Hooks
  3. @copyright
  4. Copyright 1996 - 2020 Intel Corporation. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. //
  8. // Statements that include other files
  9. //
  10. #include "AcpiPlatformLibLocal.h"
  11. #include <Library/CrcLib.h>
  12. #include <BdatSchema.h>
  13. #include <Guid/MemoryMapData.h>
  14. #include <Library/CompressedVariableLib.h>
  15. #include <Protocol/DynamicSiLibraryProtocol2.h>
  16. #include <Protocol/DynamicSiLibraryProtocol2.h>
  17. extern struct SystemMemoryMapHob *mSystemMemoryMap;
  18. extern EFI_IIO_UDS_PROTOCOL *mIioUds;
  19. #include <Acpi/Bdat.h>
  20. #ifndef MAX_HOB_ENTRY_SIZE
  21. #define MAX_HOB_ENTRY_SIZE 60*1024
  22. #endif
  23. /**
  24. Save BSSA results to BDAT
  25. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  26. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  27. @param[in] SchemaStartAddress - Starting address where the BSSA result schema will be added
  28. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  29. @param[in] SchemaSize - The size of the BSSA results schema.
  30. @param[out] SchemaSpaceUsed - The numebr bytes were filled in all schema
  31. @param[out] LastSchemaSpaceUsed - The numebr bytes were filled in the last schema
  32. @retval EFI_SUCCESS - BSSA BDAT scehma created successfully
  33. @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed
  34. **/
  35. EFI_STATUS
  36. SaveBssaResultsToBdat (
  37. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  38. IN UINT32 OffsetFromLastSchema,
  39. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  40. IN OUT UINT8 *SchemaIndex,
  41. IN UINT32 SchemaSize,
  42. OUT UINT32 *SchemaSpaceUsed,
  43. OUT UINT32 *LastSchemaSpaceUsed
  44. );
  45. /**
  46. Save EWL results to BDAT
  47. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  48. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  49. @param[in] SchemaStartAddress - Starting address where the EWL schema will be added
  50. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  51. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  52. @retval EFI_SUCCESS - EWL BDAT scehma created successfully
  53. @retval !EFI_SUCCESS - EWL BDAT scehma creation failed
  54. **/
  55. EFI_STATUS
  56. SaveEwlToBdat (
  57. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  58. IN UINT32 OffsetFromLastSchema,
  59. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  60. IN OUT UINT8 *SchemaIndex,
  61. OUT UINT32 *SchemaSpaceUsed
  62. );
  63. /**
  64. Save SPD date structure to BDAT
  65. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  66. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  67. @param[in] SchemaStartAddress - Starting address where the SPD data schema will be added
  68. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  69. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  70. @retval EFI_SUCCESS - SPD BDAT scehma created successfully
  71. @retval !EFI_SUCCESS - SPD BDAT scehma creation failed
  72. **/
  73. EFI_STATUS
  74. SaveSpdToBdat (
  75. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  76. IN UINT32 OffsetFromLastSchema,
  77. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  78. IN OUT UINT8 *SchemaIndex,
  79. OUT UINT32 *SchemaSpaceUsed
  80. );
  81. /**
  82. Save memory training date structure to BDAT
  83. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  84. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  85. @param[in] SchemaStartAddress - Starting address where the memory training data schema will be added
  86. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  87. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  88. @retval EFI_SUCCESS - Memory training data BDAT scehma created successfully
  89. @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed
  90. **/
  91. EFI_STATUS
  92. SaveTrainingDataToBdat (
  93. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  94. IN UINT32 OffsetFromLastSchema,
  95. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  96. IN OUT UINT8 *SchemaIndex,
  97. OUT UINT32 *SchemaSpaceUsed
  98. );
  99. /**
  100. Get the size of SPD data structure not include the SPD BDAT schema header.
  101. @retval UINT32 - Size of SPD data structure in bytes
  102. **/
  103. UINT32
  104. GetSpdDataSize (
  105. VOID
  106. );
  107. /**
  108. Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space.
  109. @param[out] Address - Start Address of the buffer where the SPD entry to be filled
  110. @param[in] Socket - Socket number
  111. @param[in] Channel - Channel number inside the Socket
  112. @param[in] Dimm - Dimm slot number
  113. @param[in] MaxSpdByteOffset - The max SPD byte offset. DDR4 is 512
  114. @retval EFI_SUCCESS - SPD Structure filled successfully
  115. @retval !EFI_SUCCESS - SPD structure creation failed
  116. **/
  117. EFI_STATUS
  118. FillSpdPerDimmEntry (
  119. OUT EFI_PHYSICAL_ADDRESS Address,
  120. IN UINT8 Socket,
  121. IN UINT8 Channel,
  122. IN UINT8 Dimm,
  123. IN UINT16 MaxSpdByteOffset
  124. );
  125. /**
  126. Fill the SPD data structure inside the BDAT schema space.
  127. @param[out] StartAddress - Start Address of the buffer where SPD data structure to be filled
  128. @param[in] SpdDataSize - Size of SPD data structure includes the header
  129. @retval EFI_SUCCESS - SPD Structure filled successfully
  130. @retval !EFI_SUCCESS - SPD structure creation failed
  131. **/
  132. EFI_STATUS
  133. FillSpdSchema (
  134. OUT EFI_PHYSICAL_ADDRESS StartAddress,
  135. IN UINT32 SpdDataSize
  136. );
  137. /**
  138. Displays SPD content for debugging.
  139. @param[in] Address - The starting address of the SPD entry
  140. @retval N/A
  141. **/
  142. VOID
  143. DisplaySpdContents (
  144. IN EFI_PHYSICAL_ADDRESS Address
  145. );
  146. /**
  147. Get Number of Schemas From BSSA HOB
  148. @retval UINT16 - Number of BSSA Schemas
  149. **/
  150. UINT16
  151. GetNumberOfSchemasFromBssaHob (
  152. VOID
  153. )
  154. {
  155. UINT32 GuidIdx = 0;
  156. UINT16 NumberOfBssaSchemas = 0;
  157. EFI_STATUS Status = EFI_SUCCESS;
  158. DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
  159. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, (VOID **) &DynamicSiLibraryProtocol);
  160. if (EFI_ERROR (Status)) {
  161. ASSERT_EFI_ERROR (Status);
  162. return 0;
  163. }
  164. if (mSystemMemoryMap == NULL) {
  165. mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
  166. }
  167. ASSERT (mSystemMemoryMap != NULL);
  168. if (mSystemMemoryMap == NULL) {
  169. return 0;
  170. }
  171. for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) {
  172. //
  173. // No. of HOBS per GUID added up for all GUIDs created from calls to saveToBdat ()
  174. //
  175. NumberOfBssaSchemas += mSystemMemoryMap->Reserved7[GuidIdx];
  176. DEBUG ((DEBUG_VERBOSE, "GuidIdx = %d, total num hobs: %d\n", GuidIdx, mSystemMemoryMap->Reserved7[GuidIdx]));
  177. }
  178. return NumberOfBssaSchemas;
  179. }
  180. /**
  181. Create BDAT Header with necessary information.
  182. Allocate memory with BdatSize and if failure return status.
  183. If Success return the pointer address for copying the schema information
  184. @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure
  185. @param[in] BdatSize - Size of BDAT Structure
  186. @param[in] NumberOfSchema - Total nunber of of schema
  187. @retval EFI_SUCCESS - BDAT Structure created successfully
  188. @retval !EFI_SUCCESS - BDAT structure creation failed
  189. **/
  190. EFI_STATUS
  191. CreateBdatHeader (
  192. OUT BDAT_STRUCTURE **BdatHeaderStructPtr,
  193. IN UINT32 BdatSize,
  194. IN UINT16 NumberOfSchema
  195. )
  196. {
  197. EFI_TIME EfiTime;
  198. UINT64 Address = 0xffffffff;
  199. EFI_STATUS Status = EFI_SUCCESS;
  200. //
  201. // Allocating RealTime Memory for BDAT.
  202. //
  203. Status = gBS->AllocatePages (
  204. AllocateMaxAddress,
  205. EfiACPIMemoryNVS,
  206. EFI_SIZE_TO_PAGES(BdatSize),
  207. &Address
  208. );
  209. if (EFI_ERROR (Status)) {
  210. return Status;
  211. }
  212. //
  213. // The memory location where the HOB's are to be copied to
  214. //
  215. ZeroMem ((VOID *)Address, BdatSize);
  216. *BdatHeaderStructPtr = (BDAT_STRUCTURE *)Address;
  217. DEBUG ((DEBUG_VERBOSE, "\nBDAT Allocated Address = %x\n", Address));
  218. //
  219. // Create BIOS Data Signature
  220. //
  221. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[0] = 'B';
  222. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[1] = 'D';
  223. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[2] = 'A';
  224. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[3] = 'T';
  225. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[4] = 'H';
  226. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[5] = 'E';
  227. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[6] = 'A';
  228. (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[7] = 'D';
  229. //
  230. // Structure size
  231. //
  232. (*BdatHeaderStructPtr)->BdatHeader.BiosDataStructSize = BdatSize;
  233. //
  234. // Primary Version
  235. //
  236. (*BdatHeaderStructPtr)->BdatHeader.PrimaryVersion = BDAT_PRIMARY_VER;
  237. //
  238. // Secondary Version
  239. //
  240. (*BdatHeaderStructPtr)->BdatHeader.SecondaryVersion = BDAT_SECONDARY_VER;
  241. //
  242. // CRC16 value of the BDAT_STRUCTURE
  243. //
  244. (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0;
  245. Status = CalculateCrc16 (
  246. (VOID *)(*BdatHeaderStructPtr),
  247. BdatSize,
  248. &(*BdatHeaderStructPtr)->BdatHeader.Crc16
  249. );
  250. ASSERT_EFI_ERROR (Status);
  251. if (EFI_ERROR (Status)) {
  252. (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0xFFFF;
  253. }
  254. (*BdatHeaderStructPtr)->BdatSchemas.SchemaListLength = NumberOfSchema;
  255. (*BdatHeaderStructPtr)->BdatSchemas.Reserved = 0;
  256. (*BdatHeaderStructPtr)->BdatSchemas.Reserved1 = 0;
  257. //
  258. // Initialize the Time parameters in the SCHEMA_LIST_STRUCTURE
  259. //
  260. Status = gRT->GetTime (&EfiTime, NULL);
  261. if (!EFI_ERROR (Status)) {
  262. (*BdatHeaderStructPtr)->BdatSchemas.Year = EfiTime.Year;
  263. (*BdatHeaderStructPtr)->BdatSchemas.Month = EfiTime.Month;
  264. (*BdatHeaderStructPtr)->BdatSchemas.Day = EfiTime.Day;
  265. (*BdatHeaderStructPtr)->BdatSchemas.Hour = EfiTime.Hour;
  266. (*BdatHeaderStructPtr)->BdatSchemas.Minute = EfiTime.Minute;
  267. (*BdatHeaderStructPtr)->BdatSchemas.Second = EfiTime.Second;
  268. }
  269. return Status;
  270. }
  271. /**
  272. Dump BDAT Table to serial log
  273. Example 1: There are 2 schema: BSSA RMT and EWL.
  274. Print BDAT Table
  275. Address 0 1 2 3 4 5 6 7 8 9 A B C D E F
  276. 00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x30 0x18 0x00 0x00 0xD7 0x7A 0x00 0x00
  277. 00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  278. 00000020 0x02 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x00 0x29 0x03 0x00 0x34 0x00 0x00 0x00
  279. 00000030 0xFA 0x07 0x00 0x00 0x28 0xE9 0xF4 0x08 0x5F 0x0F 0xD4 0x46 0x84 0x10 0x47 0x9F
  280. 00000040 0xDA 0x27 0x9D 0xB6 0xC6 0x07 0x00 0x00 0x57 0x7F 0x00 0x00 0x00 0x00 0x00 0xA5
  281. 00000050 0x98 0x88 0xFE 0x4C 0x00 0x00 0x00 0x0D 0xEB 0x7A 0x47 0x07 0xDE 0x77 0x42 0xA4
  282. 00000060 0xE7 0x87 0x81 0x0B 0x10 0x00 0x31 0xF1 0x98 0x88 0xFE 0xF2 0x45 0x81 0xD9 0xF4
  283. ...
  284. ...
  285. 000007F0 0x00 0x00 0x00 0x5A 0xA5 0x5A 0xA5 0x5A 0xA5 0x5A 0x2F 0x53 0xFE 0xBF 0x3B 0xCA
  286. 00000800 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D 0x36 0x10 0x00 0x00 0x9F 0xEF
  287. 00000810 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED 0x60 0xF2 0x82 0x48 0x6C 0xFC
  288. 00000820 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81 0x50 0x51 0x00 0x00 0x00 0x00
  289. 00000830 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00 0x7E 0x07 0x17 0x18 0x01 0xFF
  290. 00000840 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  291. Example 2: There is 1 schema: EWL
  292. Address 0 1 2 3 4 5 6 7 8 9 A B C D E F
  293. 00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x66 0x10 0x00 0x00 0xA9 0x44 0x00 0x00
  294. 00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  295. 00000020 0x01 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x01 0x0F 0x2C 0x00 0x30 0x00 0x00 0x00
  296. 00000030 0x2F 0x53 0xFE 0xBF 0x3B 0xCA 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D
  297. 00000040 0x36 0x10 0x00 0x00 0x9F 0xEF 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED
  298. 00000050 0x60 0xF2 0x82 0x48 0x6C 0xFC 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81
  299. 00000060 0x50 0x51 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00
  300. 00000070 0x7E 0x07 0x17 0x18 0x01 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  301. 00000080 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  302. @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure
  303. @param[in] BdatSize - Size of BDAT Structure
  304. @retval None
  305. **/
  306. VOID
  307. DumpBdatTable(
  308. IN BDAT_STRUCTURE **BdatHeaderStructPtr,
  309. IN UINT32 BdatSize
  310. )
  311. {
  312. UINT32 i = 0;
  313. UINT8 *Table = NULL;
  314. Table = (UINT8 *)(*BdatHeaderStructPtr);
  315. DEBUG ((DEBUG_VERBOSE, "\nPrint BDAT Table\n"));
  316. //
  317. // Print address header
  318. //
  319. DEBUG ((DEBUG_VERBOSE, "Address "));
  320. for (i = 0; i < 16; i++) {
  321. DEBUG ((DEBUG_VERBOSE, " %01x", i));
  322. }
  323. i = 0;
  324. while (i < BdatSize) {
  325. if ((i % 16) == 0) {
  326. DEBUG ((DEBUG_VERBOSE, "\n%08x ", (i / 16) * 16));
  327. } else {
  328. DEBUG ((DEBUG_VERBOSE, " "));
  329. }
  330. DEBUG ((DEBUG_VERBOSE, "0x%02x", Table[i]));
  331. if (i == BdatSize - 1) {
  332. DEBUG ((DEBUG_VERBOSE, "\n"));
  333. }
  334. i++;
  335. }
  336. DEBUG ((DEBUG_VERBOSE, "\n"));
  337. }
  338. /**
  339. Copy BDAT Table pointer to scratchpad 5 register
  340. @param[in] BdatAddress - Bdat Table Address to be copied to Scratchpad 5 register
  341. @retval None
  342. **/
  343. VOID
  344. CopyBdatPointerToScratchPad5 (
  345. IN UINT64 BdatAddress
  346. )
  347. {
  348. UINT8 Socket = 0;
  349. EFI_STATUS Status = EFI_SUCCESS;
  350. DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
  351. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, (VOID **) &DynamicSiLibraryProtocol);
  352. if (EFI_ERROR (Status)) {
  353. ASSERT_EFI_ERROR (Status);
  354. return;
  355. }
  356. //
  357. // Copy BDAT base address to ScratchPad5
  358. //
  359. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  360. if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) {
  361. DynamicSiLibraryProtocol->WriteScratchpad5 (Socket, (UINT32) BdatAddress);
  362. DEBUG ((DEBUG_VERBOSE, "Scratchpad_Debug PatchBdaAcpiTable: Verify Non Sticky Scratchpad5 0x%08x\n", BdatAddress));
  363. }
  364. }
  365. }
  366. /**
  367. Update the BDAT ACPI table: Multiple instances of the BDAT DATA HOB are placed into one contiguos memory range
  368. @param *TableHeader - The table to be set
  369. @retval EFI_SUCCESS - Returns Success
  370. **/
  371. EFI_STATUS
  372. PatchBdatAcpiTable (
  373. IN OUT EFI_ACPI_COMMON_HEADER *Table
  374. )
  375. {
  376. EFI_STATUS Status = EFI_SUCCESS;
  377. EFI_PHYSICAL_ADDRESS Address = 0;
  378. UINT32 Idx = 0;
  379. UINT8 Checksum = 0;
  380. BDAT_STRUCTURE *BdatHeaderStructPtr = NULL;
  381. UINT32 TotalBDATstructureSize = 0;
  382. UINT32 BdatHeaderSize = 0;
  383. EFI_HOB_GUID_TYPE *GuidHob = NULL;
  384. UINT16 NumberBssaSchemas = 0;
  385. UINT16 TotalNumberSchemas = 0;
  386. UINT32 BssaSchemaSize = 0;
  387. EFI_BDAT_ACPI_DESCRIPTION_TABLE *BdatAcpiTable = NULL;
  388. EWL_PRIVATE_DATA *EwlPrivateData = NULL;
  389. EFI_GUID EWLDataGuid = EWL_ID_GUID;
  390. UINT32 EwlSchemaSize = 0;
  391. MEM_TRAINING_DATA_STRUCTURE *MemTrainingData = NULL;
  392. MEM_TRAINING_DATA_HOB_HEADER *TrainingDataHobHeader = NULL;
  393. UINT32 TrainingDataSchemaSize = 0;
  394. UINT32 RemainingSchemaSpace = 0;
  395. UINT32 SpdDataSize = 0;
  396. UINT32 SpdSchemaSize = 0;
  397. UINT8 SchemaIndex = 0;
  398. UINT32 SpaceUsed = 0;
  399. UINT32 LastSchemaSpaceUsed = 0;
  400. UINT32 OffsetFromLastSchema = 0;
  401. BdatAcpiTable = (EFI_BDAT_ACPI_DESCRIPTION_TABLE *)Table;
  402. DEBUG ((DEBUG_INFO, "\nPatchBdatAcpiTable Started\n"));
  403. //
  404. // Gather BSSA schema info
  405. //
  406. NumberBssaSchemas = GetNumberOfSchemasFromBssaHob ();
  407. BssaSchemaSize = mSystemMemoryMap->Reserved6 + (NumberBssaSchemas * sizeof (BDAT_SCHEMA_HEADER_STRUCTURE)); //Total size of all HOBs created by SaveToBdat() + NumberBssaSchemas*headerPerSchema
  408. DEBUG ((DEBUG_VERBOSE, "NumberBssaSchemas = %d, total BSSA schema size: %d\n", NumberBssaSchemas, BssaSchemaSize));
  409. TotalNumberSchemas = NumberBssaSchemas;
  410. TotalBDATstructureSize += BssaSchemaSize;
  411. //
  412. // Gather EWL schema info
  413. //
  414. GuidHob = GetFirstGuidHob (&EWLDataGuid);
  415. if (GuidHob != NULL) {
  416. DEBUG ((DEBUG_VERBOSE, "Found EWL with GUID %g\n", &EWLDataGuid));
  417. TotalNumberSchemas += 1;
  418. EwlPrivateData = GET_GUID_HOB_DATA (GuidHob);
  419. EwlSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + EwlPrivateData->status.Header.Size;
  420. DEBUG ((DEBUG_VERBOSE, "EWL schema size: %d\n", EwlSchemaSize));
  421. TotalBDATstructureSize += EwlSchemaSize;
  422. }
  423. //
  424. // Gather SPD schema info
  425. //
  426. SpdSchemaSize = 0;
  427. if (PcdGetBool (SaveSpdToBdat)) {
  428. SpdDataSize = GetSpdDataSize ();
  429. if (SpdDataSize > 0) {
  430. TotalNumberSchemas += 1;
  431. SpdSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + SpdDataSize;
  432. DEBUG ((DEBUG_VERBOSE, "SPD data schema size: %d\n", SpdSchemaSize));
  433. TotalBDATstructureSize += SpdSchemaSize;
  434. }
  435. } // PcdGetBool (SaveSpdToBdat)
  436. //
  437. // Gather Memory training data schema info
  438. //
  439. TrainingDataSchemaSize = 0;
  440. if (PcdGetBool (SaveMrcTrainingDataToBdat)) {
  441. GuidHob = GetFirstGuidHob (&gMemTrainingDataHobGuid);
  442. if (GuidHob != NULL) {
  443. DEBUG ((DEBUG_VERBOSE, "Found memory training data HOB with GUID %g\n", &gMemTrainingDataHobGuid));
  444. TotalNumberSchemas += 1;
  445. TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
  446. MemTrainingData = (MEM_TRAINING_DATA_STRUCTURE *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER));
  447. TrainingDataSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + MemTrainingData->Header.Size;
  448. DEBUG ((DEBUG_VERBOSE, "Memory training data schema size: %d\n", TrainingDataSchemaSize));
  449. TotalBDATstructureSize += TrainingDataSchemaSize;
  450. }
  451. } // PcdGetBool (SaveMrcTrainingDataToBdat)
  452. BdatHeaderSize = sizeof (BDAT_STRUCTURE) + (TotalNumberSchemas * (sizeof (UINT32)));
  453. TotalBDATstructureSize += BdatHeaderSize;
  454. //
  455. // This variable is used to keep track the remain space in the BDAT payload (schema section) to
  456. // prevent overflow the allocated RT BDAT buffer.
  457. //
  458. RemainingSchemaSpace = TotalBDATstructureSize - BdatHeaderSize;
  459. DEBUG ((DEBUG_INFO, "Total BDAT size:%d, BDAT header size: %d, Total schema:%d \n", TotalBDATstructureSize, BdatHeaderSize, TotalNumberSchemas));
  460. Status = CreateBdatHeader (&BdatHeaderStructPtr, TotalBDATstructureSize, TotalNumberSchemas);
  461. if (EFI_ERROR (Status)) {
  462. return Status;
  463. }
  464. DEBUG ((DEBUG_INFO, "BdatRegionAddress = 0x%x\n", (UINT64)BdatHeaderStructPtr));
  465. CopyBdatPointerToScratchPad5 ((UINT64)BdatHeaderStructPtr);
  466. //
  467. // Update BDAT ACPI table
  468. //
  469. BdatAcpiTable->BdatGas.Address = (UINT64)BdatHeaderStructPtr;
  470. //
  471. // Starting address of the first schema
  472. //
  473. Address = (EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + BdatHeaderSize;
  474. //
  475. // Saving to RT Memory BDAT Data received from HOBs generated due to BSSA call/calls to SaveToBdat()
  476. //
  477. SpaceUsed = 0;
  478. //
  479. // The first schema starts right after the BDAT header structure
  480. //
  481. LastSchemaSpaceUsed = BdatHeaderSize; // It will used as the OffsetFromLastSchema for the next schema if BSSA is not available
  482. OffsetFromLastSchema = BdatHeaderSize;
  483. if (BssaSchemaSize > 0) {
  484. Status = SaveBssaResultsToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, BssaSchemaSize, &SpaceUsed, &LastSchemaSpaceUsed);
  485. if (Status != EFI_SUCCESS) {
  486. DEBUG ((DEBUG_ERROR, "Faield to add BSSA result to BDAT\n"));
  487. }
  488. }
  489. //
  490. // Update the starting address of next schema and remaining space.
  491. //
  492. Address += SpaceUsed;
  493. RemainingSchemaSpace -= SpaceUsed;
  494. OffsetFromLastSchema = LastSchemaSpaceUsed;
  495. //
  496. // Saving to RT Memory BDAT Data received from EWL HOB
  497. //
  498. SpaceUsed = 0;
  499. if (EwlSchemaSize > 0) {
  500. if (RemainingSchemaSpace < EwlSchemaSize) {
  501. DEBUG ((DEBUG_ERROR, "Not enough space to add EWL schema.\n"));
  502. goto End;
  503. }
  504. Status = SaveEwlToBdat (BdatHeaderStructPtr, OffsetFromLastSchema ,&Address, &SchemaIndex, &SpaceUsed);
  505. if (Status != EFI_SUCCESS) {
  506. DEBUG ((DEBUG_ERROR, "Failed to add EWL to BDAT.\n"));
  507. }
  508. }
  509. //
  510. // Update the starting address of next schema and remaining space.
  511. //
  512. Address += SpaceUsed;
  513. RemainingSchemaSpace -= SpaceUsed;
  514. OffsetFromLastSchema = SpaceUsed;
  515. //
  516. // Add SPD schema
  517. //
  518. SpaceUsed = 0;
  519. if (SpdSchemaSize > 0) {
  520. if (RemainingSchemaSpace < SpdSchemaSize) {
  521. DEBUG ((DEBUG_ERROR, "Not enough space to add SPD schema.\n"));
  522. goto End;
  523. }
  524. Status = SaveSpdToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed);
  525. if (Status != EFI_SUCCESS) {
  526. DEBUG ((DEBUG_ERROR, "Failed to add SPD to BDAT.\n"));
  527. }
  528. }
  529. //
  530. // Update the starting address of next schema and remaining space.
  531. //
  532. Address += SpaceUsed;
  533. RemainingSchemaSpace -= SpaceUsed;
  534. OffsetFromLastSchema = SpaceUsed;
  535. //
  536. // Add memory training data schema
  537. //
  538. SpaceUsed = 0;
  539. if (TrainingDataSchemaSize > 0) {
  540. if (RemainingSchemaSpace < TrainingDataSchemaSize) {
  541. DEBUG ((DEBUG_ERROR, "Not enough space to add memory training data schema.\n"));
  542. goto End;
  543. }
  544. Status = SaveTrainingDataToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed);
  545. if (Status != EFI_SUCCESS) {
  546. DEBUG ((DEBUG_ERROR, "Failed to add memory training data to BDAT.\n"));
  547. }
  548. }
  549. //
  550. // Update the starting address of next schema and remaining space.
  551. //
  552. Address += SpaceUsed;
  553. RemainingSchemaSpace -= SpaceUsed;
  554. OffsetFromLastSchema = SpaceUsed;
  555. DEBUG ((DEBUG_VERBOSE, "Final SchemaIndex:%d RemainingSchemaSpace:%d\n", SchemaIndex, RemainingSchemaSpace));
  556. End:
  557. //
  558. // Update checksum
  559. //
  560. BdatAcpiTable->Header.Checksum = 0;
  561. Checksum = 0;
  562. for(Idx = 0; Idx < sizeof(EFI_BDAT_ACPI_DESCRIPTION_TABLE); Idx++) {
  563. Checksum = Checksum + (UINT8) (((UINT8 *)(BdatAcpiTable))[Idx]);
  564. }
  565. BdatAcpiTable->Header.Checksum = (UINT8) (0 - Checksum);
  566. DumpBdatTable (&BdatHeaderStructPtr, TotalBDATstructureSize);
  567. return Status;
  568. }
  569. /**
  570. Displays SPD content for debugging.
  571. @param[in] Address - The starting address of the SPD entry
  572. @retval N/A
  573. **/
  574. VOID
  575. DisplaySpdContents (
  576. IN EFI_PHYSICAL_ADDRESS Address
  577. )
  578. {
  579. UINT16 Index;
  580. MEM_SPD_ENTRY_TYPE0 *EntryHeaderPtr;
  581. EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0 *)Address;
  582. //
  583. // Print the Socket, Channel and Dimm information.
  584. //
  585. DEBUG ((DEBUG_VERBOSE, "START_PRINT_SPD S%dC%dD%d:\n",
  586. EntryHeaderPtr->MemoryLocation.Socket,
  587. EntryHeaderPtr->MemoryLocation.Channel,
  588. EntryHeaderPtr->MemoryLocation.Dimm));
  589. //
  590. // Print the Column Number of the SPD data.
  591. //
  592. for (Index = 0; Index < 0x10; Index++) {
  593. DEBUG ((DEBUG_VERBOSE, " %02x", Index));
  594. }
  595. Address += sizeof (MEM_SPD_ENTRY_TYPE0);
  596. for (Index = 0; Index < EntryHeaderPtr->NumberOfBytes; Index++) {
  597. //
  598. // Print the Carriage Return and Byte Index of SPD data.
  599. //
  600. if ((Index % 0x10) == 0) {
  601. //
  602. // Split the SPD data for every 256 bytes
  603. //
  604. if (((Index % 0x100) == 0) && (Index != 0)) {
  605. DEBUG ((DEBUG_VERBOSE, "\n"));
  606. }
  607. DEBUG ((DEBUG_VERBOSE, "\n%02x:", (UINT8) (Index & 0x00F0)));
  608. }
  609. DEBUG ((DEBUG_VERBOSE, " %02x", *(UINT8 *)(Address + (EFI_PHYSICAL_ADDRESS)Index)));
  610. }
  611. DEBUG ((DEBUG_VERBOSE, "\n"));
  612. DEBUG ((DEBUG_VERBOSE, "STOP_PRINT_SPD\n"));
  613. } // DisplaySpdContents
  614. /**
  615. Get the size of SPD data structure not include the SPD BDAT schema header.
  616. @retval UINT32 - Size of SPD data structure in bytes
  617. **/
  618. UINT32
  619. GetSpdDataSize (
  620. VOID
  621. )
  622. {
  623. UINT32 SchemaSize = 0;
  624. UINT8 Socket;
  625. UINT8 Channel;
  626. UINT8 Dimm;
  627. UINT32 SpdBytesPerDimm = 0;
  628. UINT8 NumberOfDimmPresent = 0;
  629. EFI_STATUS Status = EFI_SUCCESS;
  630. DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
  631. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, (VOID **) &DynamicSiLibraryProtocol);
  632. if (EFI_ERROR (Status)) {
  633. ASSERT_EFI_ERROR (Status);
  634. return 0;
  635. }
  636. if (mSystemMemoryMap == NULL) {
  637. mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
  638. }
  639. if (mSystemMemoryMap == NULL) {
  640. return 0;
  641. }
  642. ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4);
  643. SpdBytesPerDimm = MAX_SPD_BYTE_DDR4;
  644. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  645. for (Channel = 0; Channel < MAX_CH; Channel++) {
  646. for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) {
  647. if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) {
  648. NumberOfDimmPresent += 1;
  649. }
  650. }
  651. }
  652. }
  653. //
  654. // Total entries
  655. //
  656. SchemaSize = (SpdBytesPerDimm + sizeof (MEM_SPD_ENTRY_TYPE0)) * NumberOfDimmPresent;
  657. //
  658. // Add the SPD raw data header
  659. //
  660. SchemaSize += sizeof (MEM_SPD_RAW_DATA_HEADER);
  661. return SchemaSize;
  662. }
  663. /**
  664. Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space.
  665. @param[out] Address - Start Address of the buffer where the SPD entry to be filled
  666. @param[in] Socket - Socket number
  667. @param[in] Channel - Channel number inside the Socket
  668. @param[in] Dimm - Dimm slot number
  669. @param[in] MaxSpdByteOffset - The max SPD byte offset. DDR4 is 512
  670. @retval EFI_SUCCESS - SPD Structure filled successfully
  671. @retval !EFI_SUCCESS - SPD structure creation failed
  672. **/
  673. EFI_STATUS
  674. FillSpdPerDimmEntry (
  675. OUT EFI_PHYSICAL_ADDRESS Address,
  676. IN UINT8 Socket,
  677. IN UINT8 Channel,
  678. IN UINT8 Dimm,
  679. IN UINT16 MaxSpdByteOffset
  680. )
  681. {
  682. UINT16 SpdByteOffset = 0;
  683. UINT8 SpdData = 0;
  684. MEM_SPD_ENTRY_TYPE0 *EntryHeaderPtr;
  685. EFI_STATUS Status = EFI_SUCCESS;
  686. DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
  687. DEBUG ((DEBUG_VERBOSE, "Fill Spd entry for Socket:%d Channel:%d Dimm:%d at location:0x%x \n", Socket, Channel, Dimm, Address));
  688. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, (VOID **) &DynamicSiLibraryProtocol2);
  689. if (EFI_ERROR (Status)) {
  690. ASSERT_EFI_ERROR (Status);
  691. return Status;
  692. }
  693. EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0 *)Address;
  694. //
  695. // Add the entry header. We use type 0.
  696. //
  697. EntryHeaderPtr->Header.Type = MemSpdDataType0;
  698. EntryHeaderPtr->Header.Size = sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
  699. EntryHeaderPtr->MemoryLocation.Socket = Socket;
  700. EntryHeaderPtr->MemoryLocation.Channel = Channel;
  701. EntryHeaderPtr->MemoryLocation.Dimm = Dimm;
  702. EntryHeaderPtr->NumberOfBytes = MaxSpdByteOffset;
  703. Address += sizeof (MEM_SPD_ENTRY_TYPE0);
  704. for (SpdByteOffset = 0; SpdByteOffset < MaxSpdByteOffset; SpdByteOffset++) {
  705. Status = DynamicSiLibraryProtocol2->SpdReadByte (Socket, Channel, Dimm, SpdByteOffset, &SpdData);
  706. if (EFI_ERROR (Status)) {
  707. DEBUG ((DEBUG_WARN, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d SpdByteOffset:%d Status:0x%x\n",
  708. Socket, Channel, Dimm, SpdByteOffset, Status));
  709. return Status;
  710. }
  711. *(UINT8 *)Address = SpdData;
  712. Address += 1;
  713. } // SpdByteOffset
  714. return Status;
  715. }
  716. /**
  717. Fill the SPD data structure inside the BDAT schema space.
  718. @param[out] StartAddress - Start Address of the buffer where SPD data structure to be filled
  719. @param[in] SpdDataSize - Size of SPD data structure includes the header
  720. @retval EFI_SUCCESS - SPD Structure filled successfully
  721. @retval !EFI_SUCCESS - SPD structure creation failed
  722. **/
  723. EFI_STATUS
  724. FillSpdSchema (
  725. OUT EFI_PHYSICAL_ADDRESS StartAddress,
  726. IN UINT32 SpdDataSize
  727. )
  728. {
  729. UINT8 Socket;
  730. UINT8 Channel;
  731. UINT8 Dimm;
  732. UINT16 MaxSpdByteOffset = 0;
  733. UINT32 RemainedSpace;
  734. EFI_PHYSICAL_ADDRESS Address;
  735. MEM_SPD_RAW_DATA_HEADER *SpdDataHeaderStructPtr;
  736. EFI_STATUS Status = EFI_SUCCESS;
  737. DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
  738. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, (VOID **) &DynamicSiLibraryProtocol);
  739. if (EFI_ERROR (Status)) {
  740. ASSERT_EFI_ERROR (Status);
  741. return Status;
  742. }
  743. if (mSystemMemoryMap == NULL) {
  744. mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData ();
  745. }
  746. if (mSystemMemoryMap == NULL) {
  747. return EFI_DEVICE_ERROR;;
  748. }
  749. if (StartAddress == 0) {
  750. return EFI_INVALID_PARAMETER;
  751. }
  752. RemainedSpace = SpdDataSize;
  753. Address = StartAddress;
  754. SpdDataHeaderStructPtr = (MEM_SPD_RAW_DATA_HEADER *)StartAddress;
  755. //
  756. // Fill up the header of the SPD data strcuture
  757. //
  758. SpdDataHeaderStructPtr->MemSpdGuid = gSpdVersion1Guid;
  759. SpdDataHeaderStructPtr->Size = SpdDataSize;
  760. SpdDataHeaderStructPtr->Reserved = 0;
  761. Address += sizeof (MEM_SPD_RAW_DATA_HEADER);
  762. RemainedSpace -= sizeof (MEM_SPD_RAW_DATA_HEADER);
  763. ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4);
  764. MaxSpdByteOffset = MAX_SPD_BYTE_DDR4;
  765. //
  766. // Iterate through all populated DIMMs and add them
  767. //
  768. for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
  769. for (Channel = 0; Channel < MAX_CH; Channel++) {
  770. for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) {
  771. if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) {
  772. if (RemainedSpace < sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset) {
  773. DEBUG ((DEBUG_ERROR, "Run out of allocated SPD data space. RemainedSpace:%d required space:%d\n",
  774. RemainedSpace, sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset));
  775. return RETURN_OUT_OF_RESOURCES;
  776. }
  777. Status = FillSpdPerDimmEntry (Address, Socket, Channel, Dimm, MaxSpdByteOffset);
  778. if (EFI_ERROR (Status)) {
  779. DEBUG ((DEBUG_ERROR, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d Status:0x%x.\n", Socket, Channel, Dimm, Status));
  780. return Status;
  781. }
  782. DisplaySpdContents (Address);
  783. Address += sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
  784. RemainedSpace -= sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset;
  785. }
  786. } // Dimm
  787. } // Channel
  788. } // Socket
  789. //
  790. // Update CRC
  791. //
  792. SpdDataHeaderStructPtr->Crc = 0;
  793. SpdDataHeaderStructPtr->Crc = CalculateCrc32 ((VOID *) SpdDataHeaderStructPtr, SpdDataHeaderStructPtr->Size);
  794. return EFI_SUCCESS;
  795. }
  796. /**
  797. Save BSSA results to BDAT
  798. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  799. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  800. @param[in] SchemaStartAddress - Starting address where the BSSA result schema will be added
  801. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  802. @param[in] SchemaSize - The size of the BSSA results schema.
  803. @param[out] SchemaSpaceUsed - The numebr bytes were filled in all schema
  804. @param[out] LastSchemaSpaceUsed - The numebr bytes were filled in the last schema
  805. @retval EFI_SUCCESS - BSSA BDAT scehma created successfully
  806. @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed
  807. **/
  808. EFI_STATUS
  809. SaveBssaResultsToBdat (
  810. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  811. IN UINT32 OffsetFromLastSchema,
  812. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  813. IN OUT UINT8 *SchemaIndex,
  814. IN UINT32 SchemaSize,
  815. OUT UINT32 *SchemaSpaceUsed,
  816. OUT UINT32 *LastSchemaSpaceUsed
  817. )
  818. {
  819. EFI_STATUS Status = EFI_SUCCESS;
  820. UINT32 *SchemaAddrLocationArray = NULL;
  821. UINT32 CurrentHobSize = 0;
  822. EFI_HOB_GUID_TYPE *GuidHob = NULL;
  823. VOID *HobData = NULL;
  824. UINT32 PreviousSchemaSize = 0;
  825. EFI_GUID gEfiMemoryMapDataHobBdatBssaGuid = {0};
  826. UINT32 GuidIdx = 0;
  827. UINT32 HobIdx = 0;
  828. UINT32 RemainingHobSizeBssaSchema = 0;
  829. BDAT_SCHEMA_HEADER_STRUCTURE *BssaSchemaHeaderPtr = NULL;
  830. EFI_PHYSICAL_ADDRESS Address = 0;
  831. if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
  832. return EFI_INVALID_PARAMETER;
  833. }
  834. RemainingHobSizeBssaSchema = SchemaSize;
  835. Address = *SchemaStartAddress;
  836. *SchemaSpaceUsed = 0;
  837. //
  838. // Update the schema offset array for its first BSSA schema
  839. //
  840. SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
  841. if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
  842. if (*SchemaIndex == 0) {
  843. SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
  844. }
  845. else {
  846. SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
  847. }
  848. }
  849. for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) {
  850. gEfiMemoryMapDataHobBdatBssaGuid = mSystemMemoryMap->Reserved8[GuidIdx]; //get first GUID instance
  851. GuidHob = GetFirstGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid);
  852. for (HobIdx = 0; HobIdx < mSystemMemoryMap->Reserved7[GuidIdx]; HobIdx++) { //looping through all HOBs linked to that GUID
  853. ASSERT (GuidHob != NULL);
  854. if (GuidHob == NULL) {
  855. return EFI_NOT_FOUND;
  856. }
  857. HobData = GET_GUID_HOB_DATA (GuidHob);
  858. CurrentHobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
  859. DEBUG ((DEBUG_VERBOSE, "Initial HOB size %d; remaining HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema));
  860. //
  861. // Setting the header first
  862. //
  863. if (RemainingHobSizeBssaSchema < sizeof(BDAT_SCHEMA_HEADER_STRUCTURE)) {
  864. //
  865. // Nothing we can do, break execution
  866. //
  867. DEBUG ((DEBUG_WARN, "Not enough space to add schema header to BIOS SSA result\n"));
  868. RemainingHobSizeBssaSchema = 0;
  869. break;
  870. }
  871. //
  872. // Each HOB has a header added to it (BDAT_SCHEMA_HEADER_STRUCTURE)
  873. //
  874. Address = Address + (EFI_PHYSICAL_ADDRESS)PreviousSchemaSize;
  875. BssaSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
  876. BssaSchemaHeaderPtr->SchemaId = gEfiMemoryMapDataHobBdatBssaGuid;
  877. RemainingHobSizeBssaSchema -= sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  878. *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  879. Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  880. //
  881. // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
  882. //
  883. BssaSchemaHeaderPtr->Crc16 = 0;
  884. Status = CalculateCrc16 (
  885. (VOID *) BssaSchemaHeaderPtr,
  886. sizeof (BDAT_SCHEMA_HEADER_STRUCTURE),
  887. &BssaSchemaHeaderPtr->Crc16
  888. );
  889. ASSERT_EFI_ERROR (Status);
  890. if (EFI_ERROR (Status)) {
  891. BssaSchemaHeaderPtr->Crc16 = 0xFFFF;
  892. }
  893. if (RemainingHobSizeBssaSchema < CurrentHobSize) {
  894. DEBUG ((DEBUG_WARN, "Not enough space to add complete BIOS SSA result\n"));
  895. CurrentHobSize = RemainingHobSizeBssaSchema;
  896. }
  897. //
  898. // HOB size won't overflow a UINT32.
  899. //
  900. BssaSchemaHeaderPtr->DataSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  901. DEBUG ((DEBUG_VERBOSE, "Setting schema %g size to %d\n", &(BssaSchemaHeaderPtr->SchemaId), BssaSchemaHeaderPtr->DataSize));
  902. //
  903. // HOB size won't overflow a UINT32.
  904. //
  905. PreviousSchemaSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  906. //
  907. // Copy HOB to RT Memory
  908. //
  909. CopyMem ((VOID *)Address, (VOID *)HobData, (UINT32)CurrentHobSize);
  910. //
  911. // HOB size won't overflow a UINT32.
  912. //
  913. DEBUG ((DEBUG_VERBOSE, "HOB size %d; remaining SSA HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema));
  914. RemainingHobSizeBssaSchema -= (UINT32)CurrentHobSize;
  915. *SchemaSpaceUsed = *SchemaSpaceUsed + (UINT32)CurrentHobSize;
  916. *SchemaIndex = *SchemaIndex + 1;
  917. if (RemainingHobSizeBssaSchema == 0) {
  918. break;
  919. }
  920. GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB
  921. GuidHob = GetNextGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid, GuidHob); // Now search for next instance of the BDAT HOB
  922. if (GuidHob == NULL) {
  923. break;
  924. }
  925. //
  926. // Update the schema offset arrary
  927. //
  928. if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
  929. SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + PreviousSchemaSize;
  930. }
  931. }
  932. if (RemainingHobSizeBssaSchema == 0) {
  933. break;
  934. }
  935. }
  936. *LastSchemaSpaceUsed = PreviousSchemaSize;
  937. return EFI_SUCCESS;
  938. } // SaveBssaResultsToBdat
  939. /**
  940. Save EWL results to BDAT
  941. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  942. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  943. @param[in] SchemaStartAddress - Starting address where the EWL schema will be added
  944. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  945. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  946. @retval EFI_SUCCESS - EWL BDAT scehma created successfully
  947. @retval !EFI_SUCCESS - EWL BDAT scehma creation failed
  948. **/
  949. EFI_STATUS
  950. SaveEwlToBdat (
  951. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  952. IN UINT32 OffsetFromLastSchema,
  953. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  954. IN OUT UINT8 *SchemaIndex,
  955. OUT UINT32 *SchemaSpaceUsed
  956. )
  957. {
  958. EFI_STATUS Status = EFI_SUCCESS;
  959. UINT32 *SchemaAddrLocationArray = NULL;
  960. EFI_HOB_GUID_TYPE *GuidHob = NULL;
  961. EFI_PHYSICAL_ADDRESS Address = 0;
  962. EWL_PRIVATE_DATA *EwlPrivateData = NULL;
  963. EFI_GUID EWLDataGuid = EWL_ID_GUID;
  964. BDAT_SCHEMA_HEADER_STRUCTURE *EwlSchemaHeaderPtr = NULL;
  965. UINT32 EwlSize = 0;
  966. if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
  967. return EFI_INVALID_PARAMETER;
  968. }
  969. Address = *SchemaStartAddress;
  970. *SchemaSpaceUsed = 0;
  971. DEBUG ((DEBUG_VERBOSE, "\nStarting to copy EWL schema at Address = 0x%x\n", Address));
  972. //
  973. // Update the schema offset arrary
  974. //
  975. SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
  976. if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
  977. if (*SchemaIndex == 0) {
  978. SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
  979. }
  980. else {
  981. SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
  982. }
  983. }
  984. EwlSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
  985. EwlSchemaHeaderPtr->SchemaId = gEwlBdatSchemaGuid;
  986. *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  987. //
  988. // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
  989. //
  990. EwlSchemaHeaderPtr->Crc16 = 0;
  991. Status = CalculateCrc16 (
  992. (VOID *)EwlSchemaHeaderPtr,
  993. sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
  994. &EwlSchemaHeaderPtr->Crc16
  995. );
  996. ASSERT_EFI_ERROR (Status);
  997. if (EFI_ERROR (Status)) {
  998. EwlSchemaHeaderPtr->Crc16 = 0xFFFF;
  999. }
  1000. GuidHob = GetFirstGuidHob (&EWLDataGuid);
  1001. EwlPrivateData = GET_GUID_HOB_DATA (GuidHob);
  1002. EwlSize = EwlPrivateData->status.Header.Size;
  1003. EwlSchemaHeaderPtr->DataSize = EwlSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1004. //
  1005. // Copy EWL HOB to RT Memory
  1006. //
  1007. Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1008. CopyMem ((VOID *)Address, (VOID *)&(EwlPrivateData->status), EwlSize);
  1009. *SchemaSpaceUsed = *SchemaSpaceUsed + EwlSize;
  1010. *SchemaIndex = *SchemaIndex + 1;
  1011. return EFI_SUCCESS;
  1012. } //SaveEwlToBdat
  1013. /**
  1014. Check if current boot is slow boot or not
  1015. @retval TRUE - Slow boot path
  1016. @retval FALSE - not slow boot path
  1017. **/
  1018. BOOLEAN
  1019. IsSlowBoot (
  1020. VOID
  1021. )
  1022. {
  1023. EFI_STATUS Status = EFI_SUCCESS;
  1024. DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL;
  1025. Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, (VOID **) &DynamicSiLibraryProtocol2);
  1026. if (EFI_ERROR (Status)) {
  1027. ASSERT_EFI_ERROR (Status);
  1028. return TRUE;
  1029. }
  1030. return DynamicSiLibraryProtocol2->IsSlowBoot ();
  1031. } // IsSlowBoot
  1032. /**
  1033. Save SPD date structure to BDAT
  1034. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  1035. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  1036. @param[in] SchemaStartAddress - Starting address where the SPD data schema will be added
  1037. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  1038. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  1039. @retval EFI_SUCCESS - SPD BDAT scehma created successfully
  1040. @retval !EFI_SUCCESS - SPD BDAT scehma creation failed
  1041. **/
  1042. EFI_STATUS
  1043. SaveSpdToBdat (
  1044. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  1045. IN UINT32 OffsetFromLastSchema,
  1046. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  1047. IN OUT UINT8 *SchemaIndex,
  1048. OUT UINT32 *SchemaSpaceUsed
  1049. )
  1050. {
  1051. EFI_STATUS Status = EFI_SUCCESS;
  1052. UINT32 *SchemaAddrLocationArray = NULL;
  1053. UINT32 SpdDataSize = 0;
  1054. EFI_PHYSICAL_ADDRESS Address = 0;
  1055. BDAT_SCHEMA_HEADER_STRUCTURE *SpdSchemaHeaderPtr = NULL;
  1056. // UINT16 *SpdVariableName = L"SpdData";
  1057. VOID *VariableData = NULL;
  1058. BOOLEAN SaveToVariable = TRUE;
  1059. UINTN CompareValue;
  1060. if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
  1061. return EFI_INVALID_PARAMETER;
  1062. }
  1063. Address = *SchemaStartAddress;
  1064. *SchemaSpaceUsed = 0;
  1065. //
  1066. // Add SPD schema
  1067. //
  1068. DEBUG ((DEBUG_VERBOSE, "\nStarting to add SPD schema at Address = 0x%x\n", Address));
  1069. //
  1070. // Update the schema offset arrary
  1071. //
  1072. SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
  1073. if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
  1074. if (*SchemaIndex == 0) {
  1075. SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
  1076. }
  1077. else {
  1078. SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
  1079. }
  1080. }
  1081. SpdSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
  1082. SpdSchemaHeaderPtr->SchemaId = gSpdBdatSchemaGuid;
  1083. //
  1084. // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
  1085. //
  1086. SpdSchemaHeaderPtr->Crc16 = 0;
  1087. Status = CalculateCrc16 (
  1088. (VOID *)SpdSchemaHeaderPtr,
  1089. sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
  1090. &SpdSchemaHeaderPtr->Crc16
  1091. );
  1092. ASSERT_EFI_ERROR (Status);
  1093. if (EFI_ERROR (Status)) {
  1094. SpdSchemaHeaderPtr->Crc16 = 0xFFFF;
  1095. }
  1096. Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1097. *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1098. SpdDataSize = GetSpdDataSize ();
  1099. if (IsSlowBoot ()) {
  1100. //
  1101. // Read SPD via Smbus, fill up the SPD data structure.
  1102. //
  1103. FillSpdSchema (Address, SpdDataSize);
  1104. //
  1105. // Save the SPD data structure to EFI variables to save fast boot time
  1106. //
  1107. // Before save variable, read and comapre to current data. If they are the same, then
  1108. // don't save it.
  1109. // If fail to read the variable(the variable doesn't exist), save variable.
  1110. //
  1111. SaveToVariable = TRUE;
  1112. VariableData = AllocatePool (SpdDataSize);
  1113. if (VariableData == NULL) {
  1114. DEBUG ((DEBUG_ERROR, "Not able to allocate space to store SPD variable data.\n"));
  1115. Status = EFI_OUT_OF_RESOURCES;
  1116. goto End;
  1117. }
  1118. // Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, VariableData, SpdDataSize);
  1119. if (!EFI_ERROR (Status)) {
  1120. CompareValue = CompareMem ((VOID *)Address, VariableData, SpdDataSize);
  1121. if (CompareValue == 0) {
  1122. SaveToVariable = FALSE;
  1123. DEBUG ((DEBUG_VERBOSE, "No change to the SPD data, don't save variable.\n"));
  1124. }
  1125. }
  1126. if (SaveToVariable) {
  1127. // Status = CompressAndSaveToVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize);
  1128. if (EFI_ERROR (Status)) {
  1129. DEBUG ((DEBUG_ERROR, "Failed to save SPD data to variable.\n"));
  1130. goto End;
  1131. }
  1132. DEBUG ((DEBUG_VERBOSE, "Save SPD data to EFI variable.\n"));
  1133. }
  1134. } else {
  1135. //
  1136. // Fast boot, read the SPD data from vaiable
  1137. //
  1138. // Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize);
  1139. if (EFI_ERROR (Status)) {
  1140. DEBUG ((DEBUG_ERROR, "Failed to load SPD data from variable.\n"));
  1141. goto End;
  1142. }
  1143. DEBUG ((DEBUG_VERBOSE, "Fill with SPD data from EFI variable.\n"));
  1144. }
  1145. End:
  1146. if (VariableData != NULL) {
  1147. FreePool (VariableData);
  1148. }
  1149. SpdSchemaHeaderPtr->DataSize = SpdDataSize + sizeof (BDAT_SCHEMA_HEADER_STRUCTURE);
  1150. *SchemaSpaceUsed = *SchemaSpaceUsed + SpdDataSize;
  1151. *SchemaIndex = *SchemaIndex + 1;
  1152. return Status;
  1153. } //SaveSpdToBdat
  1154. /**
  1155. Save memory training date structure to BDAT
  1156. @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure
  1157. @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array.
  1158. @param[in] SchemaStartAddress - Starting address where the memory training data schema will be added
  1159. @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array.
  1160. @param[out] SchemaSpaceUsed - The numebr bytes were filled
  1161. @retval EFI_SUCCESS - Memory training data BDAT scehma created successfully
  1162. @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed
  1163. **/
  1164. EFI_STATUS
  1165. SaveTrainingDataToBdat (
  1166. IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr,
  1167. IN UINT32 OffsetFromLastSchema,
  1168. IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress,
  1169. IN OUT UINT8 *SchemaIndex,
  1170. OUT UINT32 *SchemaSpaceUsed
  1171. )
  1172. {
  1173. EFI_STATUS Status = EFI_SUCCESS;
  1174. UINT32 *SchemaAddrLocationArray = NULL;
  1175. EFI_HOB_GUID_TYPE *GuidHob = NULL;
  1176. EFI_PHYSICAL_ADDRESS Address = 0;
  1177. MEM_TRAINING_DATA_HEADER *TrainingDataHeader = NULL;
  1178. MEM_TRAINING_DATA_HOB_HEADER *TrainingDataHobHeader = NULL;
  1179. EFI_GUID TrainingDataGuid = gMemTrainingDataHobGuid;
  1180. BDAT_SCHEMA_HEADER_STRUCTURE *SchemaHeaderPtr = NULL;
  1181. INT32 RemainingDataSize = 0;
  1182. UINT32 HobSize = 0;
  1183. UINT32 TrainingDataSize = 0;
  1184. UINT8 HobIndex = 0;
  1185. if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) {
  1186. return EFI_INVALID_PARAMETER;
  1187. }
  1188. Address = *SchemaStartAddress;
  1189. *SchemaSpaceUsed = 0;
  1190. DEBUG ((DEBUG_VERBOSE, "\nStarting to copy memory training data schema at Address = 0x%x\n", Address));
  1191. //
  1192. // Update the schema offset arrary
  1193. //
  1194. SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE));
  1195. if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) {
  1196. if (*SchemaIndex == 0) {
  1197. SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema;
  1198. }
  1199. else {
  1200. SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema;
  1201. }
  1202. }
  1203. SchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address;
  1204. SchemaHeaderPtr->SchemaId = gMemTrainingDataBdatSchemaGuid;
  1205. *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1206. //
  1207. // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE
  1208. //
  1209. SchemaHeaderPtr->Crc16 = 0;
  1210. Status = CalculateCrc16 (
  1211. (VOID *)SchemaHeaderPtr,
  1212. sizeof(BDAT_SCHEMA_HEADER_STRUCTURE),
  1213. &SchemaHeaderPtr->Crc16
  1214. );
  1215. ASSERT_EFI_ERROR (Status);
  1216. if (EFI_ERROR (Status)) {
  1217. SchemaHeaderPtr->Crc16 = 0xFFFF;
  1218. }
  1219. GuidHob = GetFirstGuidHob (&TrainingDataGuid);
  1220. ASSERT (GuidHob != NULL);
  1221. if (GuidHob == NULL) {
  1222. DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid));
  1223. return EFI_NOT_FOUND;
  1224. }
  1225. TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
  1226. TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory.
  1227. TrainingDataHeader = (MEM_TRAINING_DATA_HEADER *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER));
  1228. HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
  1229. ASSERT (TrainingDataSize <= HobSize);
  1230. HobIndex += 1;
  1231. DEBUG ((DEBUG_VERBOSE, "Memory training data structre size:%d\n", TrainingDataHeader->Size));
  1232. SchemaHeaderPtr->DataSize = TrainingDataHeader->Size + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1233. //
  1234. // This is the total data size in the training data structure.
  1235. //
  1236. RemainingDataSize = (INT32) TrainingDataHeader->Size;
  1237. DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d\n", RemainingDataSize));
  1238. //
  1239. // Copy training data HOBs to RT Memory
  1240. //
  1241. Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE);
  1242. CopyMem ((VOID *)Address, (VOID *)TrainingDataHeader, TrainingDataSize);
  1243. *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize;
  1244. Address = Address + TrainingDataSize;
  1245. RemainingDataSize -= TrainingDataSize;
  1246. while (RemainingDataSize > 0) {
  1247. GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB
  1248. GuidHob = GetNextGuidHob (&TrainingDataGuid, GuidHob); // Now search for next instance of the BDAT HOB
  1249. ASSERT (GuidHob != NULL);
  1250. if (GuidHob == NULL) {
  1251. DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid));
  1252. return EFI_NOT_FOUND;
  1253. }
  1254. TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob);
  1255. TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory.
  1256. HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
  1257. ASSERT (TrainingDataSize <= HobSize);
  1258. HobIndex += 1;
  1259. //
  1260. // Copy training data HOBs to RT Memory
  1261. //
  1262. CopyMem ((VOID *)Address, (VOID *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER)), TrainingDataSize);
  1263. *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize;
  1264. Address = Address + TrainingDataSize;
  1265. RemainingDataSize -= TrainingDataSize;
  1266. DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d after copying Hob:%d \n", RemainingDataSize, HobIndex));
  1267. }
  1268. //
  1269. // Update training data header structure CRC, after all the training data were copied from HOBs to a RT contiguous memory region.
  1270. //
  1271. TrainingDataHeader->Crc = 0;
  1272. TrainingDataHeader->Crc = CalculateCrc32 ((VOID *) TrainingDataHeader, TrainingDataHeader->Size);
  1273. *SchemaIndex = *SchemaIndex + 1;
  1274. return EFI_SUCCESS;
  1275. } //SaveTrainingDataToBdat