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