]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkPlatformPkg/Platform/Pei/PlatformInit/MrcWrapper.c
QuarkPlatformPkg/PlatformInit: Fix recovery detection issues
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / MrcWrapper.c
CommitLineData
b303605e
MK
1/** @file\r
2Framework PEIM to initialize memory on a Quark Memory Controller.\r
3\r
a9054761 4Copyright (c) 2013 - 2016, Intel Corporation.\r
b303605e
MK
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "CommonHeader.h"\r
17#include "MrcWrapper.h"\r
18#include <Ioh.h>\r
19#include "Platform.h"\r
20\r
21#include <Library/PlatformHelperLib.h>\r
22\r
23//\r
24// ------------------------ TSEG Base\r
25//\r
26// ------------------------ RESERVED_CPU_S3_SAVE_OFFSET\r
27// CPU S3 data\r
28// ------------------------ RESERVED_ACPI_S3_RANGE_OFFSET\r
29// S3 Memory base structure\r
30// ------------------------ TSEG + 1 page\r
31\r
32#define RESERVED_CPU_S3_SAVE_OFFSET (RESERVED_ACPI_S3_RANGE_OFFSET - sizeof (SMM_S3_RESUME_STATE))\r
33\r
34// Strap configuration register specifying DDR setup\r
35#define QUARK_SCSS_REG_STPDDRCFG 0x00\r
36\r
37// Macro counting array elements\r
38#define COUNT(a) (sizeof(a)/sizeof(*a))\r
39\r
40\r
41EFI_MEMORY_TYPE_INFORMATION mDefaultQncMemoryTypeInformation[] = {\r
42 { EfiReservedMemoryType, EDKII_RESERVED_SIZE_PAGES }, // BIOS Reserved\r
43 { EfiACPIMemoryNVS, ACPI_NVS_SIZE_PAGES }, // S3, SMM, etc\r
44 { EfiRuntimeServicesData, RUNTIME_SERVICES_DATA_SIZE_PAGES },\r
45 { EfiRuntimeServicesCode, RUNTIME_SERVICES_CODE_SIZE_PAGES },\r
46 { EfiACPIReclaimMemory, ACPI_RECLAIM_SIZE_PAGES }, // ACPI ASL\r
47 { EfiMaxMemoryType, 0 }\r
48};\r
49\r
50/**\r
51 Configure Uart mmio base for MRC serial log purpose\r
52\r
53 @param MrcData - MRC configuration data updated\r
54\r
55**/\r
56VOID\r
57MrcUartConfig(\r
58 MRC_PARAMS *MrcData\r
59 )\r
60{\r
61 UINT8 UartIdx;\r
62 UINT32 RegData32;\r
63 UINT8 IohUartBus;\r
64 UINT8 IohUartDev;\r
65\r
66 UartIdx = PcdGet8(PcdIohUartFunctionNumber);\r
67 IohUartBus = PcdGet8(PcdIohUartBusNumber);\r
68 IohUartDev = PcdGet8(PcdIohUartDevNumber);\r
69\r
70 RegData32 = PciRead32 (PCI_LIB_ADDRESS(IohUartBus, IohUartDev, UartIdx, PCI_BASE_ADDRESSREG_OFFSET));\r
71 MrcData->uart_mmio_base = RegData32 & 0xFFFFFFF0;\r
72}\r
73\r
74/**\r
75 Configure MRC from memory controller fuse settings.\r
76\r
77 @param MrcData - MRC configuration data to be updated.\r
78\r
79 @return EFI_SUCCESS MRC Config parameters updated from platform data.\r
80**/\r
81EFI_STATUS\r
82MrcConfigureFromMcFuses (\r
83 OUT MRC_PARAMS *MrcData\r
84 )\r
85{\r
86 UINT32 McFuseStat;\r
87\r
88 McFuseStat = QNCPortRead (\r
89 QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID,\r
90 QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT\r
91 );\r
92\r
93 DEBUG ((EFI_D_INFO, "MRC McFuseStat 0x%08x\n", McFuseStat));\r
94\r
95 if ((McFuseStat & B_DFUSESTAT_ECC_DIS) != 0) {\r
96 DEBUG ((EFI_D_INFO, "MRC Fuse : fus_dun_ecc_dis.\n"));\r
97 MrcData->ecc_enables = 0;\r
98 } else {\r
99 MrcData->ecc_enables = 1;\r
100 }\r
101 return EFI_SUCCESS;\r
102}\r
103\r
104/**\r
105 Configure MRC from platform info hob.\r
106\r
107 @param MrcData - MRC configuration data to be updated.\r
108\r
109 @return EFI_SUCCESS MRC Config parameters updated from hob.\r
110 @return EFI_NOT_FOUND Platform Info or MRC Config parameters not found.\r
111 @return EFI_INVALID_PARAMETER Wrong params in hob.\r
112**/\r
113EFI_STATUS\r
114MrcConfigureFromInfoHob (\r
115 OUT MRC_PARAMS *MrcData\r
116 )\r
117{\r
118 PDAT_MRC_ITEM *ItemData;\r
119\r
120 ItemData = (PDAT_MRC_ITEM *)PcdGetPtr (PcdMrcParameters);\r
121\r
122 MrcData->channel_enables = ItemData->ChanMask;\r
123 MrcData->channel_width = ItemData->ChanWidth;\r
124 MrcData->address_mode = ItemData->AddrMode;\r
125 // Enable scrambling if requested.\r
126 MrcData->scrambling_enables = (ItemData->Flags & PDAT_MRC_FLAG_SCRAMBLE_EN) != 0;\r
127 MrcData->ddr_type = ItemData->DramType;\r
128 MrcData->dram_width = ItemData->DramWidth;\r
129 MrcData->ddr_speed = ItemData->DramSpeed;\r
130 // Enable ECC if requested.\r
131 MrcData->rank_enables = ItemData->RankMask;\r
132 MrcData->params.DENSITY = ItemData->DramDensity;\r
133 MrcData->params.tCL = ItemData->tCL;\r
134 MrcData->params.tRAS = ItemData->tRAS;\r
135 MrcData->params.tWTR = ItemData->tWTR;\r
136 MrcData->params.tRRD = ItemData->tRRD;\r
137 MrcData->params.tFAW = ItemData->tFAW;\r
138\r
139 MrcData->refresh_rate = ItemData->SrInt;\r
140 MrcData->sr_temp_range = ItemData->SrTemp;\r
141 MrcData->ron_value = ItemData->DramRonVal;\r
142 MrcData->rtt_nom_value = ItemData->DramRttNomVal;\r
143 MrcData->rd_odt_value = ItemData->SocRdOdtVal;\r
144\r
145 DEBUG ((EFI_D_INFO, "MRC dram_width %d\n", MrcData->dram_width));\r
146 DEBUG ((EFI_D_INFO, "MRC rank_enables %d\n",MrcData->rank_enables));\r
147 DEBUG ((EFI_D_INFO, "MRC ddr_speed %d\n", MrcData->ddr_speed));\r
148 DEBUG ((EFI_D_INFO, "MRC flags: %s\n",\r
149 (MrcData->scrambling_enables) ? L"SCRAMBLE_EN" : L""\r
150 ));\r
151\r
152 DEBUG ((EFI_D_INFO, "MRC density=%d tCL=%d tRAS=%d tWTR=%d tRRD=%d tFAW=%d\n",\r
153 MrcData->params.DENSITY,\r
154 MrcData->params.tCL,\r
155 MrcData->params.tRAS,\r
156 MrcData->params.tWTR,\r
157 MrcData->params.tRRD,\r
158 MrcData->params.tFAW\r
159 ));\r
160\r
161 return EFI_SUCCESS;\r
162}\r
163\r
164/**\r
165\r
166 Configure ECC scrub\r
167\r
168 @param MrcData - MRC configuration\r
169\r
170**/\r
171VOID\r
172EccScrubSetup(\r
173 const MRC_PARAMS *MrcData\r
174 )\r
175{\r
176 UINT32 BgnAdr = 0;\r
177 UINT32 EndAdr = MrcData->mem_size;\r
178 UINT32 BlkSize = PcdGet8(PcdEccScrubBlkSize) & SCRUB_CFG_BLOCKSIZE_MASK;\r
179 UINT32 Interval = PcdGet8(PcdEccScrubInterval) & SCRUB_CFG_INTERVAL_MASK;\r
180\r
181 if( MrcData->ecc_enables == 0 || MrcData->boot_mode == bmS3 || Interval == 0) {\r
182 // No scrub configuration needed if ECC not enabled\r
183 // On S3 resume reconfiguration is done as part of resume\r
184 // script, see SNCS3Save.c ==> SaveRuntimeScriptTable()\r
185 // Also if PCD disables scrub, then we do nothing.\r
186 return;\r
187 }\r
188\r
189 QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, EndAdr);\r
190 QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, BgnAdr);\r
191 QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, BgnAdr);\r
192 QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,\r
193 Interval << SCRUB_CFG_INTERVAL_SHIFT |\r
194 BlkSize << SCRUB_CFG_BLOCKSIZE_SHIFT);\r
195\r
196 McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = SCRUB_RESUME_MSG();\r
197}\r
198\r
199/** Post InstallS3Memory / InstallEfiMemory tasks given MrcData context.\r
200\r
201 @param[in] MrcData MRC configuration.\r
202 @param[in] IsS3 TRUE if after InstallS3Memory.\r
203\r
204**/\r
205VOID\r
206PostInstallMemory (\r
207 IN MRC_PARAMS *MrcData,\r
208 IN BOOLEAN IsS3\r
209 )\r
210{\r
211 UINT32 RmuMainDestBaseAddress;\r
212 UINT32 *RmuMainSrcBaseAddress;\r
213 UINTN RmuMainSize;\r
214 EFI_STATUS Status;\r
215\r
216 //\r
217 // Setup ECC policy (All boot modes).\r
218 //\r
219 QNCPolicyDblEccBitErr (V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM);\r
220\r
221 //\r
222 // Find the 64KB of memory for Rmu Main at the top of available memory.\r
223 //\r
224 InfoPostInstallMemory (&RmuMainDestBaseAddress, NULL, NULL);\r
225 DEBUG ((EFI_D_INFO, "RmuMain Base Address : 0x%x\n", RmuMainDestBaseAddress));\r
226\r
227 //\r
228 // Relocate RmuMain.\r
229 //\r
230 if (IsS3) {\r
231 QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
232 } else {\r
233 Status = PlatformFindFvFileRawDataSection (NULL, PcdGetPtr(PcdQuarkMicrocodeFile), (VOID **) &RmuMainSrcBaseAddress, &RmuMainSize);\r
234 ASSERT_EFI_ERROR (Status);\r
235 if (!EFI_ERROR (Status)) {\r
236 DEBUG ((EFI_D_INFO, "Found Microcode ADDR:SIZE 0x%08x:0x%04x\n", (UINTN) RmuMainSrcBaseAddress, RmuMainSize));\r
237 }\r
238\r
239 RmuMainRelocation (RmuMainDestBaseAddress, (UINT32) RmuMainSrcBaseAddress, RmuMainSize);\r
240 QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
241 EccScrubSetup (MrcData);\r
242 }\r
243}\r
244\r
245/**\r
246\r
247 Do memory initialisation for QNC DDR3 SDRAM Controller\r
248\r
249 @param FfsHeader Not used.\r
250 @param PeiServices General purpose services available to every PEIM.\r
251\r
252 @return EFI_SUCCESS Memory initialisation completed successfully.\r
253 All other error conditions encountered result in an ASSERT.\r
254\r
255**/\r
256EFI_STATUS\r
257MemoryInit (\r
258 IN EFI_PEI_SERVICES **PeiServices\r
259 )\r
260{\r
261 MRC_PARAMS MrcData;\r
262 EFI_BOOT_MODE BootMode;\r
263 EFI_STATUS Status;\r
264 EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices;\r
265 EFI_STATUS_CODE_VALUE ErrorCodeValue;\r
266 PEI_QNC_MEMORY_INIT_PPI *QncMemoryInitPpi;\r
267 UINT16 PmswAdr;\r
268\r
269 ErrorCodeValue = 0;\r
270\r
271 //\r
272 // It is critical that both of these data structures are initialized to 0.\r
273 // This PEIM knows the number of DIMMs in the system and works with that\r
274 // information. The MCH PEIM that consumes these data structures does not\r
275 // know the number of DIMMs so it expects the entire structure to be\r
276 // properly initialized. By initializing these to zero, all flags indicating\r
277 // that the SPD is present or the row should be configured are set to false.\r
278 //\r
279 ZeroMem (&MrcData, sizeof(MrcData));\r
280\r
281 //\r
282 // Get necessary PPI\r
283 //\r
284 Status = PeiServicesLocatePpi (\r
285 &gEfiPeiReadOnlyVariable2PpiGuid, // GUID\r
286 0, // INSTANCE\r
287 NULL, // EFI_PEI_PPI_DESCRIPTOR\r
288 (VOID **)&VariableServices // PPI\r
289 );\r
290 ASSERT_EFI_ERROR (Status);\r
291\r
292 //\r
293 // Determine boot mode\r
294 //\r
295 Status = PeiServicesGetBootMode (&BootMode);\r
296 ASSERT_EFI_ERROR (Status);\r
297\r
298 //\r
299 // Initialize Error type for reporting status code\r
300 //\r
301 switch (BootMode) {\r
302 case BOOT_ON_FLASH_UPDATE:\r
303 ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_UPDATE_FAIL;\r
304 break;\r
305 case BOOT_ON_S3_RESUME:\r
306 ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_S3_RESUME_FAIL;\r
307 break;\r
308 default:\r
309 ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY;\r
310 break;\r
311 }\r
312\r
313 //\r
314 // Specify MRC boot mode\r
315 //\r
316 switch (BootMode) {\r
317 case BOOT_ON_S3_RESUME:\r
318 case BOOT_ON_FLASH_UPDATE:\r
319 MrcData.boot_mode = bmS3;\r
320 break;\r
321 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:\r
322 MrcData.boot_mode = bmFast;\r
323 break;\r
324 default:\r
325 MrcData.boot_mode = bmCold;\r
326 break;\r
327 }\r
328\r
329 //\r
330 // Configure MRC input parameters.\r
331 //\r
332 Status = MrcConfigureFromMcFuses (&MrcData);\r
333 ASSERT_EFI_ERROR (Status);\r
334 Status = MrcConfigureFromInfoHob (&MrcData);\r
335 ASSERT_EFI_ERROR (Status);\r
336 MrcUartConfig(&MrcData);\r
337\r
338 if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
339 //\r
340 // Always do bmCold on recovery.\r
341 //\r
342 DEBUG ((DEBUG_INFO, "MemoryInit:Force bmCold on Recovery\n"));\r
343 MrcData.boot_mode = bmCold;\r
344 } else {\r
345\r
346 //\r
347 // Load Memory configuration data saved in previous boot from variable\r
348 //\r
349 Status = LoadConfig (\r
350 PeiServices,\r
351 VariableServices,\r
352 &MrcData\r
353 );\r
354\r
355 if (EFI_ERROR (Status)) {\r
356\r
357 switch (BootMode) {\r
358 case BOOT_ON_S3_RESUME:\r
359 case BOOT_ON_FLASH_UPDATE:\r
360 REPORT_STATUS_CODE (\r
361 EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
362 ErrorCodeValue\r
363 );\r
364 PeiServicesResetSystem ();\r
365 break;\r
366\r
367 default:\r
368 MrcData.boot_mode = bmCold;\r
369 break;\r
370 }\r
371 }\r
372 }\r
373\r
374 //\r
375 // Locate Memory Reference Code PPI\r
376 //\r
377 Status = PeiServicesLocatePpi (\r
378 &gQNCMemoryInitPpiGuid, // GUID\r
379 0, // INSTANCE\r
380 NULL, // EFI_PEI_PPI_DESCRIPTOR\r
381 (VOID **)&QncMemoryInitPpi // PPI\r
382 );\r
383 ASSERT_EFI_ERROR (Status);\r
384\r
385 PmswAdr = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMSW;\r
386 if( IoRead32 (PmswAdr) & B_QNC_GPE0BLK_PMSW_DRAM_INIT) {\r
387 // MRC did not complete last execution, force cold boot path\r
388 MrcData.boot_mode = bmCold;\r
389 }\r
390\r
391 // Mark MRC pending\r
392 IoOr32 (PmswAdr, (UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
393\r
394 //\r
395 // Call Memory Reference Code's Routines\r
396 //\r
397 QncMemoryInitPpi->MrcStart (&MrcData);\r
398\r
399 // Mark MRC completed\r
400 IoAnd32 (PmswAdr, ~(UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
401\r
402\r
403 //\r
404 // Note emulation platform has to read actual memory size\r
405 // MrcData.mem_size from PcdGet32 (PcdMemorySize);\r
406\r
407 if (BootMode == BOOT_ON_S3_RESUME) {\r
408\r
409 DEBUG ((EFI_D_INFO, "Following BOOT_ON_S3_RESUME boot path.\n"));\r
410\r
411 Status = InstallS3Memory (PeiServices, VariableServices, MrcData.mem_size);\r
412 if (EFI_ERROR (Status)) {\r
413 REPORT_STATUS_CODE (\r
414 EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
415 ErrorCodeValue\r
416 );\r
417 PeiServicesResetSystem ();\r
418 }\r
419 PostInstallMemory (&MrcData, TRUE);\r
420 return EFI_SUCCESS;\r
421 }\r
422\r
423 //\r
424 // Assign physical memory to PEI and DXE\r
425 //\r
426 DEBUG ((EFI_D_INFO, "InstallEfiMemory.\n"));\r
427\r
428 Status = InstallEfiMemory (\r
429 PeiServices,\r
430 VariableServices,\r
431 BootMode,\r
432 MrcData.mem_size\r
433 );\r
434 ASSERT_EFI_ERROR (Status);\r
435\r
436 PostInstallMemory (&MrcData, FALSE);\r
437\r
438 //\r
439 // Save current configuration into Hob and will save into Variable later in DXE\r
440 //\r
441 DEBUG ((EFI_D_INFO, "SaveConfig.\n"));\r
442 Status = SaveConfig (\r
443 &MrcData\r
444 );\r
445 ASSERT_EFI_ERROR (Status);\r
446\r
447 DEBUG ((EFI_D_INFO, "MemoryInit Complete.\n"));\r
448\r
449 return EFI_SUCCESS;\r
450}\r
451\r
452/**\r
453\r
454 This function saves a config to a HOB.\r
455\r
456 @param RowInfo The MCH row configuration information.\r
457 @param TimingData Timing data to be saved.\r
458 @param RowConfArray Row configuration information for each row in the system.\r
459 @param SpdData SPD info read for each DIMM slot in the system.\r
460\r
461 @return EFI_SUCCESS: The function completed successfully.\r
462\r
463**/\r
464EFI_STATUS\r
465SaveConfig (\r
466 IN MRC_PARAMS *MrcData\r
467 )\r
468{\r
469 //\r
470 // Build HOB data for Memory Config\r
471 // HOB data size (stored in variable) is required to be multiple of 8 bytes\r
472 //\r
473 BuildGuidDataHob (\r
474 &gEfiMemoryConfigDataGuid,\r
475 (VOID *) &MrcData->timings,\r
476 ((sizeof (MrcData->timings) + 0x7) & (~0x7))\r
477 );\r
478\r
479 DEBUG ((EFI_D_INFO, "IIO IoApicBase = %x IoApicLimit=%x\n", IOAPIC_BASE, (IOAPIC_BASE + IOAPIC_SIZE - 1)));\r
480 DEBUG ((EFI_D_INFO, "IIO RcbaAddress = %x\n", (UINT32)PcdGet64 (PcdRcbaMmioBaseAddress)));\r
481\r
482 return EFI_SUCCESS;\r
483}\r
484\r
485/**\r
486\r
487 Load a configuration stored in a variable.\r
488\r
489 @param TimingData Timing data to be loaded from NVRAM.\r
490 @param RowConfArray Row configuration information for each row in the system.\r
491\r
492 @return EFI_SUCCESS The function completed successfully.\r
493 Other Could not read variable.\r
494\r
495**/\r
496EFI_STATUS\r
497LoadConfig (\r
498 IN EFI_PEI_SERVICES **PeiServices,\r
499 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
500 IN OUT MRC_PARAMS *MrcData\r
501 )\r
502{\r
503 EFI_STATUS Status;\r
504 UINTN BufferSize;\r
505 PLATFORM_VARIABLE_MEMORY_CONFIG_DATA VarData;\r
506\r
507 BufferSize = ((sizeof (VarData.timings) + 0x7) & (~0x7)); // HOB data size (stored in variable) is required to be multiple of 8bytes\r
508\r
509 Status = VariableServices->GetVariable (\r
510 VariableServices,\r
511 EFI_MEMORY_CONFIG_DATA_NAME,\r
512 &gEfiMemoryConfigDataGuid,\r
513 NULL,\r
514 &BufferSize,\r
515 &VarData.timings\r
516 );\r
517 if (!EFI_ERROR (Status)) {\r
518 CopyMem (&MrcData->timings, &VarData.timings, sizeof(MrcData->timings));\r
519 }\r
520 return Status;\r
521}\r
522\r
523/**\r
524\r
525 This function installs memory.\r
526\r
527 @param PeiServices PEI Services table.\r
528 @param BootMode The specific boot path that is being followed\r
529 @param Mch Pointer to the DualChannelDdrMemoryInit PPI\r
530 @param RowConfArray Row configuration information for each row in the system.\r
531\r
532 @return EFI_SUCCESS The function completed successfully.\r
533 EFI_INVALID_PARAMETER One of the input parameters was invalid.\r
534 EFI_ABORTED An error occurred.\r
535\r
536**/\r
537EFI_STATUS\r
538InstallEfiMemory (\r
539 IN EFI_PEI_SERVICES **PeiServices,\r
540 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
541 IN EFI_BOOT_MODE BootMode,\r
542 IN UINT32 TotalMemorySize\r
543 )\r
544{\r
545 EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress;\r
546 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
547 EFI_STATUS Status;\r
548 EFI_PEI_HOB_POINTERS Hob;\r
549 PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
550 UINT8 Index;\r
551 UINT8 NumRanges;\r
552 UINT8 SmramIndex;\r
553 UINT8 SmramRanges;\r
554 UINT64 PeiMemoryLength;\r
555 UINTN BufferSize;\r
556 UINTN PeiMemoryIndex;\r
b303605e
MK
557 EFI_RESOURCE_ATTRIBUTE_TYPE Attribute;\r
558 EFI_PHYSICAL_ADDRESS BadMemoryAddress;\r
559 EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable;\r
560 VOID *CapsuleBuffer;\r
561 UINTN CapsuleBufferLength;\r
562 PEI_CAPSULE_PPI *Capsule;\r
563 VOID *LargeMemRangeBuf;\r
564 UINTN LargeMemRangeBufLen;\r
a9054761
MK
565 UINT8 MorControl;\r
566 UINTN DataSize;\r
b303605e
MK
567\r
568 //\r
569 // Test the memory from 1M->TOM\r
570 //\r
571 if (BootMode != BOOT_ON_FLASH_UPDATE) {\r
572 Status = BaseMemoryTest (\r
573 PeiServices,\r
574 0x100000,\r
575 (TotalMemorySize - 0x100000),\r
576 Quick,\r
577 &BadMemoryAddress\r
578 );\r
579 ASSERT_EFI_ERROR (Status);\r
580 }\r
581\r
582\r
583 //\r
584 // Get the Memory Map\r
585 //\r
586 NumRanges = MAX_RANGES;\r
587\r
588 ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
589\r
590 Status = GetMemoryMap (\r
591 PeiServices,\r
592 TotalMemorySize,\r
593 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
594 &NumRanges\r
595 );\r
596 ASSERT_EFI_ERROR (Status);\r
597\r
598 //\r
599 // Find the highest memory range in processor native address space to give to\r
600 // PEI. Then take the top.\r
601 //\r
602 PeiMemoryBaseAddress = 0;\r
603\r
604 //\r
605 // Query the platform for the minimum memory size\r
606 //\r
607\r
608 Status = GetPlatformMemorySize (\r
609 PeiServices,\r
610 BootMode,\r
611 &PeiMemoryLength\r
612 );\r
613 ASSERT_EFI_ERROR (Status);\r
614\r
a9054761
MK
615 //\r
616 // Detect MOR request by the OS.\r
617 //\r
618 MorControl = 0;\r
619 DataSize = sizeof (MorControl);\r
620 Status = VariableServices->GetVariable (\r
621 VariableServices,\r
622 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
623 &gEfiMemoryOverwriteControlDataGuid,\r
624 NULL,\r
625 &DataSize,\r
626 &MorControl\r
627 );\r
628\r
b303605e
MK
629 PeiMemoryIndex = 0;\r
630\r
631 for (Index = 0; Index < NumRanges; Index++)\r
632 {\r
633 DEBUG ((EFI_D_INFO, "Found 0x%x bytes at ", MemoryMap[Index].RangeLength));\r
634 DEBUG ((EFI_D_INFO, "0x%x.\n", MemoryMap[Index].PhysicalAddress));\r
635\r
a9054761
MK
636 //\r
637 // If OS requested a memory overwrite perform it now. Only do it for memory\r
638 // used by the OS.\r
639 //\r
640 if (MOR_CLEAR_MEMORY_VALUE (MorControl) && MemoryMap[Index].Type == DualChannelDdrMainMemory) {\r
641 DEBUG ((EFI_D_INFO, "Clear memory per MOR request.\n"));\r
642 if ((UINTN)MemoryMap[Index].RangeLength > 0) {\r
643 if ((UINTN)MemoryMap[Index].PhysicalAddress == 0) {\r
644 //\r
645 // ZeroMem() generates an ASSERT() if Buffer parameter is NULL.\r
646 // Clear byte at 0 and start clear operation at address 1.\r
647 //\r
648 *(UINT8 *)(0) = 0;\r
649 ZeroMem ((VOID *)1, (UINTN)MemoryMap[Index].RangeLength - 1);\r
650 } else {\r
651 ZeroMem (\r
652 (VOID *)(UINTN)MemoryMap[Index].PhysicalAddress,\r
653 (UINTN)MemoryMap[Index].RangeLength\r
654 );\r
655 }\r
656 }\r
657 }\r
658\r
b303605e
MK
659 if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
660 (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS) &&\r
661 (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) &&\r
662 (MemoryMap[Index].RangeLength >= PeiMemoryLength)) {\r
663 PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress +\r
664 MemoryMap[Index].RangeLength -\r
665 PeiMemoryLength;\r
666 PeiMemoryIndex = Index;\r
667 }\r
668 }\r
669\r
670 //\r
671 // Find the largest memory range excluding that given to PEI.\r
672 //\r
673 LargeMemRangeBuf = NULL;\r
674 LargeMemRangeBufLen = 0;\r
675 for (Index = 0; Index < NumRanges; Index++) {\r
676 if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
677 (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS)) {\r
678 if (Index != PeiMemoryIndex) {\r
679 if (MemoryMap[Index].RangeLength > LargeMemRangeBufLen) {\r
680 LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
681 LargeMemRangeBufLen = (UINTN) MemoryMap[Index].RangeLength;\r
682 }\r
683 } else {\r
684 if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) {\r
685 LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
686 LargeMemRangeBufLen = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength);\r
687 }\r
688 }\r
689 }\r
690 }\r
691\r
692 Capsule = NULL;\r
693 CapsuleBuffer = NULL;\r
694 CapsuleBufferLength = 0;\r
695 if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
696 Status = PeiServicesLocatePpi (\r
697 &gPeiCapsulePpiGuid, // GUID\r
698 0, // INSTANCE\r
699 NULL, // EFI_PEI_PPI_DESCRIPTOR\r
700 (VOID **)&Capsule // PPI\r
701 );\r
702 ASSERT_EFI_ERROR (Status);\r
703\r
704 if (Status == EFI_SUCCESS) {\r
705 CapsuleBuffer = LargeMemRangeBuf;\r
706 CapsuleBufferLength = LargeMemRangeBufLen;\r
707\r
708 //\r
709 // Call the Capsule PPI Coalesce function to coalesce the capsule data.\r
710 //\r
711 Status = Capsule->Coalesce (\r
712 PeiServices,\r
713 &CapsuleBuffer,\r
714 &CapsuleBufferLength\r
715 );\r
716 //\r
717 // If it failed, then NULL out our capsule PPI pointer so that the capsule\r
718 // HOB does not get created below.\r
719 //\r
720 if (Status != EFI_SUCCESS) {\r
721 Capsule = NULL;\r
722 }\r
723 }\r
724 }\r
725\r
726 //\r
727 // Set up the IMR policy required for this platform\r
728 //\r
729 Status = SetPlatformImrPolicy (\r
730 PeiMemoryBaseAddress,\r
69a0854b 731 PeiMemoryLength\r
b303605e
MK
732 );\r
733 ASSERT_EFI_ERROR (Status);\r
734\r
735 //\r
736 // Carve out the top memory reserved for ACPI\r
737 //\r
69a0854b 738 Status = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, PeiMemoryLength);\r
b303605e
MK
739 ASSERT_EFI_ERROR (Status);\r
740\r
741 BuildResourceDescriptorHob (\r
742 EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
743 (\r
744 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
745 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
746 EFI_RESOURCE_ATTRIBUTE_TESTED |\r
747 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
748 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
749 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
750 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
751 ),\r
752 PeiMemoryBaseAddress, // MemoryBegin\r
753 PeiMemoryLength // MemoryLength\r
754 );\r
755\r
756 //\r
757 // Install physical memory descriptor hobs for each memory range.\r
758 //\r
759 SmramRanges = 0;\r
760 for (Index = 0; Index < NumRanges; Index++) {\r
761 Attribute = 0;\r
762 if (MemoryMap[Index].Type == DualChannelDdrMainMemory)\r
763 {\r
764 if (Index == PeiMemoryIndex) {\r
765 //\r
766 // This is a partially tested Main Memory range, give it to EFI\r
767 //\r
768 BuildResourceDescriptorHob (\r
769 EFI_RESOURCE_SYSTEM_MEMORY,\r
770 (\r
771 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
772 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
773 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
774 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
775 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
776 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
777 ),\r
778 MemoryMap[Index].PhysicalAddress,\r
779 MemoryMap[Index].RangeLength - PeiMemoryLength\r
780 );\r
781 } else {\r
782 //\r
783 // This is an untested Main Memory range, give it to EFI\r
784 //\r
785 BuildResourceDescriptorHob (\r
786 EFI_RESOURCE_SYSTEM_MEMORY, // MemoryType,\r
787 (\r
788 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
789 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
790 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
791 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
792 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
793 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
794 ),\r
795 MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
796 MemoryMap[Index].RangeLength // MemoryLength\r
797 );\r
798 }\r
799 } else {\r
800 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
801 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
802 SmramRanges++;\r
803 }\r
804 if ((MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) ||\r
805 (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)) {\r
806 Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
807 }\r
808 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
809 (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable)) {\r
810 //\r
811 // TSEG and HSEG can be used with a write-back(WB) cache policy; however,\r
812 // the specification requires that the TSEG and HSEG space be cached only\r
813 // inside of the SMI handler. when using HSEG or TSEG an IA-32 processor\r
814 // does not automatically write back and invalidate its cache before entering\r
815 // SMM or before existing SMM therefore any MTRR defined for the active TSEG\r
816 // or HSEG must be set to un-cacheable(UC) outside of SMM.\r
817 //\r
818 Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
819 }\r
820 if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) {\r
821 Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |\r
822 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
823 }\r
824 //\r
825 // Make sure non-system memory is marked as reserved\r
826 //\r
827 BuildResourceDescriptorHob (\r
828 EFI_RESOURCE_MEMORY_RESERVED, // MemoryType,\r
829 Attribute, // MemoryAttribute\r
830 MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
831 MemoryMap[Index].RangeLength // MemoryLength\r
832 );\r
833 }\r
834 }\r
835\r
836 //\r
837 // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
838 // to the SMM Services Table that is required on the S3 resume path\r
839 //\r
840 ASSERT (SmramRanges > 0);\r
841 BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
842 BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
843\r
844 Hob.Raw = BuildGuidHob (\r
845 &gEfiSmmPeiSmramMemoryReserveGuid,\r
846 BufferSize\r
847 );\r
848 ASSERT (Hob.Raw);\r
849\r
850 SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
851 SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
852\r
853 SmramIndex = 0;\r
854 for (Index = 0; Index < NumRanges; Index++) {\r
855 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
856 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
857 ) {\r
858 //\r
859 // This is an SMRAM range, create an SMRAM descriptor\r
860 //\r
861 SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
862 SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress;\r
863 SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength;\r
864 if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
865 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
866 } else {\r
867 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
868 }\r
869\r
870 SmramIndex++;\r
871 }\r
872 }\r
873\r
874 //\r
875 // Build a HOB with the location of the reserved memory range.\r
876 //\r
877 CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
878 DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
879 BuildGuidDataHob (\r
880 &gEfiAcpiVariableGuid,\r
881 &DescriptorAcpiVariable,\r
882 sizeof (EFI_SMRAM_DESCRIPTOR)\r
883 );\r
884\r
885 //\r
886 // If we found the capsule PPI (and we didn't have errors), then\r
887 // call the capsule PEIM to allocate memory for the capsule.\r
888 //\r
889 if (Capsule != NULL) {\r
890 Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);\r
891 }\r
892\r
893 return EFI_SUCCESS;\r
894}\r
895\r
896/**\r
897\r
898 Find memory that is reserved so PEI has some to use.\r
899\r
900 @param PeiServices PEI Services table.\r
901 @param VariableSevices Variable PPI instance.\r
902\r
903 @return EFI_SUCCESS The function completed successfully.\r
904 Error value from LocatePpi()\r
905 Error Value from VariableServices->GetVariable()\r
906\r
907**/\r
908EFI_STATUS\r
909InstallS3Memory (\r
910 IN EFI_PEI_SERVICES **PeiServices,\r
911 IN EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices,\r
912 IN UINT32 TotalMemorySize\r
913 )\r
914{\r
915 EFI_STATUS Status;\r
916 UINTN S3MemoryBase;\r
917 UINTN S3MemorySize;\r
918 UINT8 SmramRanges;\r
919 UINT8 NumRanges;\r
920 UINT8 Index;\r
921 UINT8 SmramIndex;\r
922 UINTN BufferSize;\r
923 EFI_PEI_HOB_POINTERS Hob;\r
924 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
925 PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
926 RESERVED_ACPI_S3_RANGE *S3MemoryRangeData;\r
927 EFI_SMRAM_DESCRIPTOR DescriptorAcpiVariable;\r
928\r
929 //\r
930 // Get the Memory Map\r
931 //\r
932 NumRanges = MAX_RANGES;\r
933\r
934 ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
935\r
936 Status = GetMemoryMap (\r
937 PeiServices,\r
938 TotalMemorySize,\r
939 (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
940 &NumRanges\r
941 );\r
942 ASSERT_EFI_ERROR (Status);\r
943\r
944 //\r
945 // Install physical memory descriptor hobs for each memory range.\r
946 //\r
947 SmramRanges = 0;\r
948 for (Index = 0; Index < NumRanges; Index++) {\r
949 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
950 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
951 SmramRanges++;\r
952 }\r
953 }\r
954\r
955 ASSERT (SmramRanges > 0);\r
956\r
957 //\r
958 // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
959 // to the SMM Services Table that is required on the S3 resume path\r
960 //\r
961 BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
962 if (SmramRanges > 0) {\r
963 BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
964 }\r
965\r
966 Hob.Raw = BuildGuidHob (\r
967 &gEfiSmmPeiSmramMemoryReserveGuid,\r
968 BufferSize\r
969 );\r
970 ASSERT (Hob.Raw);\r
971\r
972 SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
973 SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
974\r
975 SmramIndex = 0;\r
976 for (Index = 0; Index < NumRanges; Index++) {\r
977 if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
978 (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
979 ) {\r
980 //\r
981 // This is an SMRAM range, create an SMRAM descriptor\r
982 //\r
983 SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
984 SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart = MemoryMap[Index].CpuAddress;\r
985 SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize = MemoryMap[Index].RangeLength;\r
986 if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
987 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
988 } else {\r
989 SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
990 }\r
991\r
992 SmramIndex++;\r
993 }\r
994 }\r
995\r
996 //\r
997 // Build a HOB with the location of the reserved memory range.\r
998 //\r
999 CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
1000 DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
1001 BuildGuidDataHob (\r
1002 &gEfiAcpiVariableGuid,\r
1003 &DescriptorAcpiVariable,\r
1004 sizeof (EFI_SMRAM_DESCRIPTOR)\r
1005 );\r
1006\r
1007 //\r
1008 // Get the location and size of the S3 memory range in the reserved page and\r
1009 // install it as PEI Memory.\r
1010 //\r
1011\r
1012 DEBUG ((EFI_D_INFO, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart));\r
1013 S3MemoryRangeData = (RESERVED_ACPI_S3_RANGE*)(UINTN)\r
1014 (SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart + RESERVED_ACPI_S3_RANGE_OFFSET);\r
1015\r
1016 S3MemoryBase = (UINTN) (S3MemoryRangeData->AcpiReservedMemoryBase);\r
1017 DEBUG ((EFI_D_INFO, "S3MemoryBase = 0x%08x\n", S3MemoryBase));\r
1018 S3MemorySize = (UINTN) (S3MemoryRangeData->AcpiReservedMemorySize);\r
1019 DEBUG ((EFI_D_INFO, "S3MemorySize = 0x%08x\n", S3MemorySize));\r
1020\r
1021 Status = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize);\r
1022 ASSERT_EFI_ERROR (Status);\r
1023\r
1024 //\r
1025 // Retrieve the system memory length and build memory hob for the system\r
1026 // memory above 1MB. So Memory Callback can set cache for the system memory\r
1027 // correctly on S3 boot path, just like it does on Normal boot path.\r
1028 //\r
74e00be5 1029 ASSERT ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0);\r
b303605e
MK
1030 BuildResourceDescriptorHob (\r
1031 EFI_RESOURCE_SYSTEM_MEMORY,\r
1032 (\r
1033 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
1034 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
1035 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
1036 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
1037 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
1038 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
1039 ),\r
1040 0x100000,\r
1041 S3MemoryRangeData->SystemMemoryLength - 0x100000\r
1042 );\r
1043\r
1044 for (Index = 0; Index < NumRanges; Index++) {\r
1045 if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
1046 (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < 0x100000)) {\r
1047 BuildResourceDescriptorHob (\r
1048 EFI_RESOURCE_SYSTEM_MEMORY,\r
1049 (\r
1050 EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
1051 EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
1052 EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
1053 EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
1054 EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
1055 EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
1056 ),\r
1057 MemoryMap[Index].PhysicalAddress,\r
1058 MemoryMap[Index].RangeLength\r
1059 );\r
1060 DEBUG ((EFI_D_INFO, "Build resource HOB for Legacy Region on S3 patch :"));\r
1061 DEBUG ((EFI_D_INFO, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength));\r
1062 }\r
1063 }\r
1064\r
1065 return EFI_SUCCESS;\r
1066}\r
1067\r
b303605e
MK
1068/**\r
1069\r
1070 This function returns the memory ranges to be enabled, along with information\r
1071 describing how the range should be used.\r
1072\r
1073 @param PeiServices PEI Services Table.\r
1074 @param TimingData Detected DDR timing parameters for installed memory.\r
1075 @param RowConfArray Pointer to an array of EFI_DUAL_CHANNEL_DDR_ROW_CONFIG structures. The number\r
1076 of items in the array must match MaxRows returned by the McGetRowInfo() function.\r
1077 @param MemoryMap Buffer to record details of the memory ranges tobe enabled.\r
1078 @param NumRanges On input, this contains the maximum number of memory ranges that can be described\r
1079 in the MemoryMap buffer.\r
1080\r
1081 @return MemoryMap The buffer will be filled in\r
1082 NumRanges will contain the actual number of memory ranges that are to be anabled.\r
1083 EFI_SUCCESS The function completed successfully.\r
1084\r
1085**/\r
1086EFI_STATUS\r
1087GetMemoryMap (\r
1088 IN EFI_PEI_SERVICES **PeiServices,\r
1089 IN UINT32 TotalMemorySize,\r
1090 IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *MemoryMap,\r
1091 IN OUT UINT8 *NumRanges\r
1092 )\r
1093{\r
1094 EFI_PHYSICAL_ADDRESS MemorySize;\r
1095 EFI_PHYSICAL_ADDRESS RowLength;\r
1096 EFI_STATUS Status;\r
1097 PEI_MEMORY_RANGE_PCI_MEMORY PciMemoryMask;\r
1098 PEI_MEMORY_RANGE_OPTION_ROM OptionRomMask;\r
1099 PEI_MEMORY_RANGE_SMRAM SmramMask;\r
1100 PEI_MEMORY_RANGE_SMRAM TsegMask;\r
1101 UINT32 BlockNum;\r
b303605e
MK
1102 UINT8 ExtendedMemoryIndex;\r
1103 UINT32 Register;\r
1104\r
1105 if ((*NumRanges) < MAX_RANGES) {\r
1106 return EFI_BUFFER_TOO_SMALL;\r
1107 }\r
1108\r
1109 *NumRanges = 0;\r
1110\r
1111 //\r
1112 // Find out which memory ranges to reserve on this platform\r
1113 //\r
1114 Status = ChooseRanges (\r
1115 &OptionRomMask,\r
1116 &SmramMask,\r
1117 &PciMemoryMask\r
1118 );\r
1119 ASSERT_EFI_ERROR (Status);\r
1120\r
1121 //\r
1122 // Generate Memory ranges for the memory map.\r
1123 //\r
b303605e
MK
1124 MemorySize = 0;\r
1125\r
1126 RowLength = TotalMemorySize;\r
1127\r
1128 //\r
1129 // Add memory below 640KB to the memory map. Make sure memory between\r
1130 // 640KB and 1MB are reserved, even if not used for SMRAM\r
1131 //\r
1132 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
1133 MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
1134 MemoryMap[*NumRanges].RangeLength = 0xA0000;\r
1135 MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;\r
1136 (*NumRanges)++;\r
1137\r
1138 //\r
1139 // Just mark this range reserved\r
1140 //\r
1141 MemoryMap[*NumRanges].PhysicalAddress = 0xA0000;\r
1142 MemoryMap[*NumRanges].CpuAddress = 0xA0000;\r
1143 MemoryMap[*NumRanges].RangeLength = 0x60000;\r
1144 MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;\r
1145 (*NumRanges)++;\r
1146\r
1147 RowLength -= (0x100000 - MemorySize);\r
1148 MemorySize = 0x100000;\r
1149\r
1150 //\r
1151 // Add remaining memory to the memory map\r
1152 //\r
1153 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
1154 MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
1155 MemoryMap[*NumRanges].RangeLength = RowLength;\r
1156 MemoryMap[*NumRanges].Type = DualChannelDdrMainMemory;\r
1157 (*NumRanges)++;\r
1158 MemorySize += RowLength;\r
1159\r
1160 ExtendedMemoryIndex = (UINT8) (*NumRanges - 1);\r
1161\r
1162 // See if we need to trim TSEG out of the highest memory range\r
1163 //\r
1164 if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) {//pcd\r
1165 //\r
1166 // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range\r
1167 //\r
1168 TsegMask = (SmramMask & PEI_MR_SMRAM_SIZE_MASK);\r
1169\r
1170 BlockNum = 1;\r
1171 while (TsegMask) {\r
1172 TsegMask >>= 1;\r
1173 BlockNum <<= 1;\r
1174 }\r
1175\r
1176 BlockNum >>= 1;\r
1177\r
1178 if (BlockNum) {\r
1179\r
1180 MemoryMap[*NumRanges].RangeLength = (BlockNum * 128 * 1024);\r
1181 Register = (UINT32)((MemorySize - 1) & SMM_END_MASK);\r
1182 MemorySize -= MemoryMap[*NumRanges].RangeLength;\r
1183 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
1184 MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
1185 MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
1186\r
1187 //\r
1188 // Update QuarkNcSoc HSMMCTL register\r
1189 //\r
1190 Register |= (UINT32)(((RShiftU64(MemorySize, 16)) & SMM_START_MASK) + (SMM_WRITE_OPEN | SMM_READ_OPEN | SMM_CODE_RD_OPEN));\r
1191 QncHsmmcWrite (Register);\r
1192 }\r
1193\r
1194 //\r
1195 // Chipset only supports cacheable SMRAM\r
1196 //\r
1197 MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable;\r
1198\r
1199 (*NumRanges)++;\r
1200 }\r
1201\r
1202 //\r
1203 // trim 64K memory from highest memory range for Rmu Main binary shadow\r
1204 //\r
1205 MemoryMap[*NumRanges].RangeLength = 0x10000;\r
1206 MemorySize -= MemoryMap[*NumRanges].RangeLength;\r
1207 MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
1208 MemoryMap[*NumRanges].CpuAddress = MemorySize;\r
1209 MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
1210 MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;\r
1211 (*NumRanges)++;\r
1212\r
1213 return EFI_SUCCESS;\r
1214}\r
1215\r
1216/**\r
1217\r
1218Routine Description:\r
1219\r
1220 Fill in bit masks to specify reserved memory ranges on the Lakeport platform\r
1221\r
1222Arguments:\r
1223\r
1224Returns:\r
1225\r
1226 OptionRomMask - Bit mask specifying memory regions reserved for Legacy option\r
1227 ROM use (if any)\r
1228\r
1229 SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)\r
1230\r
1231**/\r
1232EFI_STATUS\r
1233ChooseRanges (\r
1234 IN OUT PEI_MEMORY_RANGE_OPTION_ROM *OptionRomMask,\r
1235 IN OUT PEI_MEMORY_RANGE_SMRAM *SmramMask,\r
1236 IN OUT PEI_MEMORY_RANGE_PCI_MEMORY *PciMemoryMask\r
1237 )\r
1238{\r
1239\r
1240 //\r
1241 // Choose regions to reserve for Option ROM use\r
1242 //\r
1243 *OptionRomMask = PEI_MR_OPTION_ROM_NONE;\r
1244\r
1245 //\r
1246 // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks\r
1247 //\r
1248 *SmramMask = PEI_MR_SMRAM_CACHEABLE_MASK | PEI_MR_SMRAM_TSEG_MASK | ((PcdGet32(PcdTSegSize)) >> 17);\r
1249\r
1250 *PciMemoryMask = 0;\r
1251\r
1252 return EFI_SUCCESS;\r
1253}\r
1254\r
1255EFI_STATUS\r
1256GetPlatformMemorySize (\r
1257 IN EFI_PEI_SERVICES **PeiServices,\r
1258 IN EFI_BOOT_MODE BootMode,\r
1259 IN OUT UINT64 *MemorySize\r
1260 )\r
1261{\r
1262 EFI_STATUS Status;\r
1263 EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;\r
1264 UINTN DataSize;\r
1265 EFI_MEMORY_TYPE_INFORMATION MemoryData [EfiMaxMemoryType + 1];\r
1266 UINTN Index;\r
1267\r
1268 DataSize = sizeof (MemoryData);\r
1269\r
1270 if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
1271\r
1272 //\r
1273 // // Treat recovery as if variable not found (eg 1st boot).\r
1274 //\r
1275 Status = EFI_NOT_FOUND;\r
1276\r
1277 } else {\r
1278 Status = PeiServicesLocatePpi (\r
1279 &gEfiPeiReadOnlyVariable2PpiGuid,\r
1280 0,\r
1281 NULL,\r
1282 (VOID **)&Variable\r
1283 );\r
1284\r
1285 ASSERT_EFI_ERROR (Status);\r
1286\r
1287 DataSize = sizeof (MemoryData);\r
1288 Status = Variable->GetVariable (\r
1289 Variable,\r
1290 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
1291 &gEfiMemoryTypeInformationGuid,\r
1292 NULL,\r
1293 &DataSize,\r
1294 &MemoryData\r
1295 );\r
1296 }\r
1297\r
1298 //\r
1299 // Accumulate maximum amount of memory needed\r
1300 //\r
1301 if (EFI_ERROR (Status)) {\r
1302 //\r
1303 // Start with minimum memory\r
1304 //\r
1305 *MemorySize = PEI_MIN_MEMORY_SIZE;\r
1306\r
1307 for (Index = 0; Index < sizeof(mDefaultQncMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
1308 *MemorySize += mDefaultQncMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;\r
1309 }\r
1310\r
1311 //\r
1312 // Build the GUID'd HOB for DXE\r
1313 //\r
1314 BuildGuidDataHob (\r
1315 &gEfiMemoryTypeInformationGuid,\r
1316 mDefaultQncMemoryTypeInformation,\r
1317 sizeof(mDefaultQncMemoryTypeInformation)\r
1318 );\r
1319 } else {\r
1320 //\r
1321 // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack\r
1322 //\r
1323\r
1324 *MemorySize = PEI_MIN_MEMORY_SIZE;\r
1325 for (Index = 0; Index < DataSize / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
1326 DEBUG ((EFI_D_INFO, "Index %d, Page: %d\n", Index, MemoryData[Index].NumberOfPages));\r
1327 *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE;\r
1328 }\r
1329\r
1330 //\r
1331 // Build the GUID'd HOB for DXE\r
1332 //\r
1333 BuildGuidDataHob (\r
1334 &gEfiMemoryTypeInformationGuid,\r
1335 MemoryData,\r
1336 DataSize\r
1337 );\r
1338\r
1339 }\r
1340\r
1341 return EFI_SUCCESS;\r
1342}\r
1343\r
1344\r
1345EFI_STATUS\r
1346BaseMemoryTest (\r
1347 IN EFI_PEI_SERVICES **PeiServices,\r
1348 IN EFI_PHYSICAL_ADDRESS BeginAddress,\r
1349 IN UINT64 MemoryLength,\r
1350 IN PEI_MEMORY_TEST_OP Operation,\r
1351 OUT EFI_PHYSICAL_ADDRESS *ErrorAddress\r
1352 )\r
1353{\r
1354 UINT32 TestPattern;\r
1355 EFI_PHYSICAL_ADDRESS TempAddress;\r
1356 UINT32 SpanSize;\r
1357\r
1358 TestPattern = 0x5A5A5A5A;\r
1359 SpanSize = 0;\r
1360\r
1361 //\r
1362 // Make sure we don't try and test anything above the max physical address range\r
1363 //\r
1364 ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);\r
1365\r
1366 switch (Operation) {\r
1367 case Extensive:\r
1368 SpanSize = 0x4;\r
1369 break;\r
1370\r
1371 case Sparse:\r
1372 case Quick:\r
1373 SpanSize = 0x40000;\r
1374 break;\r
1375\r
1376 case Ignore:\r
1377 goto Done;\r
1378 break;\r
1379 }\r
1380 //\r
1381 // Write the test pattern into memory range\r
1382 //\r
1383 TempAddress = BeginAddress;\r
1384 while (TempAddress < BeginAddress + MemoryLength) {\r
1385 (*(UINT32 *) (UINTN) TempAddress) = TestPattern;\r
1386 TempAddress += SpanSize;\r
1387 }\r
1388 //\r
1389 // Read pattern from memory and compare it\r
1390 //\r
1391 TempAddress = BeginAddress;\r
1392 while (TempAddress < BeginAddress + MemoryLength) {\r
1393 if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) {\r
1394 *ErrorAddress = TempAddress;\r
1395 DEBUG ((EFI_D_ERROR, "Memory test failed at 0x%x.\n", TempAddress));\r
1396 return EFI_DEVICE_ERROR;\r
1397 }\r
1398\r
1399 TempAddress += SpanSize;\r
1400 }\r
1401\r
1402Done:\r
1403 return EFI_SUCCESS;\r
1404}\r
1405\r
1406/**\r
1407\r
1408 This function sets up the platform specific IMR protection for the various\r
1409 memory regions.\r
1410\r
1411 @param PeiMemoryBaseAddress Base address of memory allocated for PEI.\r
1412 @param PeiMemoryLength Length in bytes of the PEI memory (includes ACPI memory).\r
b303605e
MK
1413\r
1414 @return EFI_SUCCESS The function completed successfully.\r
1415 EFI_ACCESS_DENIED Access to IMRs failed.\r
1416\r
1417**/\r
1418EFI_STATUS\r
1419SetPlatformImrPolicy (\r
1420 IN EFI_PHYSICAL_ADDRESS PeiMemoryBaseAddress,\r
69a0854b 1421 IN UINT64 PeiMemoryLength\r
b303605e
MK
1422 )\r
1423{\r
1424 UINT8 Index;\r
1425 UINT32 Register;\r
1426 UINT16 DeviceId;\r
1427\r
1428 //\r
1429 // Check what Soc we are running on (read Host bridge DeviceId)\r
1430 //\r
1431 DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);\r
1432\r
1433 //\r
1434 // If any IMR register is locked then we cannot proceed\r
1435 //\r
1436 for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <=(QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index=Index+4)\r
1437 {\r
1438 Register = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);\r
1439 if (Register & IMR_LOCK) {\r
1440 return EFI_ACCESS_DENIED;\r
1441 }\r
1442 }\r
1443\r
b303605e
MK
1444 //\r
1445 // Add IMR2 protection for shadowed RMU binary.\r
1446 //\r
1447 QncImrWrite (\r
1448 QUARK_NC_MEMORY_MANAGER_IMR2,\r
1449 (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength), 8)) & IMRH_MASK) | IMR_EN),\r
1450 (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength+PcdGet32(PcdFlashQNCMicrocodeSize)-1), 8)) & IMRH_MASK),\r
1451 (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM),\r
1452 (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM)\r
1453 );\r
1454\r
1455 //\r
1456 // Add IMR3 protection for the default SMRAM.\r
1457 //\r
1458 QncImrWrite (\r
1459 QUARK_NC_MEMORY_MANAGER_IMR3,\r
1460 (UINT32)(((RShiftU64((SMM_DEFAULT_SMBASE), 8)) & IMRL_MASK) | IMR_EN),\r
1461 (UINT32)((RShiftU64((SMM_DEFAULT_SMBASE+SMM_DEFAULT_SMBASE_SIZE_BYTES-1), 8)) & IMRH_MASK),\r
1462 (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
1463 (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
1464 );\r
1465\r
b303605e
MK
1466 //\r
1467 // Enable IMR4 protection of eSRAM.\r
1468 //\r
1469 QncImrWrite (\r
1470 QUARK_NC_MEMORY_MANAGER_IMR4,\r
1471 (UINT32)(((RShiftU64((UINTN)PcdGet32 (PcdEsramStage1Base), 8)) & IMRL_MASK) | IMR_EN),\r
1472 (UINT32)((RShiftU64(((UINTN)PcdGet32 (PcdEsramStage1Base) + (UINTN)PcdGet32 (PcdESramMemorySize) - 1), 8)) & IMRH_MASK),\r
1473 (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
1474 (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
1475 );\r
1476\r
1477 //\r
1478 // Enable Interrupt on IMR/SMM Violation\r
1479 //\r
1480 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BIMRVCTL, (UINT32)(EnableIMRInt));\r
1481 if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
1482 QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BSMMVCTL, (UINT32)(EnableSMMInt));\r
1483 }\r
1484\r
1485 //\r
1486 // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies\r
1487 // are now setup.\r
1488 //\r
1489 QncImrWrite (\r
1490 QUARK_NC_MEMORY_MANAGER_IMR7,\r
1491 (UINT32)(IMRL_RESET & ~IMR_EN),\r
1492 (UINT32)IMRH_RESET,\r
1493 (UINT32)IMRX_ALL_ACCESS,\r
1494 (UINT32)IMRX_ALL_ACCESS\r
1495 );\r
1496\r
1497 return EFI_SUCCESS;\r
1498}\r
1499\r
1500/** Return info derived from Installing Memory by MemoryInit.\r
1501\r
1502 @param[out] RmuMainBaseAddressPtr Return RmuMainBaseAddress to this location.\r
1503 @param[out] SmramDescriptorPtr Return start of Smram descriptor list to this location.\r
1504 @param[out] NumSmramRegionsPtr Return numbers of Smram regions to this location.\r
1505\r
1506 @return Address of RMU shadow region at the top of available memory.\r
1507 @return List of Smram descriptors for each Smram region.\r
1508 @return Numbers of Smram regions.\r
1509**/\r
1510VOID\r
1511EFIAPI\r
1512InfoPostInstallMemory (\r
1513 OUT UINT32 *RmuMainBaseAddressPtr OPTIONAL,\r
1514 OUT EFI_SMRAM_DESCRIPTOR **SmramDescriptorPtr OPTIONAL,\r
1515 OUT UINTN *NumSmramRegionsPtr OPTIONAL\r
1516 )\r
1517{\r
1518 EFI_STATUS Status;\r
1519 EFI_PEI_HOB_POINTERS Hob;\r
1520 UINT64 CalcLength;\r
1521 EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHobDescriptorBlock;\r
1522\r
1523 if ((RmuMainBaseAddressPtr == NULL) && (SmramDescriptorPtr == NULL) && (NumSmramRegionsPtr == NULL)) {\r
1524 return;\r
1525 }\r
1526\r
1527 SmramHobDescriptorBlock = NULL;\r
1528 if (SmramDescriptorPtr != NULL) {\r
1529 *SmramDescriptorPtr = NULL;\r
1530 }\r
1531 if (NumSmramRegionsPtr != NULL) {\r
1532 *NumSmramRegionsPtr = 0;\r
1533 }\r
1534\r
1535 //\r
1536 // Calculate RMU shadow region base address.\r
1537 // Set to 1 MB. Since 1MB cacheability will always be set\r
1538 // until override by CSM.\r
1539 //\r
1540 CalcLength = 0x100000;\r
1541\r
1542 Status = PeiServicesGetHobList ((VOID **) &Hob.Raw);\r
1543 ASSERT_EFI_ERROR (Status);\r
1544 while (!END_OF_HOB_LIST (Hob)) {\r
1545 if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
1546 if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
1547 //\r
1548 // Skip the memory region below 1MB\r
1549 //\r
1550 if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {\r
1551 CalcLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength);\r
1552 }\r
1553 }\r
1554 } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {\r
1555 if (CompareGuid (&(Hob.Guid->Name), &gEfiSmmPeiSmramMemoryReserveGuid)) {\r
1556 SmramHobDescriptorBlock = (VOID*) (Hob.Raw + sizeof (EFI_HOB_GUID_TYPE));\r
1557 if (SmramDescriptorPtr != NULL) {\r
1558 *SmramDescriptorPtr = SmramHobDescriptorBlock->Descriptor;\r
1559 }\r
1560 if (NumSmramRegionsPtr != NULL) {\r
1561 *NumSmramRegionsPtr = SmramHobDescriptorBlock->NumberOfSmmReservedRegions;\r
1562 }\r
1563 }\r
1564 }\r
1565 Hob.Raw = GET_NEXT_HOB (Hob);\r
1566 }\r
1567\r
1568 if (RmuMainBaseAddressPtr != NULL) {\r
1569 *RmuMainBaseAddressPtr = (UINT32) CalcLength;\r
1570 }\r
1571}\r